]> icculus.org git repositories - btb/d2x.git/blob - main/gameseg.c
remove rcs tags
[btb/d2x.git] / main / gameseg.c
1 /*
2 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
3 SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
4 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
5 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
6 IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
7 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
8 FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
9 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
10 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
11 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
12 */
13
14 /*
15  *
16  * Functions moved from segment.c to make editor separable from game.
17  *
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #include <conf.h>
22 #endif
23
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <string.h>     //      for memset()
27
28 #include "u_mem.h"
29 #include "inferno.h"
30 #include "game.h"
31 #include "error.h"
32 #include "mono.h"
33 #include "vecmat.h"
34 #include "gameseg.h"
35 #include "wall.h"
36 #include "fuelcen.h"
37 #include "bm.h"
38 #include "fvi.h"
39 #include "byteswap.h"
40
41 // How far a point can be from a plane, and still be "in" the plane
42 #define PLANE_DIST_TOLERANCE    250
43
44 dl_index                Dl_indices[MAX_DL_INDICES];
45 delta_light Delta_lights[MAX_DELTA_LIGHTS];
46 int     Num_static_lights;
47
48 // ------------------------------------------------------------------------------------------
49 // Compute the center point of a side of a segment.
50 //      The center point is defined to be the average of the 4 points defining the side.
51 void compute_center_point_on_side(vms_vector *vp,segment *sp,int side)
52 {
53         int                     v;
54
55         vm_vec_zero(vp);
56
57         for (v=0; v<4; v++)
58                 vm_vec_add2(vp,&Vertices[sp->verts[Side_to_verts[side][v]]]);
59
60         vm_vec_scale(vp,F1_0/4);
61 }
62
63 // ------------------------------------------------------------------------------------------
64 // Compute segment center.
65 //      The center point is defined to be the average of the 8 points defining the segment.
66 void compute_segment_center(vms_vector *vp,segment *sp)
67 {
68         int                     v;
69
70         vm_vec_zero(vp);
71
72         for (v=0; v<8; v++)
73                 vm_vec_add2(vp,&Vertices[sp->verts[v]]);
74
75         vm_vec_scale(vp,F1_0/8);
76 }
77
78 // -----------------------------------------------------------------------------
79 //      Given two segments, return the side index in the connecting segment which connects to the base segment
80 //      Optimized by MK on 4/21/94 because it is a 2% load.
81 int find_connect_side(segment *base_seg, segment *con_seg)
82 {
83         int     s;
84         short base_seg_num = SEGMENT_NUMBER(base_seg);
85         short *childs = con_seg->children;
86
87         for (s=0; s<MAX_SIDES_PER_SEGMENT; s++) {
88                 if (*childs++ == base_seg_num)
89                         return s;
90         }
91
92
93         // legal to return -1, used in object_move_one(), mk, 06/08/94: Assert(0);              // Illegal -- there is no connecting side between these two segments
94         return -1;
95
96 }
97
98 // -----------------------------------------------------------------------------------
99 //      Given a side, return the number of faces
100 int get_num_faces(side *sidep)
101 {
102         switch (sidep->type) {
103                 case SIDE_IS_QUAD:      
104                         return 1;       
105                         break;
106                 case SIDE_IS_TRI_02:
107                 case SIDE_IS_TRI_13:    
108                         return 2;       
109                         break;
110                 default:
111                         Error("Illegal type = %i\n", sidep->type);
112                         break;
113         }
114         return 0;
115 }
116
117 // Fill in array with four absolute point numbers for a given side
118 void get_side_verts(short *vertlist,int segnum,int sidenum)
119 {
120         int     i;
121         sbyte   *sv = Side_to_verts[sidenum];
122         short   *vp = Segments[segnum].verts;
123
124         for (i=4; i--;)
125                 vertlist[i] = vp[sv[i]];
126 }
127
128
129 #ifdef EDITOR
130 // -----------------------------------------------------------------------------------
131 //      Create all vertex lists (1 or 2) for faces on a side.
132 //      Sets:
133 //              num_faces               number of lists
134 //              vertices                        vertices in all (1 or 2) faces
135 //      If there is one face, it has 4 vertices.
136 //      If there are two faces, they both have three vertices, so face #0 is stored in vertices 0,1,2,
137 //      face #1 is stored in vertices 3,4,5.
138 // Note: these are not absolute vertex numbers, but are relative to the segment
139 // Note:  for triagulated sides, the middle vertex of each trianle is the one NOT
140 //   adjacent on the diagonal edge
141 void create_all_vertex_lists(int *num_faces, int *vertices, int segnum, int sidenum)
142 {
143         side    *sidep = &Segments[segnum].sides[sidenum];
144         int  *sv = Side_to_verts_int[sidenum];
145
146         Assert((segnum <= Highest_segment_index) && (segnum >= 0));
147         Assert((sidenum >= 0) && (sidenum < 6));
148
149         switch (sidep->type) {
150                 case SIDE_IS_QUAD:
151
152                         vertices[0] = sv[0];
153                         vertices[1] = sv[1];
154                         vertices[2] = sv[2];
155                         vertices[3] = sv[3];
156
157                         *num_faces = 1;
158                         break;
159                 case SIDE_IS_TRI_02:
160                         *num_faces = 2;
161
162                         vertices[0] = sv[0];
163                         vertices[1] = sv[1];
164                         vertices[2] = sv[2];
165
166                         vertices[3] = sv[2];
167                         vertices[4] = sv[3];
168                         vertices[5] = sv[0];
169
170                         //IMPORTANT: DON'T CHANGE THIS CODE WITHOUT CHANGING GET_SEG_MASKS()
171                         //CREATE_ABS_VERTEX_LISTS(), CREATE_ALL_VERTEX_LISTS(), CREATE_ALL_VERTNUM_LISTS()
172                         break;
173                 case SIDE_IS_TRI_13:
174                         *num_faces = 2;
175
176                         vertices[0] = sv[3];
177                         vertices[1] = sv[0];
178                         vertices[2] = sv[1];
179
180                         vertices[3] = sv[1];
181                         vertices[4] = sv[2];
182                         vertices[5] = sv[3];
183
184                         //IMPORTANT: DON'T CHANGE THIS CODE WITHOUT CHANGING GET_SEG_MASKS()
185                         //CREATE_ABS_VERTEX_LISTS(), CREATE_ALL_VERTEX_LISTS(), CREATE_ALL_VERTNUM_LISTS()
186                         break;
187                 default:
188                         Error("Illegal side type (1), type = %i, segment # = %i, side # = %i\n Please report this bug.\n", sidep->type, segnum, sidenum);
189                         break;
190         }
191
192 }
193 #endif
194
195 // -----------------------------------------------------------------------------------
196 // Like create all vertex lists, but returns the vertnums (relative to
197 // the side) for each of the faces that make up the side. 
198 //      If there is one face, it has 4 vertices.
199 //      If there are two faces, they both have three vertices, so face #0 is stored in vertices 0,1,2,
200 //      face #1 is stored in vertices 3,4,5.
201 void create_all_vertnum_lists(int *num_faces, int *vertnums, int segnum, int sidenum)
202 {
203         side    *sidep = &Segments[segnum].sides[sidenum];
204
205         Assert((segnum <= Highest_segment_index) && (segnum >= 0));
206
207         switch (sidep->type) {
208                 case SIDE_IS_QUAD:
209
210                         vertnums[0] = 0;
211                         vertnums[1] = 1;
212                         vertnums[2] = 2;
213                         vertnums[3] = 3;
214
215                         *num_faces = 1;
216                         break;
217                 case SIDE_IS_TRI_02:
218                         *num_faces = 2;
219
220                         vertnums[0] = 0;
221                         vertnums[1] = 1;
222                         vertnums[2] = 2;
223
224                         vertnums[3] = 2;
225                         vertnums[4] = 3;
226                         vertnums[5] = 0;
227
228                         //IMPORTANT: DON'T CHANGE THIS CODE WITHOUT CHANGING GET_SEG_MASKS()
229                         //CREATE_ABS_VERTEX_LISTS(), CREATE_ALL_VERTEX_LISTS(), CREATE_ALL_VERTNUM_LISTS()
230                         break;
231                 case SIDE_IS_TRI_13:
232                         *num_faces = 2;
233
234                         vertnums[0] = 3;
235                         vertnums[1] = 0;
236                         vertnums[2] = 1;
237
238                         vertnums[3] = 1;
239                         vertnums[4] = 2;
240                         vertnums[5] = 3;
241
242                         //IMPORTANT: DON'T CHANGE THIS CODE WITHOUT CHANGING GET_SEG_MASKS()
243                         //CREATE_ABS_VERTEX_LISTS(), CREATE_ALL_VERTEX_LISTS(), CREATE_ALL_VERTNUM_LISTS()
244                         break;
245                 default:
246                         Error("Illegal side type (2), type = %i, segment # = %i, side # = %i\n Please report this bug.\n", sidep->type, segnum, sidenum);
247                         break;
248         }
249
250 }
251
252 // -----
253 // like create_all_vertex_lists(), but generate absolute point numbers
254 void create_abs_vertex_lists(int *num_faces, int *vertices, int segnum, int sidenum, char *calling_file, int calling_linenum)
255 {
256         short   *vp = Segments[segnum].verts;
257         side    *sidep = &Segments[segnum].sides[sidenum];
258         int  *sv = Side_to_verts_int[sidenum];
259
260         Assert((segnum <= Highest_segment_index) && (segnum >= 0));
261         
262         switch (sidep->type) {
263                 case SIDE_IS_QUAD:
264
265                         vertices[0] = vp[sv[0]];
266                         vertices[1] = vp[sv[1]];
267                         vertices[2] = vp[sv[2]];
268                         vertices[3] = vp[sv[3]];
269
270                         *num_faces = 1;
271                         break;
272                 case SIDE_IS_TRI_02:
273                         *num_faces = 2;
274
275                         vertices[0] = vp[sv[0]];
276                         vertices[1] = vp[sv[1]];
277                         vertices[2] = vp[sv[2]];
278
279                         vertices[3] = vp[sv[2]];
280                         vertices[4] = vp[sv[3]];
281                         vertices[5] = vp[sv[0]];
282
283                         //IMPORTANT: DON'T CHANGE THIS CODE WITHOUT CHANGING GET_SEG_MASKS(),
284                         //CREATE_ABS_VERTEX_LISTS(), CREATE_ALL_VERTEX_LISTS(), CREATE_ALL_VERTNUM_LISTS()
285                         break;
286                 case SIDE_IS_TRI_13:
287                         *num_faces = 2;
288
289                         vertices[0] = vp[sv[3]];
290                         vertices[1] = vp[sv[0]];
291                         vertices[2] = vp[sv[1]];
292
293                         vertices[3] = vp[sv[1]];
294                         vertices[4] = vp[sv[2]];
295                         vertices[5] = vp[sv[3]];
296
297                         //IMPORTANT: DON'T CHANGE THIS CODE WITHOUT CHANGING GET_SEG_MASKS()
298                         //CREATE_ABS_VERTEX_LISTS(), CREATE_ALL_VERTEX_LISTS(), CREATE_ALL_VERTNUM_LISTS()
299                         break;
300                 default:
301                         Error("Illegal side type (3), type = %i, segment # = %i, side # = %i caller:%s:%i\n Please report this bug.\n", sidep->type, segnum, sidenum, calling_file, calling_linenum);
302                         break;
303         }
304
305 }
306
307
308 //returns 3 different bitmasks with info telling if this sphere is in
309 //this segment.  See segmasks structure for info on fields  
310 segmasks get_seg_masks(vms_vector *checkp, int segnum, fix rad, char *calling_file, int calling_linenum)
311 {
312         int                     sn,facebit,sidebit;
313         segmasks                masks;
314         int                     num_faces;
315         int                     vertex_list[6];
316         segment         *seg;
317
318         if (segnum==-1)
319                 Error("segnum == -1 in get_seg_masks()");
320
321         Assert((segnum <= Highest_segment_index) && (segnum >= 0));
322
323         seg = &Segments[segnum];
324
325         //check point against each side of segment. return bitmask
326
327         masks.sidemask = masks.facemask = masks.centermask = 0;
328
329         for (sn=0,facebit=sidebit=1;sn<6;sn++,sidebit<<=1) {
330                 #ifndef COMPACT_SEGS
331                 side    *s = &seg->sides[sn];
332                 #endif
333                 int     side_pokes_out;
334                 int     vertnum,fn;
335                 
336                 // Get number of faces on this side, and at vertex_list, store vertices.
337                 //      If one face, then vertex_list indicates a quadrilateral.
338                 //      If two faces, then 0,1,2 define one triangle, 3,4,5 define the second.
339                 create_abs_vertex_lists(&num_faces, vertex_list, segnum, sn, calling_file, calling_linenum);
340
341                 //ok...this is important.  If a side has 2 faces, we need to know if
342                 //those faces form a concave or convex side.  If the side pokes out,
343                 //then a point is on the back of the side if it is behind BOTH faces,
344                 //but if the side pokes in, a point is on the back if behind EITHER face.
345
346                 if (num_faces==2) {
347                         fix     dist;
348                         int     side_count,center_count;
349                         #ifdef COMPACT_SEGS
350                         vms_vector normals[2];
351                         #endif
352
353                         vertnum = min(vertex_list[0],vertex_list[2]);
354                         
355                         #ifdef COMPACT_SEGS
356                         get_side_normals(seg, sn, &normals[0], &normals[1] );
357                         #endif
358                         
359                         if (vertex_list[4] < vertex_list[1])
360                                 #ifdef COMPACT_SEGS
361                                         dist = vm_dist_to_plane(&Vertices[vertex_list[4]],&normals[0],&Vertices[vertnum]);
362                                 #else
363                                         dist = vm_dist_to_plane(&Vertices[vertex_list[4]],&s->normals[0],&Vertices[vertnum]);
364                                 #endif
365                         else
366                                 #ifdef COMPACT_SEGS
367                                         dist = vm_dist_to_plane(&Vertices[vertex_list[1]],&normals[1],&Vertices[vertnum]);
368                                 #else
369                                         dist = vm_dist_to_plane(&Vertices[vertex_list[1]],&s->normals[1],&Vertices[vertnum]);
370                                 #endif
371
372                         side_pokes_out = (dist > PLANE_DIST_TOLERANCE);
373
374                         side_count = center_count = 0;
375
376                         for (fn=0;fn<2;fn++,facebit<<=1) {
377
378                                 #ifdef COMPACT_SEGS
379                                         dist = vm_dist_to_plane(checkp, &normals[fn], &Vertices[vertnum]);
380                                 #else
381                                         dist = vm_dist_to_plane(checkp, &s->normals[fn], &Vertices[vertnum]);
382                                 #endif
383
384                                 if (dist < -PLANE_DIST_TOLERANCE)       //in front of face
385                                         center_count++;
386
387                                 if (dist-rad < -PLANE_DIST_TOLERANCE) {
388                                         masks.facemask |= facebit;
389                                         side_count++;
390                                 }
391                         }
392
393                         if (!side_pokes_out) {          //must be behind both faces
394
395                                 if (side_count==2)
396                                         masks.sidemask |= sidebit;
397
398                                 if (center_count==2)
399                                         masks.centermask |= sidebit;
400
401                         }
402                         else {                                                  //must be behind at least one face
403
404                                 if (side_count)
405                                         masks.sidemask |= sidebit;
406
407                                 if (center_count)
408                                         masks.centermask |= sidebit;
409
410                         }
411
412
413                 }
414                 else {                          //only one face on this side
415                         fix dist;
416                         int i;
417                         #ifdef COMPACT_SEGS                     
418                         vms_vector normal;
419                         #endif
420
421                         //use lowest point number
422
423                         vertnum = vertex_list[0];
424                         for (i=1;i<4;i++)
425                                 if (vertex_list[i] < vertnum)
426                                         vertnum = vertex_list[i];
427
428                         #ifdef COMPACT_SEGS
429                                 get_side_normal(seg, sn, 0, &normal );
430                                 dist = vm_dist_to_plane(checkp, &normal, &Vertices[vertnum]);
431                         #else
432                                 dist = vm_dist_to_plane(checkp, &s->normals[0], &Vertices[vertnum]);
433                         #endif
434
435         
436                         if (dist < -PLANE_DIST_TOLERANCE)
437                                 masks.centermask |= sidebit;
438         
439                         if (dist-rad < -PLANE_DIST_TOLERANCE) {
440                                 masks.facemask |= facebit;
441                                 masks.sidemask |= sidebit;
442                         }
443
444                         facebit <<= 2;
445                 }
446
447         }
448
449         return masks;
450
451 }
452
453 //this was converted from get_seg_masks()...it fills in an array of 6
454 //elements for the distace behind each side, or zero if not behind
455 //only gets centermask, and assumes zero rad
456 ubyte get_side_dists(vms_vector *checkp,int segnum,fix *side_dists)
457 {
458         int                     sn,facebit,sidebit;
459         ubyte                   mask;
460         int                     num_faces;
461         int                     vertex_list[6];
462         segment         *seg;
463
464         Assert((segnum <= Highest_segment_index) && (segnum >= 0));
465
466         if (segnum==-1)
467                 Error("segnum == -1 in get_seg_dists()");
468
469         seg = &Segments[segnum];
470
471         //check point against each side of segment. return bitmask
472
473         mask = 0;
474
475         for (sn=0,facebit=sidebit=1;sn<6;sn++,sidebit<<=1) {
476                 #ifndef COMPACT_SEGS
477                 side    *s = &seg->sides[sn];
478                 #endif
479                 int     side_pokes_out;
480                 int     fn;
481
482                 side_dists[sn] = 0;
483
484                 // Get number of faces on this side, and at vertex_list, store vertices.
485                 //      If one face, then vertex_list indicates a quadrilateral.
486                 //      If two faces, then 0,1,2 define one triangle, 3,4,5 define the second.
487                 create_abs_vertex_lists(&num_faces, vertex_list, segnum, sn, __FILE__, __LINE__);
488
489                 //ok...this is important.  If a side has 2 faces, we need to know if
490                 //those faces form a concave or convex side.  If the side pokes out,
491                 //then a point is on the back of the side if it is behind BOTH faces,
492                 //but if the side pokes in, a point is on the back if behind EITHER face.
493
494                 if (num_faces==2) {
495                         fix     dist;
496                         int     center_count;
497                         int     vertnum;
498                         #ifdef COMPACT_SEGS
499                         vms_vector normals[2];
500                         #endif
501
502                         vertnum = min(vertex_list[0],vertex_list[2]);
503
504                         #ifdef COMPACT_SEGS
505                         get_side_normals(seg, sn, &normals[0], &normals[1] );
506                         #endif
507
508                         if (vertex_list[4] < vertex_list[1])
509                                 #ifdef COMPACT_SEGS
510                                         dist = vm_dist_to_plane(&Vertices[vertex_list[4]],&normals[0],&Vertices[vertnum]);
511                                 #else
512                                         dist = vm_dist_to_plane(&Vertices[vertex_list[4]],&s->normals[0],&Vertices[vertnum]);
513                                 #endif
514                         else
515                                 #ifdef COMPACT_SEGS
516                                         dist = vm_dist_to_plane(&Vertices[vertex_list[1]],&normals[1],&Vertices[vertnum]);
517                                 #else
518                                         dist = vm_dist_to_plane(&Vertices[vertex_list[1]],&s->normals[1],&Vertices[vertnum]);
519                                 #endif
520
521                         side_pokes_out = (dist > PLANE_DIST_TOLERANCE);
522
523                         center_count = 0;
524
525                         for (fn=0;fn<2;fn++,facebit<<=1) {
526
527                                 #ifdef COMPACT_SEGS
528                                         dist = vm_dist_to_plane(checkp, &normals[fn], &Vertices[vertnum]);
529                                 #else
530                                         dist = vm_dist_to_plane(checkp, &s->normals[fn], &Vertices[vertnum]);
531                                 #endif
532
533                                 if (dist < -PLANE_DIST_TOLERANCE) {     //in front of face
534                                         center_count++;
535                                         side_dists[sn] += dist;
536                                 }
537
538                         }
539
540                         if (!side_pokes_out) {          //must be behind both faces
541
542                                 if (center_count==2) {
543                                         mask |= sidebit;
544                                         side_dists[sn] /= 2;            //get average
545                                 }
546                                         
547
548                         }
549                         else {                                                  //must be behind at least one face
550
551                                 if (center_count) {
552                                         mask |= sidebit;
553                                         if (center_count==2)
554                                                 side_dists[sn] /= 2;            //get average
555
556                                 }
557                         }
558
559
560                 }
561                 else {                          //only one face on this side
562                         fix dist;
563                         int i,vertnum;
564                         #ifdef COMPACT_SEGS                     
565                         vms_vector normal;
566                         #endif
567
568
569                         //use lowest point number
570
571                         vertnum = vertex_list[0];
572                         for (i=1;i<4;i++)
573                                 if (vertex_list[i] < vertnum)
574                                         vertnum = vertex_list[i];
575
576                         #ifdef COMPACT_SEGS
577                                 get_side_normal(seg, sn, 0, &normal );
578                                 dist = vm_dist_to_plane(checkp, &normal, &Vertices[vertnum]);
579                         #else
580                                 dist = vm_dist_to_plane(checkp, &s->normals[0], &Vertices[vertnum]);
581                         #endif
582         
583                         if (dist < -PLANE_DIST_TOLERANCE) {
584                                 mask |= sidebit;
585                                 side_dists[sn] = dist;
586                         }
587         
588                         facebit <<= 2;
589                 }
590
591         }
592
593         return mask;
594
595 }
596
597 #ifndef NDEBUG
598 #ifndef COMPACT_SEGS
599 //returns true if errors detected
600 int check_norms(int segnum,int sidenum,int facenum,int csegnum,int csidenum,int cfacenum)
601 {
602         vms_vector *n0,*n1;
603
604         n0 = &Segments[segnum].sides[sidenum].normals[facenum];
605         n1 = &Segments[csegnum].sides[csidenum].normals[cfacenum];
606
607         if (n0->x != -n1->x  ||  n0->y != -n1->y  ||  n0->z != -n1->z) {
608                 mprintf((0,"Seg %x, side %d, norm %d doesn't match seg %x, side %d, norm %d:\n"
609                                 "   %8x %8x %8x\n"
610                                 "   %8x %8x %8x (negated)\n",
611                                 segnum,sidenum,facenum,csegnum,csidenum,cfacenum,
612                                 n0->x,n0->y,n0->z,-n1->x,-n1->y,-n1->z));
613                 return 1;
614         }
615         else
616                 return 0;
617 }
618
619 //heavy-duty error checking
620 int check_segment_connections(void)
621 {
622         int segnum,sidenum;
623         int errors=0;
624
625         for (segnum=0;segnum<=Highest_segment_index;segnum++) {
626                 segment *seg;
627
628                 seg = &Segments[segnum];
629
630                 for (sidenum=0;sidenum<6;sidenum++) {
631                         side *s;
632                         segment *cseg;
633                         side *cs;
634                         int num_faces,csegnum,csidenum,con_num_faces;
635                         int vertex_list[6],con_vertex_list[6];
636
637                         s = &seg->sides[sidenum];
638
639                         create_abs_vertex_lists(&num_faces, vertex_list, segnum, sidenum, __FILE__, __LINE__);
640
641                         csegnum = seg->children[sidenum];
642
643                         if (csegnum >= 0) {
644                                 cseg = &Segments[csegnum];
645                                 csidenum = find_connect_side(seg,cseg);
646
647                                 if (csidenum == -1) {
648                                         mprintf((0,"Could not find connected side for seg %x back to seg %x, side %d\n",csegnum,segnum,sidenum));
649                                         errors = 1;
650                                         continue;
651                                 }
652
653                                 cs = &cseg->sides[csidenum];
654
655                                 create_abs_vertex_lists(&con_num_faces, con_vertex_list, csegnum, csidenum, __FILE__, __LINE__);
656
657                                 if (con_num_faces != num_faces) {
658                                         mprintf((0,"Seg %x, side %d: num_faces (%d) mismatch with seg %x, side %d (%d)\n",segnum,sidenum,num_faces,csegnum,csidenum,con_num_faces));
659                                         errors = 1;
660                                 }
661                                 else
662                                         if (num_faces == 1) {
663                                                 int t;
664
665                                                 for (t=0;t<4 && con_vertex_list[t]!=vertex_list[0];t++);
666
667                                                 if (t==4 ||
668                                                          vertex_list[0] != con_vertex_list[t] ||
669                                                          vertex_list[1] != con_vertex_list[(t+3)%4] ||
670                                                          vertex_list[2] != con_vertex_list[(t+2)%4] ||
671                                                          vertex_list[3] != con_vertex_list[(t+1)%4]) {
672                                                         mprintf((0,"Seg %x, side %d: vertex list mismatch with seg %x, side %d\n"
673                                                                         "  %x %x %x %x\n"
674                                                                         "  %x %x %x %x\n",
675                                                                         segnum,sidenum,csegnum,csidenum,
676                                                                         vertex_list[0],vertex_list[1],vertex_list[2],vertex_list[3],
677                                                                         con_vertex_list[0],con_vertex_list[1],con_vertex_list[2],con_vertex_list[3]));
678                                                         errors = 1;
679                                                 }
680                                                 else
681                                                         errors |= check_norms(segnum,sidenum,0,csegnum,csidenum,0);
682         
683                                         }
684                                         else {
685         
686                                                 if (vertex_list[1] == con_vertex_list[1]) {
687                 
688                                                         if (vertex_list[4] != con_vertex_list[4] ||
689                                                                  vertex_list[0] != con_vertex_list[2] ||
690                                                                  vertex_list[2] != con_vertex_list[0] ||
691                                                                  vertex_list[3] != con_vertex_list[5] ||
692                                                                  vertex_list[5] != con_vertex_list[3]) {
693                                                                 mprintf((0,"Seg %x, side %d: vertex list mismatch with seg %x, side %d\n"
694                                                                                 "  %x %x %x  %x %x %x\n"
695                                                                                 "  %x %x %x  %x %x %x\n",
696                                                                                 segnum,sidenum,csegnum,csidenum,
697                                                                                 vertex_list[0],vertex_list[1],vertex_list[2],vertex_list[3],vertex_list[4],vertex_list[5],
698                                                                                 con_vertex_list[0],con_vertex_list[1],con_vertex_list[2],con_vertex_list[3],con_vertex_list[4],con_vertex_list[5]));
699                                                                 mprintf((0,"Changing seg:side %4i:%i from %i to %i\n", csegnum, csidenum, Segments[csegnum].sides[csidenum].type, 5-Segments[csegnum].sides[csidenum].type));
700                                                                 Segments[csegnum].sides[csidenum].type = 5-Segments[csegnum].sides[csidenum].type;
701                                                         } else {
702                                                                 errors |= check_norms(segnum,sidenum,0,csegnum,csidenum,0);
703                                                                 errors |= check_norms(segnum,sidenum,1,csegnum,csidenum,1);
704                                                         }
705         
706                                                 } else {
707                 
708                                                         if (vertex_list[1] != con_vertex_list[4] ||
709                                                                  vertex_list[4] != con_vertex_list[1] ||
710                                                                  vertex_list[0] != con_vertex_list[5] ||
711                                                                  vertex_list[5] != con_vertex_list[0] ||
712                                                                  vertex_list[2] != con_vertex_list[3] ||
713                                                                  vertex_list[3] != con_vertex_list[2]) {
714                                                                 mprintf((0,"Seg %x, side %d: vertex list mismatch with seg %x, side %d\n"
715                                                                                 "  %x %x %x  %x %x %x\n"
716                                                                                 "  %x %x %x  %x %x %x\n",
717                                                                                 segnum,sidenum,csegnum,csidenum,
718                                                                                 vertex_list[0],vertex_list[1],vertex_list[2],vertex_list[3],vertex_list[4],vertex_list[5],
719                                                                                 con_vertex_list[0],con_vertex_list[1],con_vertex_list[2],con_vertex_list[3],con_vertex_list[4],vertex_list[5]));
720                                                                 mprintf((0,"Changing seg:side %4i:%i from %i to %i\n", csegnum, csidenum, Segments[csegnum].sides[csidenum].type, 5-Segments[csegnum].sides[csidenum].type));
721                                                                 Segments[csegnum].sides[csidenum].type = 5-Segments[csegnum].sides[csidenum].type;
722                                                         } else {
723                                                                 errors |= check_norms(segnum,sidenum,0,csegnum,csidenum,1);
724                                                                 errors |= check_norms(segnum,sidenum,1,csegnum,csidenum,0);
725                                                         }
726                                                 }
727                                         }
728                         }
729                 }
730         }
731
732         // mprintf((0,"\n DONE \n"));
733
734         return errors;
735
736 }
737 #endif
738 #endif
739
740 // Used to become a constant based on editor, but I wanted to be able to set
741 // this for omega blob find_point_seg calls.
742 // Would be better to pass a paremeter to the routine...--MK, 01/17/96
743 int     Doing_lighting_hack_flag=0;
744
745 // figure out what seg the given point is in, tracing through segments
746 // returns segment number, or -1 if can't find segment
747 int trace_segs(vms_vector *p0, int oldsegnum, int recursion_count)
748 {
749         int centermask;
750         segment *seg;
751         fix side_dists[6];
752         fix biggest_val;
753         int sidenum, bit, check, biggest_side;
754         static ubyte visited [MAX_SEGMENTS];
755
756         Assert((oldsegnum <= Highest_segment_index) && (oldsegnum >= 0));
757
758         if (recursion_count >= Num_segments) {
759                 con_printf (CON_DEBUG, "trace_segs: Segment not found\n");
760                 mprintf ((0,"trace_segs (gameseg.c): Error: infinite loop\n"));
761                 return -1;
762         }
763         if (recursion_count == 0)
764                 memset (visited, 0, sizeof (visited));
765         if (visited [oldsegnum])
766                 return -1;
767         visited [oldsegnum] = 1;
768
769         centermask = get_side_dists(p0,oldsegnum,side_dists);           //check old segment
770         if (centermask == 0) // we are in the old segment
771                 return oldsegnum; //..say so
772
773         for (;;) {
774                 seg = &Segments[oldsegnum];
775                 biggest_side = -1;
776                 biggest_val = 0;
777                 for (sidenum = 0, bit = 1; sidenum < 6; sidenum++, bit <<= 1)
778                         if ((centermask & bit) && (seg->children[sidenum] > -1)
779                             && side_dists[sidenum] < biggest_val) {
780                                 biggest_val = side_dists[sidenum];
781                                 biggest_side = sidenum;
782                         }
783
784                         if (biggest_side == -1)
785                                 break;
786
787                         side_dists[biggest_side] = 0;
788                         // trace into adjacent segment:
789                         check = trace_segs(p0, seg->children[biggest_side], recursion_count + 1);
790                         if (check >= 0)         //we've found a segment
791                                 return check;
792         }
793         return -1;              //we haven't found a segment
794 }
795
796
797 int     Exhaustive_count=0, Exhaustive_failed_count=0;
798
799 //Tries to find a segment for a point, in the following way:
800 // 1. Check the given segment
801 // 2. Recursively trace through attached segments
802 // 3. Check all the segmentns
803 //Returns segnum if found, or -1
804 int find_point_seg(vms_vector *p,int segnum)
805 {
806         int newseg;
807
808         //allow segnum==-1, meaning we have no idea what segment point is in
809         Assert((segnum <= Highest_segment_index) && (segnum >= -1));
810
811         if (segnum != -1) {
812                 newseg = trace_segs(p, segnum, 0);
813
814                 if (newseg != -1)                       //we found a segment!
815                         return newseg;
816         }
817
818         //couldn't find via attached segs, so search all segs
819
820         //      MK: 10/15/94
821         //      This Doing_lighting_hack_flag thing added by mk because the hundreds of scrolling messages were
822         //      slowing down lighting, and in about 98% of cases, it would just return -1 anyway.
823         //      Matt: This really should be fixed, though.  We're probably screwing up our lighting in a few places.
824         if (!Doing_lighting_hack_flag) {
825                 mprintf((1,"Warning: doing exhaustive search to find point segment (%i times)\n", ++Exhaustive_count));
826
827                 for (newseg=0;newseg <= Highest_segment_index;newseg++)
828                         if (get_seg_masks(p, newseg, 0, __FILE__, __LINE__).centermask == 0)
829                                 return newseg;
830
831                 mprintf((1,"Warning: could not find point segment (%i times)\n", ++Exhaustive_failed_count));
832
833                 return -1;              //no segment found
834         } else
835                 return -1;
836 }
837
838
839 //--repair-- // ------------------------------------------------------------------------------
840 //--repair-- void clsd_repair_center(int segnum)
841 //--repair-- {
842 //--repair--    int     sidenum;
843 //--repair--
844 //--repair--    //      --- Set repair center bit for all repair center segments.
845 //--repair--    if (Segments[segnum].special == SEGMENT_IS_REPAIRCEN) {
846 //--repair--            Lsegments[segnum].special_type |= SS_REPAIR_CENTER;
847 //--repair--            Lsegments[segnum].special_segment = segnum;
848 //--repair--    }
849 //--repair--
850 //--repair--    //      --- Set repair center bit for all segments adjacent to a repair center.
851 //--repair--    for (sidenum=0; sidenum < MAX_SIDES_PER_SEGMENT; sidenum++) {
852 //--repair--            int     s = Segments[segnum].children[sidenum];
853 //--repair--
854 //--repair--            if ( (s != -1) && (Segments[s].special==SEGMENT_IS_REPAIRCEN) ) {
855 //--repair--                    Lsegments[segnum].special_type |= SS_REPAIR_CENTER;
856 //--repair--                    Lsegments[segnum].special_segment = s;
857 //--repair--            }
858 //--repair--    }
859 //--repair-- }
860
861 //--repair-- // ------------------------------------------------------------------------------
862 //--repair-- // --- Set destination points for all Materialization centers.
863 //--repair-- void clsd_materialization_center(int segnum)
864 //--repair-- {
865 //--repair--    if (Segments[segnum].special == SEGMENT_IS_ROBOTMAKER) {
866 //--repair--
867 //--repair--    }
868 //--repair-- }
869 //--repair--
870 //--repair-- int        Lsegment_highest_segment_index, Lsegment_highest_vertex_index;
871 //--repair--
872 //--repair-- // ------------------------------------------------------------------------------
873 //--repair-- // Create data specific to mine which doesn't get written to disk.
874 //--repair-- // Highest_segment_index and Highest_object_index must be valid.
875 //--repair-- // 07/21:  set repair center bit
876 //--repair-- void create_local_segment_data(void)
877 //--repair-- {
878 //--repair--    int     segnum;
879 //--repair--
880 //--repair--    //      --- Initialize all Lsegments.
881 //--repair--    for (segnum=0; segnum <= Highest_segment_index; segnum++) {
882 //--repair--            Lsegments[segnum].special_type = 0;
883 //--repair--            Lsegments[segnum].special_segment = -1;
884 //--repair--    }
885 //--repair--
886 //--repair--    for (segnum=0; segnum <= Highest_segment_index; segnum++) {
887 //--repair--
888 //--repair--            clsd_repair_center(segnum);
889 //--repair--            clsd_materialization_center(segnum);
890 //--repair--    
891 //--repair--    }
892 //--repair--
893 //--repair--    //      Set check variables.
894 //--repair--    //      In main game loop, make sure these are valid, else Lsegments is not valid.
895 //--repair--    Lsegment_highest_segment_index = Highest_segment_index;
896 //--repair--    Lsegment_highest_vertex_index = Highest_vertex_index;
897 //--repair-- }
898 //--repair--
899 //--repair-- // ------------------------------------------------------------------------------------------
900 //--repair-- // Sort of makes sure create_local_segment_data has been called for the currently executing mine.
901 //--repair-- // It is not failsafe, as you will see if you look at the code.
902 //--repair-- // Returns 1 if Lsegments appears valid, 0 if not.
903 //--repair-- int check_lsegments_validity(void)
904 //--repair-- {
905 //--repair--    return ((Lsegment_highest_segment_index == Highest_segment_index) && (Lsegment_highest_vertex_index == Highest_vertex_index));
906 //--repair-- }
907
908 #define MAX_LOC_POINT_SEGS      64
909
910 int     Connected_segment_distance;
911
912 #define MIN_CACHE_FCD_DIST      (F1_0*80)       //      Must be this far apart for cache lookup to succeed.  Recognizes small changes in distance matter at small distances.
913 #define MAX_FCD_CACHE   8
914
915 typedef struct {
916         int     seg0, seg1, csd;
917         fix     dist;
918 } fcd_data;
919
920 int     Fcd_index = 0;
921 fcd_data Fcd_cache[MAX_FCD_CACHE];
922 fix     Last_fcd_flush_time;
923
924 //      ----------------------------------------------------------------------------------------------------------
925 void flush_fcd_cache(void)
926 {
927         int     i;
928
929         Fcd_index = 0;
930
931         for (i=0; i<MAX_FCD_CACHE; i++)
932                 Fcd_cache[i].seg0 = -1;
933 }
934
935 //      ----------------------------------------------------------------------------------------------------------
936 void add_to_fcd_cache(int seg0, int seg1, int depth, fix dist)
937 {
938         if (dist > MIN_CACHE_FCD_DIST) {
939                 Fcd_cache[Fcd_index].seg0 = seg0;
940                 Fcd_cache[Fcd_index].seg1 = seg1;
941                 Fcd_cache[Fcd_index].csd = depth;
942                 Fcd_cache[Fcd_index].dist = dist;
943
944                 Fcd_index++;
945
946                 if (Fcd_index >= MAX_FCD_CACHE)
947                         Fcd_index = 0;
948
949                 // -- mprintf((0, "Adding seg0=%i, seg1=%i to cache.\n", seg0, seg1));
950         } else {
951                 //      If it's in the cache, remove it.
952                 int     i;
953
954                 for (i=0; i<MAX_FCD_CACHE; i++)
955                         if (Fcd_cache[i].seg0 == seg0)
956                                 if (Fcd_cache[i].seg1 == seg1) {
957                                         Fcd_cache[Fcd_index].seg0 = -1;
958                                         break;
959                                 }
960         }
961
962 }
963
964 //      ----------------------------------------------------------------------------------------------------------
965 //      Determine whether seg0 and seg1 are reachable in a way that allows sound to pass.
966 //      Search up to a maximum depth of max_depth.
967 //      Return the distance.
968 fix find_connected_distance(vms_vector *p0, int seg0, vms_vector *p1, int seg1, int max_depth, int wid_flag)
969 {
970         int             cur_seg;
971         int             sidenum;
972         int             qtail = 0, qhead = 0;
973         int             i;
974         sbyte   visited[MAX_SEGMENTS];
975         seg_seg seg_queue[MAX_SEGMENTS];
976         short           depth[MAX_SEGMENTS];
977         int             cur_depth;
978         int             num_points;
979         point_seg       point_segs[MAX_LOC_POINT_SEGS];
980         fix             dist;
981
982         //      If > this, will overrun point_segs buffer
983 #ifdef WINDOWS
984         if (max_depth == -1) max_depth = 200;
985 #endif  
986
987         if (max_depth > MAX_LOC_POINT_SEGS-2) {
988                 mprintf((1, "Warning: In find_connected_distance, max_depth = %i, limited to %i\n", max_depth, MAX_LOC_POINT_SEGS-2));
989                 max_depth = MAX_LOC_POINT_SEGS-2;
990         }
991
992         if (seg0 == seg1) {
993                 Connected_segment_distance = 0;
994                 return vm_vec_dist_quick(p0, p1);
995         } else {
996                 int     conn_side;
997                 if ((conn_side = find_connect_side(&Segments[seg0], &Segments[seg1])) != -1) {
998                         if (WALL_IS_DOORWAY(&Segments[seg1], conn_side) & wid_flag) {
999                                 Connected_segment_distance = 1;
1000                                 //mprintf((0, "\n"));
1001                                 return vm_vec_dist_quick(p0, p1);
1002                         }
1003                 }
1004         }
1005
1006         //      Periodically flush cache.
1007         if ((GameTime - Last_fcd_flush_time > F1_0*2) || (GameTime < Last_fcd_flush_time)) {
1008                 flush_fcd_cache();
1009                 Last_fcd_flush_time = GameTime;
1010         }
1011
1012         //      Can't quickly get distance, so see if in Fcd_cache.
1013         for (i=0; i<MAX_FCD_CACHE; i++)
1014                 if ((Fcd_cache[i].seg0 == seg0) && (Fcd_cache[i].seg1 == seg1)) {
1015                         Connected_segment_distance = Fcd_cache[i].csd;
1016                         // -- mprintf((0, "In cache, seg0=%i, seg1=%i.  Returning.\n", seg0, seg1));
1017                         return Fcd_cache[i].dist;
1018                 }
1019
1020         num_points = 0;
1021
1022         memset(visited, 0, Highest_segment_index+1);
1023         memset(depth, 0, sizeof(depth[0]) * (Highest_segment_index+1));
1024
1025         cur_seg = seg0;
1026         visited[cur_seg] = 1;
1027         cur_depth = 0;
1028
1029         while (cur_seg != seg1) {
1030                 segment *segp = &Segments[cur_seg];
1031
1032                 for (sidenum = 0; sidenum < MAX_SIDES_PER_SEGMENT; sidenum++) {
1033
1034                         int     snum = sidenum;
1035
1036                         if (WALL_IS_DOORWAY(segp, snum) & wid_flag) {
1037                                 int     this_seg = segp->children[snum];
1038
1039                                 if (!visited[this_seg]) {
1040                                         seg_queue[qtail].start = cur_seg;
1041                                         seg_queue[qtail].end = this_seg;
1042                                         visited[this_seg] = 1;
1043                                         depth[qtail++] = cur_depth+1;
1044                                         if (max_depth != -1) {
1045                                                 if (depth[qtail-1] == max_depth) {
1046                                                         Connected_segment_distance = 1000;
1047                                                         add_to_fcd_cache(seg0, seg1, Connected_segment_distance, F1_0*1000);
1048                                                         return -1;
1049                                                 }
1050                                         } else if (this_seg == seg1) {
1051                                                 goto fcd_done1;
1052                                         }
1053                                 }
1054
1055                         }
1056                 }       //      for (sidenum...
1057
1058                 if (qhead >= qtail) {
1059                         Connected_segment_distance = 1000;
1060                         add_to_fcd_cache(seg0, seg1, Connected_segment_distance, F1_0*1000);
1061                         return -1;
1062                 }
1063
1064                 cur_seg = seg_queue[qhead].end;
1065                 cur_depth = depth[qhead];
1066                 qhead++;
1067
1068 fcd_done1: ;
1069         }       //      while (cur_seg ...
1070
1071         //      Set qtail to the segment which ends at the goal.
1072         while (seg_queue[--qtail].end != seg1)
1073                 if (qtail < 0) {
1074                         Connected_segment_distance = 1000;
1075                         add_to_fcd_cache(seg0, seg1, Connected_segment_distance, F1_0*1000);
1076                         return -1;
1077                 }
1078
1079         while (qtail >= 0) {
1080                 int     parent_seg, this_seg;
1081
1082                 this_seg = seg_queue[qtail].end;
1083                 parent_seg = seg_queue[qtail].start;
1084                 point_segs[num_points].segnum = this_seg;
1085                 compute_segment_center(&point_segs[num_points].point,&Segments[this_seg]);
1086                 num_points++;
1087
1088                 if (parent_seg == seg0)
1089                         break;
1090
1091                 while (seg_queue[--qtail].end != parent_seg)
1092                         Assert(qtail >= 0);
1093         }
1094
1095         point_segs[num_points].segnum = seg0;
1096         compute_segment_center(&point_segs[num_points].point,&Segments[seg0]);
1097         num_points++;
1098
1099         if (num_points == 1) {
1100                 Connected_segment_distance = num_points;
1101                 return vm_vec_dist_quick(p0, p1);
1102         } else {
1103                 dist = vm_vec_dist_quick(p1, &point_segs[1].point);
1104                 dist += vm_vec_dist_quick(p0, &point_segs[num_points-2].point);
1105
1106                 for (i=1; i<num_points-2; i++) {
1107                         fix     ndist;
1108                         ndist = vm_vec_dist_quick(&point_segs[i].point, &point_segs[i+1].point);
1109                         dist += ndist;
1110                 }
1111
1112         }
1113
1114         Connected_segment_distance = num_points;
1115         add_to_fcd_cache(seg0, seg1, num_points, dist);
1116
1117         return dist;
1118
1119 }
1120
1121 sbyte convert_to_byte(fix f)
1122 {
1123         if (f >= 0x00010000)
1124                 return MATRIX_MAX;
1125         else if (f <= -0x00010000)
1126                 return -MATRIX_MAX;
1127         else
1128                 return f >> MATRIX_PRECISION;
1129 }
1130
1131 #define VEL_PRECISION 12
1132
1133 //      Create a shortpos struct from an object.
1134 //      Extract the matrix into byte values.
1135 //      Create a position relative to vertex 0 with 1/256 normal "fix" precision.
1136 //      Stuff segment in a short.
1137 void create_shortpos(shortpos *spp, object *objp, int swap_bytes)
1138 {
1139         // int  segnum;
1140         sbyte   *sp;
1141
1142         sp = spp->bytemat;
1143
1144         *sp++ = convert_to_byte(objp->orient.rvec.x);
1145         *sp++ = convert_to_byte(objp->orient.uvec.x);
1146         *sp++ = convert_to_byte(objp->orient.fvec.x);
1147         *sp++ = convert_to_byte(objp->orient.rvec.y);
1148         *sp++ = convert_to_byte(objp->orient.uvec.y);
1149         *sp++ = convert_to_byte(objp->orient.fvec.y);
1150         *sp++ = convert_to_byte(objp->orient.rvec.z);
1151         *sp++ = convert_to_byte(objp->orient.uvec.z);
1152         *sp++ = convert_to_byte(objp->orient.fvec.z);
1153
1154         spp->xo = (objp->pos.x - Vertices[Segments[objp->segnum].verts[0]].x) >> RELPOS_PRECISION;
1155         spp->yo = (objp->pos.y - Vertices[Segments[objp->segnum].verts[0]].y) >> RELPOS_PRECISION;
1156         spp->zo = (objp->pos.z - Vertices[Segments[objp->segnum].verts[0]].z) >> RELPOS_PRECISION;
1157
1158         spp->segment = objp->segnum;
1159
1160         spp->velx = (objp->mtype.phys_info.velocity.x) >> VEL_PRECISION;
1161         spp->vely = (objp->mtype.phys_info.velocity.y) >> VEL_PRECISION;
1162         spp->velz = (objp->mtype.phys_info.velocity.z) >> VEL_PRECISION;
1163
1164 // swap the short values for the big-endian machines.
1165
1166         if (swap_bytes) {
1167                 spp->xo = INTEL_SHORT(spp->xo);
1168                 spp->yo = INTEL_SHORT(spp->yo);
1169                 spp->zo = INTEL_SHORT(spp->zo);
1170                 spp->segment = INTEL_SHORT(spp->segment);
1171                 spp->velx = INTEL_SHORT(spp->velx);
1172                 spp->vely = INTEL_SHORT(spp->vely);
1173                 spp->velz = INTEL_SHORT(spp->velz);
1174         }
1175 //      mprintf((0, "Matrix: %08x %08x %08x    %08x %08x %08x\n", objp->orient.m1,objp->orient.m2,objp->orient.m3,
1176 //                                      spp->bytemat[0] << MATRIX_PRECISION,spp->bytemat[1] << MATRIX_PRECISION,spp->bytemat[2] << MATRIX_PRECISION));
1177 //
1178 //      mprintf((0, "        %08x %08x %08x    %08x %08x %08x\n", objp->orient.m4,objp->orient.m5,objp->orient.m6,
1179 //                                      spp->bytemat[3] << MATRIX_PRECISION,spp->bytemat[4] << MATRIX_PRECISION,spp->bytemat[5] << MATRIX_PRECISION));
1180 //
1181 //      mprintf((0, "        %08x %08x %08x    %08x %08x %08x\n", objp->orient.m7,objp->orient.m8,objp->orient.m9,
1182 //                                      spp->bytemat[6] << MATRIX_PRECISION,spp->bytemat[7] << MATRIX_PRECISION,spp->bytemat[8] << MATRIX_PRECISION));
1183 //
1184 //      mprintf((0, "Positn: %08x %08x %08x    %08x %08x %08x\n", objp->pos.x, objp->pos.y, objp->pos.z,
1185 //               (spp->xo << RELPOS_PRECISION) + Vertices[Segments[segnum].verts[0]].x,
1186 //               (spp->yo << RELPOS_PRECISION) + Vertices[Segments[segnum].verts[0]].y,
1187 //               (spp->zo << RELPOS_PRECISION) + Vertices[Segments[segnum].verts[0]].z));
1188 //      mprintf((0, "Segment: %3i    %3i\n", objp->segnum, spp->segment));
1189
1190 }
1191
1192 void extract_shortpos(object *objp, shortpos *spp, int swap_bytes)
1193 {
1194         int     segnum;
1195         sbyte   *sp;
1196
1197         sp = spp->bytemat;
1198
1199         objp->orient.rvec.x = *sp++ << MATRIX_PRECISION;
1200         objp->orient.uvec.x = *sp++ << MATRIX_PRECISION;
1201         objp->orient.fvec.x = *sp++ << MATRIX_PRECISION;
1202         objp->orient.rvec.y = *sp++ << MATRIX_PRECISION;
1203         objp->orient.uvec.y = *sp++ << MATRIX_PRECISION;
1204         objp->orient.fvec.y = *sp++ << MATRIX_PRECISION;
1205         objp->orient.rvec.z = *sp++ << MATRIX_PRECISION;
1206         objp->orient.uvec.z = *sp++ << MATRIX_PRECISION;
1207         objp->orient.fvec.z = *sp++ << MATRIX_PRECISION;
1208
1209         if (swap_bytes) {
1210                 spp->xo = INTEL_SHORT(spp->xo);
1211                 spp->yo = INTEL_SHORT(spp->yo);
1212                 spp->zo = INTEL_SHORT(spp->zo);
1213                 spp->segment = INTEL_SHORT(spp->segment);
1214                 spp->velx = INTEL_SHORT(spp->velx);
1215                 spp->vely = INTEL_SHORT(spp->vely);
1216                 spp->velz = INTEL_SHORT(spp->velz);
1217         }
1218
1219         segnum = spp->segment;
1220
1221         Assert((segnum >= 0) && (segnum <= Highest_segment_index));
1222
1223         objp->pos.x = (spp->xo << RELPOS_PRECISION) + Vertices[Segments[segnum].verts[0]].x;
1224         objp->pos.y = (spp->yo << RELPOS_PRECISION) + Vertices[Segments[segnum].verts[0]].y;
1225         objp->pos.z = (spp->zo << RELPOS_PRECISION) + Vertices[Segments[segnum].verts[0]].z;
1226
1227         objp->mtype.phys_info.velocity.x = (spp->velx << VEL_PRECISION);
1228         objp->mtype.phys_info.velocity.y = (spp->vely << VEL_PRECISION);
1229         objp->mtype.phys_info.velocity.z = (spp->velz << VEL_PRECISION);
1230
1231         obj_relink(OBJECT_NUMBER(objp), segnum);
1232
1233 //      mprintf((0, "Matrix: %08x %08x %08x    %08x %08x %08x\n", objp->orient.m1,objp->orient.m2,objp->orient.m3,
1234 //                                      spp->bytemat[0],spp->bytemat[1],spp->bytemat[2]));
1235 //
1236 //      mprintf((0, "        %08x %08x %08x    %08x %08x %08x\n", objp->orient.m4,objp->orient.m5,objp->orient.m6,
1237 //                                      spp->bytemat[3],spp->bytemat[4],spp->bytemat[5]));
1238 //
1239 //      mprintf((0, "        %08x %08x %08x    %08x %08x %08x\n", objp->orient.m7,objp->orient.m8,objp->orient.m9,
1240 //                                      spp->bytemat[6],spp->bytemat[7],spp->bytemat[8]));
1241 //
1242 //      mprintf((0, "Positn: %08x %08x %08x    %08x %08x %08x\n", objp->pos.x, objp->pos.y, objp->pos.z,
1243 //                      (spp->xo << RELPOS_PRECISION) + Vertices[Segments[segnum].verts[0]].x, (spp->yo << RELPOS_PRECISION) + Vertices[Segments[segnum].verts[0]].y, (spp->zo << RELPOS_PRECISION) + Vertices[Segments[segnum].verts[0]].z));
1244 //      mprintf((0, "Segment: %3i    %3i\n", objp->segnum, spp->segment));
1245
1246 }
1247
1248 //--unused-- void test_shortpos(void)
1249 //--unused-- {
1250 //--unused--    shortpos        spp;
1251 //--unused--
1252 //--unused--    create_shortpos(&spp, &Objects[0]);
1253 //--unused--    extract_shortpos(&Objects[0], &spp);
1254 //--unused--
1255 //--unused-- }
1256
1257 //      -----------------------------------------------------------------------------
1258 //      Segment validation functions.
1259 //      Moved from editor to game so we can compute surface normals at load time.
1260 // -------------------------------------------------------------------------------
1261
1262 // ------------------------------------------------------------------------------------------
1263 //      Extract a vector from a segment.  The vector goes from the start face to the end face.
1264 //      The point on each face is the average of the four points forming the face.
1265 void extract_vector_from_segment(segment *sp, vms_vector *vp, int start, int end)
1266 {
1267         int                     i;
1268         vms_vector      vs,ve;
1269
1270         vm_vec_zero(&vs);
1271         vm_vec_zero(&ve);
1272
1273         for (i=0; i<4; i++) {
1274                 vm_vec_add2(&vs,&Vertices[sp->verts[Side_to_verts[start][i]]]);
1275                 vm_vec_add2(&ve,&Vertices[sp->verts[Side_to_verts[end][i]]]);
1276         }
1277
1278         vm_vec_sub(vp,&ve,&vs);
1279         vm_vec_scale(vp,F1_0/4);
1280
1281 }
1282
1283 //create a matrix that describes the orientation of the given segment
1284 void extract_orient_from_segment(vms_matrix *m,segment *seg)
1285 {
1286         vms_vector fvec,uvec;
1287
1288         extract_vector_from_segment(seg,&fvec,WFRONT,WBACK);
1289         extract_vector_from_segment(seg,&uvec,WBOTTOM,WTOP);
1290
1291         //vector to matrix does normalizations and orthogonalizations
1292         vm_vector_2_matrix(m,&fvec,&uvec,NULL);
1293 }
1294
1295 #ifdef EDITOR
1296 // ------------------------------------------------------------------------------------------
1297 //      Extract the forward vector from segment *sp, return in *vp.
1298 //      The forward vector is defined to be the vector from the the center of the front face of the segment
1299 // to the center of the back face of the segment.
1300 void extract_forward_vector_from_segment(segment *sp,vms_vector *vp)
1301 {
1302         extract_vector_from_segment(sp,vp,WFRONT,WBACK);
1303 }
1304
1305 // ------------------------------------------------------------------------------------------
1306 //      Extract the right vector from segment *sp, return in *vp.
1307 //      The forward vector is defined to be the vector from the the center of the left face of the segment
1308 // to the center of the right face of the segment.
1309 void extract_right_vector_from_segment(segment *sp,vms_vector *vp)
1310 {
1311         extract_vector_from_segment(sp,vp,WLEFT,WRIGHT);
1312 }
1313
1314 // ------------------------------------------------------------------------------------------
1315 //      Extract the up vector from segment *sp, return in *vp.
1316 //      The forward vector is defined to be the vector from the the center of the bottom face of the segment
1317 // to the center of the top face of the segment.
1318 void extract_up_vector_from_segment(segment *sp,vms_vector *vp)
1319 {
1320         extract_vector_from_segment(sp,vp,WBOTTOM,WTOP);
1321 }
1322 #endif
1323
1324 void add_side_as_quad(segment *sp, int sidenum, vms_vector *normal)
1325 {
1326         side    *sidep = &sp->sides[sidenum];
1327
1328         sidep->type = SIDE_IS_QUAD;
1329
1330         #ifdef COMPACT_SEGS
1331                 normal = normal;                //avoid compiler warning
1332         #else
1333         sidep->normals[0] = *normal;
1334         sidep->normals[1] = *normal;
1335         #endif
1336
1337         //      If there is a connection here, we only formed the faces for the purpose of determining segment boundaries,
1338         //      so don't generate polys, else they will get rendered.
1339 //      if (sp->children[sidenum] != -1)
1340 //              sidep->render_flag = 0;
1341 //      else
1342 //              sidep->render_flag = 1;
1343
1344 }
1345
1346
1347 // -------------------------------------------------------------------------------
1348 //      Return v0, v1, v2 = 3 vertices with smallest numbers.  If *negate_flag set, then negate normal after computation.
1349 //      Note, you cannot just compute the normal by treating the points in the opposite direction as this introduces
1350 //      small differences between normals which should merely be opposites of each other.
1351 void get_verts_for_normal(int va, int vb, int vc, int vd, int *v0, int *v1, int *v2, int *v3, int *negate_flag)
1352 {
1353         int     i,j;
1354         int     v[4],w[4];
1355
1356         //      w is a list that shows how things got scrambled so we know if our normal is pointing backwards
1357         for (i=0; i<4; i++)
1358                 w[i] = i;
1359
1360         v[0] = va;
1361         v[1] = vb;
1362         v[2] = vc;
1363         v[3] = vd;
1364
1365         for (i=1; i<4; i++)
1366                 for (j=0; j<i; j++)
1367                         if (v[j] > v[i]) {
1368                                 int     t;
1369                                 t = v[j];       v[j] = v[i];    v[i] = t;
1370                                 t = w[j];       w[j] = w[i];    w[i] = t;
1371                         }
1372
1373         Assert((v[0] < v[1]) && (v[1] < v[2]) && (v[2] < v[3]));
1374
1375         //      Now, if for any w[i] & w[i+1]: w[i+1] = (w[i]+3)%4, then must swap
1376         *v0 = v[0];
1377         *v1 = v[1];
1378         *v2 = v[2];
1379         *v3 = v[3];
1380
1381         if ( (((w[0]+3) % 4) == w[1]) || (((w[1]+3) % 4) == w[2]))
1382                 *negate_flag = 1;
1383         else
1384                 *negate_flag = 0;
1385
1386 }
1387
1388 // -------------------------------------------------------------------------------
1389 void add_side_as_2_triangles(segment *sp, int sidenum)
1390 {
1391         vms_vector      norm;
1392         sbyte       *vs = Side_to_verts[sidenum];
1393         fix                     dot;
1394         vms_vector      vec_13;         //      vector from vertex 1 to vertex 3
1395
1396         side    *sidep = &sp->sides[sidenum];
1397
1398         //      Choose how to triangulate.
1399         //      If a wall, then
1400         //              Always triangulate so segment is convex.
1401         //              Use Matt's formula: Na . AD > 0, where ABCD are vertices on side, a is face formed by A,B,C, Na is normal from face a.
1402         //      If not a wall, then triangulate so whatever is on the other side is triangulated the same (ie, between the same absoluate vertices)
1403         if (!IS_CHILD(sp->children[sidenum])) {
1404                 vm_vec_normal(&norm,  &Vertices[sp->verts[vs[0]]], &Vertices[sp->verts[vs[1]]], &Vertices[sp->verts[vs[2]]]);
1405                 vm_vec_sub(&vec_13, &Vertices[sp->verts[vs[3]]], &Vertices[sp->verts[vs[1]]]);
1406                 dot = vm_vec_dot(&norm, &vec_13);
1407
1408                 //      Now, signifiy whether to triangulate from 0:2 or 1:3
1409                 if (dot >= 0)
1410                         sidep->type = SIDE_IS_TRI_02;
1411                 else
1412                         sidep->type = SIDE_IS_TRI_13;
1413
1414                 #ifndef COMPACT_SEGS
1415                 //      Now, based on triangulation type, set the normals.
1416                 if (sidep->type == SIDE_IS_TRI_02) {
1417                         vm_vec_normal(&norm,  &Vertices[sp->verts[vs[0]]], &Vertices[sp->verts[vs[1]]], &Vertices[sp->verts[vs[2]]]);
1418                         sidep->normals[0] = norm;
1419                         vm_vec_normal(&norm, &Vertices[sp->verts[vs[0]]], &Vertices[sp->verts[vs[2]]], &Vertices[sp->verts[vs[3]]]);
1420                         sidep->normals[1] = norm;
1421                 } else {
1422                         vm_vec_normal(&norm, &Vertices[sp->verts[vs[0]]], &Vertices[sp->verts[vs[1]]], &Vertices[sp->verts[vs[3]]]);
1423                         sidep->normals[0] = norm;
1424                         vm_vec_normal(&norm, &Vertices[sp->verts[vs[1]]], &Vertices[sp->verts[vs[2]]], &Vertices[sp->verts[vs[3]]]);
1425                         sidep->normals[1] = norm;
1426                 }
1427                 #endif
1428         } else {
1429                 int     i,v[4], vsorted[4];
1430                 int     negate_flag;
1431
1432                 for (i=0; i<4; i++)
1433                         v[i] = sp->verts[vs[i]];
1434
1435                 get_verts_for_normal(v[0], v[1], v[2], v[3], &vsorted[0], &vsorted[1], &vsorted[2], &vsorted[3], &negate_flag);
1436
1437                 if ((vsorted[0] == v[0]) || (vsorted[0] == v[2])) {
1438                         sidep->type = SIDE_IS_TRI_02;
1439                         #ifndef COMPACT_SEGS
1440                         //      Now, get vertices for normal for each triangle based on triangulation type.
1441                         get_verts_for_normal(v[0], v[1], v[2], 32767, &vsorted[0], &vsorted[1], &vsorted[2], &vsorted[3], &negate_flag);
1442                         vm_vec_normal(&norm,  &Vertices[vsorted[0]], &Vertices[vsorted[1]], &Vertices[vsorted[2]]);
1443                         if (negate_flag)
1444                                 vm_vec_negate(&norm);
1445                         sidep->normals[0] = norm;
1446
1447                         get_verts_for_normal(v[0], v[2], v[3], 32767, &vsorted[0], &vsorted[1], &vsorted[2], &vsorted[3], &negate_flag);
1448                         vm_vec_normal(&norm,  &Vertices[vsorted[0]], &Vertices[vsorted[1]], &Vertices[vsorted[2]]);
1449                         if (negate_flag)
1450                                 vm_vec_negate(&norm);
1451                         sidep->normals[1] = norm;
1452                         #endif
1453                 } else {
1454                         sidep->type = SIDE_IS_TRI_13;
1455                         #ifndef COMPACT_SEGS
1456                         //      Now, get vertices for normal for each triangle based on triangulation type.
1457                         get_verts_for_normal(v[0], v[1], v[3], 32767, &vsorted[0], &vsorted[1], &vsorted[2], &vsorted[3], &negate_flag);
1458                         vm_vec_normal(&norm,  &Vertices[vsorted[0]], &Vertices[vsorted[1]], &Vertices[vsorted[2]]);
1459                         if (negate_flag)
1460                                 vm_vec_negate(&norm);
1461                         sidep->normals[0] = norm;
1462
1463                         get_verts_for_normal(v[1], v[2], v[3], 32767, &vsorted[0], &vsorted[1], &vsorted[2], &vsorted[3], &negate_flag);
1464                         vm_vec_normal(&norm,  &Vertices[vsorted[0]], &Vertices[vsorted[1]], &Vertices[vsorted[2]]);
1465                         if (negate_flag)
1466                                 vm_vec_negate(&norm);
1467                         sidep->normals[1] = norm;
1468                         #endif
1469                 }
1470         }
1471 }
1472
1473 int sign(fix v)
1474 {
1475
1476         if (v > PLANE_DIST_TOLERANCE)
1477                 return 1;
1478         else if (v < -(PLANE_DIST_TOLERANCE+1))         //neg & pos round differently
1479                 return -1;
1480         else
1481                 return 0;
1482 }
1483
1484 // -------------------------------------------------------------------------------
1485 void create_walls_on_side(segment *sp, int sidenum)
1486 {
1487         int     vm0, vm1, vm2, vm3, negate_flag;
1488         int     v0, v1, v2, v3;
1489         vms_vector vn;
1490         fix     dist_to_plane;
1491
1492         v0 = sp->verts[Side_to_verts[sidenum][0]];
1493         v1 = sp->verts[Side_to_verts[sidenum][1]];
1494         v2 = sp->verts[Side_to_verts[sidenum][2]];
1495         v3 = sp->verts[Side_to_verts[sidenum][3]];
1496
1497         get_verts_for_normal(v0, v1, v2, v3, &vm0, &vm1, &vm2, &vm3, &negate_flag);
1498
1499         vm_vec_normal(&vn, &Vertices[vm0], &Vertices[vm1], &Vertices[vm2]);
1500         dist_to_plane = abs(vm_dist_to_plane(&Vertices[vm3], &vn, &Vertices[vm0]));
1501
1502 //if ((SEGMENT_NUMBER(sp) == 0x7b) && (sidenum == 3)) {
1503 //      mprintf((0, "Verts = %3i %3i %3i %3i, negate flag = %3i, dist = %8x\n", vm0, vm1, vm2, vm3, negate_flag, dist_to_plane));
1504 //      mprintf((0, "  Normal = %8x %8x %8x\n", vn.x, vn.y, vn.z));
1505 //      mprintf((0, "   Vert %3i = [%8x %8x %8x]\n", vm0, Vertices[vm0].x, Vertices[vm0].y, Vertices[vm0].z));
1506 //      mprintf((0, "   Vert %3i = [%8x %8x %8x]\n", vm1, Vertices[vm1].x, Vertices[vm1].y, Vertices[vm1].z));
1507 //      mprintf((0, "   Vert %3i = [%8x %8x %8x]\n", vm2, Vertices[vm2].x, Vertices[vm2].y, Vertices[vm2].z));
1508 //      mprintf((0, "   Vert %3i = [%8x %8x %8x]\n", vm3, Vertices[vm3].x, Vertices[vm3].y, Vertices[vm3].z));
1509 //}
1510
1511 //if ((SEGMENT_NUMBER(sp) == 0x86) && (sidenum == 5)) {
1512 //      mprintf((0, "Verts = %3i %3i %3i %3i, negate flag = %3i, dist = %8x\n", vm0, vm1, vm2, vm3, negate_flag, dist_to_plane));
1513 //      mprintf((0, "  Normal = %8x %8x %8x\n", vn.x, vn.y, vn.z));
1514 //      mprintf((0, "   Vert %3i = [%8x %8x %8x]\n", vm0, Vertices[vm0].x, Vertices[vm0].y, Vertices[vm0].z));
1515 //      mprintf((0, "   Vert %3i = [%8x %8x %8x]\n", vm1, Vertices[vm1].x, Vertices[vm1].y, Vertices[vm1].z));
1516 //      mprintf((0, "   Vert %3i = [%8x %8x %8x]\n", vm2, Vertices[vm2].x, Vertices[vm2].y, Vertices[vm2].z));
1517 //      mprintf((0, "   Vert %3i = [%8x %8x %8x]\n", vm3, Vertices[vm3].x, Vertices[vm3].y, Vertices[vm3].z));
1518 //}
1519
1520         if (negate_flag)
1521                 vm_vec_negate(&vn);
1522
1523         if (dist_to_plane <= PLANE_DIST_TOLERANCE)
1524                 add_side_as_quad(sp, sidenum, &vn);
1525         else {
1526                 add_side_as_2_triangles(sp, sidenum);
1527
1528                 //this code checks to see if we really should be triangulated, and
1529                 //de-triangulates if we shouldn't be.
1530
1531                 {
1532                         int                     num_faces;
1533                         int                     vertex_list[6];
1534                         fix                     dist0,dist1;
1535                         int                     s0,s1;
1536                         int                     vertnum;
1537                         side                    *s;
1538
1539                         create_abs_vertex_lists(&num_faces, vertex_list, SEGMENT_NUMBER(sp), sidenum, __FILE__, __LINE__);
1540
1541                         Assert(num_faces == 2);
1542
1543                         s = &sp->sides[sidenum];
1544
1545                         vertnum = min(vertex_list[0],vertex_list[2]);
1546
1547                         #ifdef COMPACT_SEGS
1548                         {
1549                         vms_vector normals[2];
1550                         get_side_normals(sp, sidenum, &normals[0], &normals[1] );
1551                         dist0 = vm_dist_to_plane(&Vertices[vertex_list[1]],&normals[1],&Vertices[vertnum]);
1552                         dist1 = vm_dist_to_plane(&Vertices[vertex_list[4]],&normals[0],&Vertices[vertnum]);
1553                         }
1554                         #else
1555                         dist0 = vm_dist_to_plane(&Vertices[vertex_list[1]],&s->normals[1],&Vertices[vertnum]);
1556                         dist1 = vm_dist_to_plane(&Vertices[vertex_list[4]],&s->normals[0],&Vertices[vertnum]);
1557                         #endif
1558
1559                         s0 = sign(dist0);
1560                         s1 = sign(dist1);
1561
1562                         if (s0==0 || s1==0 || s0!=s1) {
1563                                 sp->sides[sidenum].type = SIDE_IS_QUAD;         //detriangulate!
1564                                 #ifndef COMPACT_SEGS
1565                                 sp->sides[sidenum].normals[0] = vn;
1566                                 sp->sides[sidenum].normals[1] = vn;
1567                                 #endif
1568                         }
1569
1570                 }
1571         }
1572
1573 }
1574
1575
1576 #ifdef COMPACT_SEGS
1577
1578 //#define CACHE_DEBUG 1
1579 #define MAX_CACHE_NORMALS 128
1580 #define CACHE_MASK 127
1581
1582 typedef struct ncache_element {
1583         short segnum;
1584         ubyte sidenum;
1585         vms_vector normals[2];
1586 } ncache_element;
1587
1588 int ncache_initialized = 0;
1589 ncache_element ncache[MAX_CACHE_NORMALS];
1590
1591 #ifdef CACHE_DEBUG
1592 int ncache_counter = 0;
1593 int ncache_hits = 0;
1594 int ncache_misses = 0;
1595 #endif
1596
1597 void ncache_init()
1598 {
1599         ncache_flush();
1600         ncache_initialized = 1;
1601 }
1602
1603 void ncache_flush()
1604 {
1605         int i;
1606         for (i=0; i<MAX_CACHE_NORMALS; i++ )    {
1607                 ncache[i].segnum = -1;
1608         }       
1609 }
1610
1611
1612
1613 // -------------------------------------------------------------------------------
1614 int find_ncache_element( int segnum, int sidenum, int face_flags )
1615 {
1616         uint i;
1617
1618         if (!ncache_initialized) ncache_init();
1619
1620 #ifdef CACHE_DEBUG
1621         if (((++ncache_counter % 5000)==1) && (ncache_hits+ncache_misses > 0))
1622                 mprintf(( 0, "NCACHE %d%% missed, H:%d, M:%d\n", (ncache_misses*100)/(ncache_hits+ncache_misses), ncache_hits, ncache_misses ));
1623 #endif
1624
1625         i = ((segnum<<2) ^ sidenum) & CACHE_MASK;
1626
1627         if ((ncache[i].segnum == segnum) && ((ncache[i].sidenum&0xf)==sidenum) )        {
1628                 uint f1;
1629 #ifdef CACHE_DEBUG
1630                 ncache_hits++;
1631 #endif
1632                 f1 = ncache[i].sidenum>>4;
1633                 if ( (f1&face_flags)==face_flags )
1634                         return i;
1635                 if ( f1 & 1 )
1636                         uncached_get_side_normal( &Segments[segnum], sidenum, 1, &ncache[i].normals[1] );
1637                 else
1638                         uncached_get_side_normal( &Segments[segnum], sidenum, 0, &ncache[i].normals[0] );
1639                 ncache[i].sidenum |= face_flags<<4;
1640                 return i;
1641         }
1642 #ifdef CACHE_DEBUG
1643         ncache_misses++;
1644 #endif
1645
1646         switch( face_flags )    {
1647         case 1: 
1648                 uncached_get_side_normal( &Segments[segnum], sidenum, 0, &ncache[i].normals[0] );
1649                 break;
1650         case 2:
1651                 uncached_get_side_normal( &Segments[segnum], sidenum, 1, &ncache[i].normals[1] );
1652                 break;
1653         case 3:
1654                 uncached_get_side_normals(&Segments[segnum], sidenum, &ncache[i].normals[0], &ncache[i].normals[1] );
1655                 break;
1656         }
1657         ncache[i].segnum = segnum;
1658         ncache[i].sidenum = sidenum | (face_flags<<4);
1659         return i;
1660 }
1661
1662 void get_side_normal(segment *sp, int sidenum, int face_num, vms_vector * vm )
1663 {
1664         int i;
1665         i = find_ncache_element( SEGMENT_NUMBER(sp), sidenum, 1 << face_num );
1666         *vm = ncache[i].normals[face_num];
1667         if (0) {
1668                 vms_vector tmp;
1669                 uncached_get_side_normal(sp, sidenum, face_num, &tmp );
1670                 Assert( tmp.x == vm->x );
1671                 Assert( tmp.y == vm->y );
1672                 Assert( tmp.z == vm->z );
1673         }
1674 }
1675
1676 void get_side_normals(segment *sp, int sidenum, vms_vector * vm1, vms_vector * vm2 )
1677 {
1678         int i;
1679         i = find_ncache_element( SEGMENT_NUMBER(sp), sidenum, 3 );
1680         *vm1 = ncache[i].normals[0];
1681         *vm2 = ncache[i].normals[1];
1682
1683         if (0) {
1684                 vms_vector tmp;
1685                 uncached_get_side_normal(sp, sidenum, 0, &tmp );
1686                 Assert( tmp.x == vm1->x );
1687                 Assert( tmp.y == vm1->y );
1688                 Assert( tmp.z == vm1->z );
1689                 uncached_get_side_normal(sp, sidenum, 1, &tmp );
1690                 Assert( tmp.x == vm2->x );
1691                 Assert( tmp.y == vm2->y );
1692                 Assert( tmp.z == vm2->z );
1693         }
1694
1695 }
1696
1697 void uncached_get_side_normal(segment *sp, int sidenum, int face_num, vms_vector * vm )
1698 {
1699         int     vm0, vm1, vm2, vm3, negate_flag;
1700         char    *vs = Side_to_verts[sidenum];
1701
1702         switch( sp->sides[sidenum].type )       {
1703         case SIDE_IS_QUAD:
1704                 get_verts_for_normal(sp->verts[vs[0]], sp->verts[vs[1]], sp->verts[vs[2]], sp->verts[vs[3]], &vm0, &vm1, &vm2, &vm3, &negate_flag);
1705                 vm_vec_normal(vm, &Vertices[vm0], &Vertices[vm1], &Vertices[vm2]);
1706                 if (negate_flag)
1707                         vm_vec_negate(vm);
1708                 break;
1709         case SIDE_IS_TRI_02:
1710                 if ( face_num == 0 )
1711                         vm_vec_normal(vm, &Vertices[sp->verts[vs[0]]], &Vertices[sp->verts[vs[1]]], &Vertices[sp->verts[vs[2]]]);
1712                 else
1713                         vm_vec_normal(vm, &Vertices[sp->verts[vs[0]]], &Vertices[sp->verts[vs[2]]], &Vertices[sp->verts[vs[3]]]);
1714                 break;
1715         case SIDE_IS_TRI_13:
1716                 if ( face_num == 0 )
1717                         vm_vec_normal(vm, &Vertices[sp->verts[vs[0]]], &Vertices[sp->verts[vs[1]]], &Vertices[sp->verts[vs[3]]]);
1718                 else
1719                         vm_vec_normal(vm, &Vertices[sp->verts[vs[1]]], &Vertices[sp->verts[vs[2]]], &Vertices[sp->verts[vs[3]]]);
1720                 break;
1721         }
1722 }
1723
1724 void uncached_get_side_normals(segment *sp, int sidenum, vms_vector * vm1, vms_vector * vm2 )
1725 {
1726         int     vvm0, vvm1, vvm2, vvm3, negate_flag;
1727         char    *vs = Side_to_verts[sidenum];
1728
1729         switch( sp->sides[sidenum].type )       {
1730         case SIDE_IS_QUAD:
1731                 get_verts_for_normal(sp->verts[vs[0]], sp->verts[vs[1]], sp->verts[vs[2]], sp->verts[vs[3]], &vvm0, &vvm1, &vvm2, &vvm3, &negate_flag);
1732                 vm_vec_normal(vm1, &Vertices[vvm0], &Vertices[vvm1], &Vertices[vvm2]);
1733                 if (negate_flag)
1734                         vm_vec_negate(vm1);
1735                 *vm2 = *vm1;
1736                 break;
1737         case SIDE_IS_TRI_02:
1738                 vm_vec_normal(vm1, &Vertices[sp->verts[vs[0]]], &Vertices[sp->verts[vs[1]]], &Vertices[sp->verts[vs[2]]]);
1739                 vm_vec_normal(vm2, &Vertices[sp->verts[vs[0]]], &Vertices[sp->verts[vs[2]]], &Vertices[sp->verts[vs[3]]]);
1740                 break;
1741         case SIDE_IS_TRI_13:
1742                 vm_vec_normal(vm1, &Vertices[sp->verts[vs[0]]], &Vertices[sp->verts[vs[1]]], &Vertices[sp->verts[vs[3]]]);
1743                 vm_vec_normal(vm2, &Vertices[sp->verts[vs[1]]], &Vertices[sp->verts[vs[2]]], &Vertices[sp->verts[vs[3]]]);
1744                 break;
1745         }
1746 }
1747
1748 #endif
1749
1750 // -------------------------------------------------------------------------------
1751 void validate_removable_wall(segment *sp, int sidenum, int tmap_num)
1752 {
1753         create_walls_on_side(sp, sidenum);
1754
1755         sp->sides[sidenum].tmap_num = tmap_num;
1756
1757 //      assign_default_uvs_to_side(sp, sidenum);
1758 //      assign_light_to_side(sp, sidenum);
1759 }
1760
1761 // -------------------------------------------------------------------------------
1762 //      Make a just-modified segment side valid.
1763 void validate_segment_side(segment *sp, int sidenum)
1764 {
1765         if (sp->sides[sidenum].wall_num == -1)
1766                 create_walls_on_side(sp, sidenum);
1767         else
1768                 // create_removable_wall(sp, sidenum, sp->sides[sidenum].tmap_num);
1769                 validate_removable_wall(sp, sidenum, sp->sides[sidenum].tmap_num);
1770
1771         //      Set render_flag.
1772         //      If side doesn't have a child, then render wall.  If it does have a child, but there is a temporary
1773         //      wall there, then do render wall.
1774 //      if (sp->children[sidenum] == -1)
1775 //              sp->sides[sidenum].render_flag = 1;
1776 //      else if (sp->sides[sidenum].wall_num != -1)
1777 //              sp->sides[sidenum].render_flag = 1;
1778 //      else
1779 //              sp->sides[sidenum].render_flag = 0;
1780 }
1781
1782 extern int check_for_degenerate_segment(segment *sp);
1783
1784 // -------------------------------------------------------------------------------
1785 //      Make a just-modified segment valid.
1786 //              check all sides to see how many faces they each should have (0,1,2)
1787 //              create new vector normals
1788 void validate_segment(segment *sp)
1789 {
1790         int     side;
1791
1792         #ifdef EDITOR
1793         check_for_degenerate_segment(sp);
1794         #endif
1795
1796         for (side = 0; side < MAX_SIDES_PER_SEGMENT; side++)
1797                 validate_segment_side(sp, side);
1798
1799 //      assign_default_uvs_to_segment(sp);
1800 }
1801
1802 // -------------------------------------------------------------------------------
1803 //      Validate all segments.
1804 //      Highest_segment_index must be set.
1805 //      For all used segments (number <= Highest_segment_index), segnum field must be != -1.
1806 void validate_segment_all(void)
1807 {
1808         int     s;
1809
1810         for (s=0; s<=Highest_segment_index; s++)
1811                 #ifdef EDITOR
1812                 if (Segments[s].segnum != -1)
1813                 #endif
1814                         validate_segment(&Segments[s]);
1815
1816         #ifdef EDITOR
1817         {
1818                 int said=0;
1819                 for (s=Highest_segment_index+1; s<MAX_SEGMENTS; s++)
1820                         if (Segments[s].segnum != -1) {
1821                                 if (!said) {
1822                                         mprintf((0, "Segment %i has invalid segnum.  Bashing to -1.  Silently bashing all others...", s));
1823                                 }
1824                                 said++;
1825                                 Segments[s].segnum = -1;
1826                         }
1827
1828                 if (said)
1829                         mprintf((0, "%i fixed.\n", said));
1830         }
1831         #endif
1832
1833         #ifndef NDEBUG
1834         #ifndef COMPACT_SEGS
1835         if (check_segment_connections())
1836                 Int3();         //Get Matt, si vous plait.
1837         #endif
1838         #endif
1839 }
1840
1841
1842 //      ------------------------------------------------------------------------------------------------------
1843 //      Picks a random point in a segment like so:
1844 //              From center, go up to 50% of way towards any of the 8 vertices.
1845 void pick_random_point_in_seg(vms_vector *new_pos, int segnum)
1846 {
1847         int                     vnum;
1848         vms_vector      vec2;
1849
1850         compute_segment_center(new_pos, &Segments[segnum]);
1851         vnum = (d_rand() * MAX_VERTICES_PER_SEGMENT) >> 15;
1852         vm_vec_sub(&vec2, &Vertices[Segments[segnum].verts[vnum]], new_pos);
1853         vm_vec_scale(&vec2, d_rand());          // d_rand() always in 0..1/2
1854         vm_vec_add2(new_pos, &vec2);
1855 }
1856
1857
1858 //      ----------------------------------------------------------------------------------------------------------
1859 //      Set the segment depth of all segments from start_seg in *segbuf.
1860 //      Returns maximum depth value.
1861 int set_segment_depths(int start_seg, ubyte *segbuf)
1862 {
1863         int     i, curseg;
1864         ubyte   visited[MAX_SEGMENTS];
1865         int     queue[MAX_SEGMENTS];
1866         int     head, tail;
1867         int     depth;
1868         int     parent_depth=0;
1869
1870         depth = 1;
1871         head = 0;
1872         tail = 0;
1873
1874         for (i=0; i<=Highest_segment_index; i++)
1875                 visited[i] = 0;
1876
1877         if (segbuf[start_seg] == 0)
1878                 return 1;
1879
1880         queue[tail++] = start_seg;
1881         visited[start_seg] = 1;
1882         segbuf[start_seg] = depth++;
1883
1884         if (depth == 0)
1885                 depth = 255;
1886
1887         while (head < tail) {
1888                 curseg = queue[head++];
1889                 parent_depth = segbuf[curseg];
1890
1891                 for (i=0; i<MAX_SIDES_PER_SEGMENT; i++) {
1892                         int     childnum;
1893
1894                         childnum = Segments[curseg].children[i];
1895                         if (childnum != -1)
1896                                 if (segbuf[childnum])
1897                                         if (!visited[childnum]) {
1898                                                 visited[childnum] = 1;
1899                                                 segbuf[childnum] = parent_depth+1;
1900                                                 queue[tail++] = childnum;
1901                                         }
1902                 }
1903         }
1904
1905         return parent_depth+1;
1906 }
1907
1908 //these constants should match the ones in seguvs
1909 #define LIGHT_DISTANCE_THRESHOLD        (F1_0*80)
1910 #define Magical_light_constant  (F1_0*16)
1911
1912 #define MAX_CHANGED_SEGS 30
1913 short changed_segs[MAX_CHANGED_SEGS];
1914 int n_changed_segs;
1915
1916 //      ------------------------------------------------------------------------------------------
1917 //cast static light from a segment to nearby segments
1918 void apply_light_to_segment(segment *segp,vms_vector *segment_center, fix light_intensity,int recursion_depth)
1919 {
1920         vms_vector      r_segment_center;
1921         fix                     dist_to_rseg;
1922         int         i, segnum = SEGMENT_NUMBER(segp), sidenum;
1923
1924         for (i=0;i<n_changed_segs;i++)
1925                 if (changed_segs[i] == segnum)
1926                         break;
1927
1928         if (i == n_changed_segs) {
1929                 compute_segment_center(&r_segment_center, segp);
1930                 dist_to_rseg = vm_vec_dist_quick(&r_segment_center, segment_center);
1931         
1932                 if (dist_to_rseg <= LIGHT_DISTANCE_THRESHOLD) {
1933                         fix     light_at_point;
1934                         if (dist_to_rseg > F1_0)
1935                                 light_at_point = fixdiv(Magical_light_constant, dist_to_rseg);
1936                         else
1937                                 light_at_point = Magical_light_constant;
1938         
1939                         if (light_at_point >= 0) {
1940                                 segment2        *seg2p  = &Segment2s[segnum];
1941                                 light_at_point = fixmul(light_at_point, light_intensity);
1942 #if 0   // don't see the point, static_light can be greater than F1_0
1943                                 if (light_at_point >= F1_0)
1944                                         light_at_point = F1_0-1;
1945                                 if (light_at_point <= -F1_0)
1946                                         light_at_point = -(F1_0-1);
1947 #endif
1948                                 seg2p->static_light += light_at_point;
1949                                 if (seg2p->static_light < 0)    // if it went negative, saturate
1950                                         seg2p->static_light = 0;
1951                         }       //      end if (light_at_point...
1952                 }       //      end if (dist_to_rseg...
1953
1954                 changed_segs[n_changed_segs++] = segnum;
1955         }
1956
1957         if (recursion_depth < 2)
1958                 for (sidenum=0; sidenum<6; sidenum++) {
1959                         if (WALL_IS_DOORWAY(segp,sidenum) & WID_RENDPAST_FLAG)
1960                                 apply_light_to_segment(&Segments[segp->children[sidenum]],segment_center,light_intensity,recursion_depth+1);
1961                 }
1962
1963 }
1964
1965
1966 extern object *old_viewer;
1967
1968 //update the static_light field in a segment, which is used for object lighting
1969 //this code is copied from the editor routine calim_process_all_lights()
1970 void change_segment_light(int segnum,int sidenum,int dir)
1971 {
1972         segment *segp = &Segments[segnum];
1973
1974         if (WALL_IS_DOORWAY(segp, sidenum) & WID_RENDER_FLAG) {
1975                 side    *sidep = &segp->sides[sidenum];
1976                 fix     light_intensity;
1977
1978                 light_intensity = TmapInfo[sidep->tmap_num].lighting + TmapInfo[sidep->tmap_num2 & 0x3fff].lighting;
1979
1980                 light_intensity *= dir;
1981
1982                 n_changed_segs = 0;
1983
1984                 if (light_intensity) {
1985                         vms_vector      segment_center;
1986                         compute_segment_center(&segment_center, segp);
1987                         apply_light_to_segment(segp,&segment_center,light_intensity,0);
1988                 }
1989         }
1990
1991         //this is a horrible hack to get around the horrible hack used to
1992         //smooth lighting values when an object moves between segments
1993         old_viewer = NULL;
1994
1995 }
1996
1997 //      ------------------------------------------------------------------------------------------
1998 //      dir = +1 -> add light
1999 //      dir = -1 -> subtract light
2000 //      dir = 17 -> add 17x light
2001 //      dir =  0 -> you are dumb
2002 void change_light(int segnum, int sidenum, int dir)
2003 {
2004         int     i, j, k;
2005
2006         for (i=0; i<Num_static_lights; i++) {
2007                 if ((Dl_indices[i].segnum == segnum) && (Dl_indices[i].sidenum == sidenum)) {
2008                         delta_light     *dlp;
2009                         dlp = &Delta_lights[Dl_indices[i].index];
2010
2011                         for (j=0; j<Dl_indices[i].count; j++) {
2012                                 for (k=0; k<4; k++) {
2013                                         fix     dl,new_l;
2014                                         dl = dir * dlp->vert_light[k] * DL_SCALE;
2015                                         Assert((dlp->segnum >= 0) && (dlp->segnum <= Highest_segment_index));
2016                                         Assert((dlp->sidenum >= 0) && (dlp->sidenum < MAX_SIDES_PER_SEGMENT));
2017                                         new_l = (Segments[dlp->segnum].sides[dlp->sidenum].uvls[k].l += dl);
2018                                         if (new_l < 0)
2019                                                 Segments[dlp->segnum].sides[dlp->sidenum].uvls[k].l = 0;
2020                                 }
2021                                 dlp++;
2022                         }
2023                 }
2024         }
2025
2026         //recompute static light for segment
2027         change_segment_light(segnum,sidenum,dir);
2028 }
2029
2030 //      Subtract light cast by a light source from all surfaces to which it applies light.
2031 //      This is precomputed data, stored at static light application time in the editor (the slow lighting function).
2032 // returns 1 if lights actually subtracted, else 0
2033 int subtract_light(int segnum, int sidenum)
2034 {
2035         if (Light_subtracted[segnum] & (1 << sidenum)) {
2036                 //mprintf((0, "Warning: Trying to subtract light from a source twice!\n"));
2037                 return 0;
2038         }
2039
2040         Light_subtracted[segnum] |= (1 << sidenum);
2041         change_light(segnum, sidenum, -1);
2042         return 1;
2043 }
2044
2045 //      Add light cast by a light source from all surfaces to which it applies light.
2046 //      This is precomputed data, stored at static light application time in the editor (the slow lighting function).
2047 //      You probably only want to call this after light has been subtracted.
2048 // returns 1 if lights actually added, else 0
2049 int add_light(int segnum, int sidenum)
2050 {
2051         if (!(Light_subtracted[segnum] & (1 << sidenum))) {
2052                 //mprintf((0, "Warning: Trying to add light which has never been subtracted!\n"));
2053                 return 0;
2054         }
2055
2056         Light_subtracted[segnum] &= ~(1 << sidenum);
2057         change_light(segnum, sidenum, 1);
2058         return 1;
2059 }
2060
2061 //      Light_subtracted[i] contains bit indicators for segment #i.
2062 //      If bit n (1 << n) is set, then side #n in segment #i has had light subtracted from original (editor-computed) value.
2063 ubyte   Light_subtracted[MAX_SEGMENTS];
2064
2065 //      Parse the Light_subtracted array, turning on or off all lights.
2066 void apply_all_changed_light(void)
2067 {
2068         int     i,j;
2069
2070         for (i=0; i<=Highest_segment_index; i++) {
2071                 for (j=0; j<MAX_SIDES_PER_SEGMENT; j++)
2072                         if (Light_subtracted[i] & (1 << j))
2073                                 change_light(i, j, -1);
2074         }
2075 }
2076
2077 //@@//  Scans Light_subtracted bit array.
2078 //@@//  For all light sources which have had their light subtracted, adds light back in.
2079 //@@void restore_all_lights_in_mine(void)
2080 //@@{
2081 //@@    int     i, j, k;
2082 //@@
2083 //@@    for (i=0; i<Num_static_lights; i++) {
2084 //@@            int     segnum, sidenum;
2085 //@@            delta_light     *dlp;
2086 //@@
2087 //@@            segnum = Dl_indices[i].segnum;
2088 //@@            sidenum = Dl_indices[i].sidenum;
2089 //@@            if (Light_subtracted[segnum] & (1 << sidenum)) {
2090 //@@                    dlp = &Delta_lights[Dl_indices[i].index];
2091 //@@
2092 //@@                    Light_subtracted[segnum] &= ~(1 << sidenum);
2093 //@@                    for (j=0; j<Dl_indices[i].count; j++) {
2094 //@@                            for (k=0; k<4; k++) {
2095 //@@                                    fix     dl;
2096 //@@                                    dl = dlp->vert_light[k] * DL_SCALE;
2097 //@@                                    Assert((dlp->segnum >= 0) && (dlp->segnum <= Highest_segment_index));
2098 //@@                                    Assert((dlp->sidenum >= 0) && (dlp->sidenum < MAX_SIDES_PER_SEGMENT));
2099 //@@                                    Segments[dlp->segnum].sides[dlp->sidenum].uvls[k].l += dl;
2100 //@@                            }
2101 //@@                            dlp++;
2102 //@@                    }
2103 //@@            }
2104 //@@    }
2105 //@@}
2106
2107 //      Should call this whenever a new mine gets loaded.
2108 //      More specifically, should call this whenever something global happens
2109 //      to change the status of static light in the mine.
2110 void clear_light_subtracted(void)
2111 {
2112         int     i;
2113
2114         for (i=0; i<=Highest_segment_index; i++)
2115                 Light_subtracted[i] = 0;
2116
2117 }
2118
2119 //      -----------------------------------------------------------------------------
2120 fix find_connected_distance_segments( int seg0, int seg1, int depth, int wid_flag)
2121 {
2122         vms_vector      p0, p1;
2123
2124         compute_segment_center(&p0, &Segments[seg0]);
2125         compute_segment_center(&p1, &Segments[seg1]);
2126
2127         return find_connected_distance(&p0, seg0, &p1, seg1, depth, wid_flag);
2128 }
2129
2130 #define AMBIENT_SEGMENT_DEPTH           5
2131
2132 //      -----------------------------------------------------------------------------
2133 //      Do a bfs from segnum, marking slots in marked_segs if the segment is reachable.
2134 void ambient_mark_bfs(int segnum, sbyte *marked_segs, int depth)
2135 {
2136         int     i;
2137
2138         if (depth < 0)
2139                 return;
2140
2141         marked_segs[segnum] = 1;
2142
2143         for (i=0; i<MAX_SIDES_PER_SEGMENT; i++) {
2144                 int     child = Segments[segnum].children[i];
2145
2146                 if (IS_CHILD(child) && (WALL_IS_DOORWAY(&Segments[segnum],i) & WID_RENDPAST_FLAG) && !marked_segs[child])
2147                         ambient_mark_bfs(child, marked_segs, depth-1);
2148         }
2149
2150 }
2151
2152 //      -----------------------------------------------------------------------------
2153 //      Indicate all segments which are within audible range of falling water or lava,
2154 //      and so should hear ambient gurgles.
2155 void set_ambient_sound_flags_common(int tmi_bit, int s2f_bit)
2156 {
2157         int     i, j;
2158         sbyte   marked_segs[MAX_SEGMENTS];
2159
2160         //      Now, all segments containing ambient lava or water sound makers are flagged.
2161         //      Additionally flag all segments which are within range of them.
2162         for (i=0; i<=Highest_segment_index; i++) {
2163                 marked_segs[i] = 0;
2164                 Segment2s[i].s2_flags &= ~s2f_bit;
2165         }
2166
2167         //      Mark all segments which are sources of the sound.
2168         for (i=0; i<=Highest_segment_index; i++) {
2169                 segment *segp = &Segments[i];
2170                 segment2        *seg2p = &Segment2s[i];
2171
2172                 for (j=0; j<MAX_SIDES_PER_SEGMENT; j++) {
2173                         side    *sidep = &segp->sides[j];
2174
2175                         if ((TmapInfo[sidep->tmap_num].flags & tmi_bit) || (TmapInfo[sidep->tmap_num2 & 0x3fff].flags & tmi_bit)) {
2176                                 if (!IS_CHILD(segp->children[j]) || (sidep->wall_num != -1)) {
2177                                         seg2p->s2_flags |= s2f_bit;
2178                                         marked_segs[i] = 1;             //      Say it's itself that it is close enough to to hear something.
2179                                 }
2180                         }
2181
2182                 }
2183
2184         }
2185
2186         //      Next mark all segments within N segments of a source.
2187         for (i=0; i<=Highest_segment_index; i++) {
2188                 segment2        *seg2p = &Segment2s[i];
2189
2190                 if (seg2p->s2_flags & s2f_bit)
2191                         ambient_mark_bfs(i, marked_segs, AMBIENT_SEGMENT_DEPTH);
2192         }
2193
2194         //      Now, flip bits in all segments which can hear the ambient sound.
2195         for (i=0; i<=Highest_segment_index; i++)
2196                 if (marked_segs[i])
2197                         Segment2s[i].s2_flags |= s2f_bit;
2198
2199 }
2200
2201
2202 //      -----------------------------------------------------------------------------
2203 //      Indicate all segments which are within audible range of falling water or lava,
2204 //      and so should hear ambient gurgles.
2205 //      Bashes values in Segment2s array.
2206 void set_ambient_sound_flags(void)
2207 {
2208         set_ambient_sound_flags_common(TMI_VOLATILE, S2F_AMBIENT_LAVA);
2209         set_ambient_sound_flags_common(TMI_WATER, S2F_AMBIENT_WATER);
2210 }