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