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