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.
16 * Functions moved from segment.c to make editor separable from game.
26 #include <string.h> // for memset()
41 // How far a point can be from a plane, and still be "in" the plane
42 #define PLANE_DIST_TOLERANCE 250
44 dl_index Dl_indices[MAX_DL_INDICES];
45 delta_light Delta_lights[MAX_DELTA_LIGHTS];
46 int Num_static_lights;
48 // ------------------------------------------------------------------------------------------
49 // Compute the center point of a side of a segment.
50 // The center point is defined to be the average of the 4 points defining the side.
51 void compute_center_point_on_side(vms_vector *vp,segment *sp,int side)
58 vm_vec_add2(vp,&Vertices[sp->verts[Side_to_verts[side][v]]]);
60 vm_vec_scale(vp,F1_0/4);
63 // ------------------------------------------------------------------------------------------
64 // Compute segment center.
65 // The center point is defined to be the average of the 8 points defining the segment.
66 void compute_segment_center(vms_vector *vp,segment *sp)
73 vm_vec_add2(vp,&Vertices[sp->verts[v]]);
75 vm_vec_scale(vp,F1_0/8);
78 // -----------------------------------------------------------------------------
79 // Given two segments, return the side index in the connecting segment which connects to the base segment
80 // Optimized by MK on 4/21/94 because it is a 2% load.
81 int find_connect_side(segment *base_seg, segment *con_seg)
84 short base_seg_num = SEGMENT_NUMBER(base_seg);
85 short *childs = con_seg->children;
87 for (s=0; s<MAX_SIDES_PER_SEGMENT; s++) {
88 if (*childs++ == base_seg_num)
93 // legal to return -1, used in object_move_one(), mk, 06/08/94: Assert(0); // Illegal -- there is no connecting side between these two segments
98 // -----------------------------------------------------------------------------------
99 // Given a side, return the number of faces
100 int get_num_faces(side *sidep)
102 switch (sidep->type) {
111 Error("Illegal type = %i\n", sidep->type);
117 // Fill in array with four absolute point numbers for a given side
118 void get_side_verts(short *vertlist,int segnum,int sidenum)
121 sbyte *sv = Side_to_verts[sidenum];
122 short *vp = Segments[segnum].verts;
125 vertlist[i] = vp[sv[i]];
130 // -----------------------------------------------------------------------------------
131 // Create all vertex lists (1 or 2) for faces on a side.
133 // num_faces number of lists
134 // vertices vertices in all (1 or 2) faces
135 // If there is one face, it has 4 vertices.
136 // If there are two faces, they both have three vertices, so face #0 is stored in vertices 0,1,2,
137 // face #1 is stored in vertices 3,4,5.
138 // Note: these are not absolute vertex numbers, but are relative to the segment
139 // Note: for triagulated sides, the middle vertex of each trianle is the one NOT
140 // adjacent on the diagonal edge
141 void create_all_vertex_lists(int *num_faces, int *vertices, int segnum, int sidenum)
143 side *sidep = &Segments[segnum].sides[sidenum];
144 int *sv = Side_to_verts_int[sidenum];
146 Assert((segnum <= Highest_segment_index) && (segnum >= 0));
147 Assert((sidenum >= 0) && (sidenum < 6));
149 switch (sidep->type) {
170 //IMPORTANT: DON'T CHANGE THIS CODE WITHOUT CHANGING GET_SEG_MASKS()
171 //CREATE_ABS_VERTEX_LISTS(), CREATE_ALL_VERTEX_LISTS(), CREATE_ALL_VERTNUM_LISTS()
184 //IMPORTANT: DON'T CHANGE THIS CODE WITHOUT CHANGING GET_SEG_MASKS()
185 //CREATE_ABS_VERTEX_LISTS(), CREATE_ALL_VERTEX_LISTS(), CREATE_ALL_VERTNUM_LISTS()
188 Error("Illegal side type (1), type = %i, segment # = %i, side # = %i\n Please report this bug.\n", sidep->type, segnum, sidenum);
195 // -----------------------------------------------------------------------------------
196 // Like create all vertex lists, but returns the vertnums (relative to
197 // the side) for each of the faces that make up the side.
198 // If there is one face, it has 4 vertices.
199 // If there are two faces, they both have three vertices, so face #0 is stored in vertices 0,1,2,
200 // face #1 is stored in vertices 3,4,5.
201 void create_all_vertnum_lists(int *num_faces, int *vertnums, int segnum, int sidenum)
203 side *sidep = &Segments[segnum].sides[sidenum];
205 Assert((segnum <= Highest_segment_index) && (segnum >= 0));
207 switch (sidep->type) {
228 //IMPORTANT: DON'T CHANGE THIS CODE WITHOUT CHANGING GET_SEG_MASKS()
229 //CREATE_ABS_VERTEX_LISTS(), CREATE_ALL_VERTEX_LISTS(), CREATE_ALL_VERTNUM_LISTS()
242 //IMPORTANT: DON'T CHANGE THIS CODE WITHOUT CHANGING GET_SEG_MASKS()
243 //CREATE_ABS_VERTEX_LISTS(), CREATE_ALL_VERTEX_LISTS(), CREATE_ALL_VERTNUM_LISTS()
246 Error("Illegal side type (2), type = %i, segment # = %i, side # = %i\n Please report this bug.\n", sidep->type, segnum, sidenum);
253 // like create_all_vertex_lists(), but generate absolute point numbers
254 void create_abs_vertex_lists(int *num_faces, int *vertices, int segnum, int sidenum, char *calling_file, int calling_linenum)
256 short *vp = Segments[segnum].verts;
257 side *sidep = &Segments[segnum].sides[sidenum];
258 int *sv = Side_to_verts_int[sidenum];
260 Assert((segnum <= Highest_segment_index) && (segnum >= 0));
262 switch (sidep->type) {
265 vertices[0] = vp[sv[0]];
266 vertices[1] = vp[sv[1]];
267 vertices[2] = vp[sv[2]];
268 vertices[3] = vp[sv[3]];
275 vertices[0] = vp[sv[0]];
276 vertices[1] = vp[sv[1]];
277 vertices[2] = vp[sv[2]];
279 vertices[3] = vp[sv[2]];
280 vertices[4] = vp[sv[3]];
281 vertices[5] = vp[sv[0]];
283 //IMPORTANT: DON'T CHANGE THIS CODE WITHOUT CHANGING GET_SEG_MASKS(),
284 //CREATE_ABS_VERTEX_LISTS(), CREATE_ALL_VERTEX_LISTS(), CREATE_ALL_VERTNUM_LISTS()
289 vertices[0] = vp[sv[3]];
290 vertices[1] = vp[sv[0]];
291 vertices[2] = vp[sv[1]];
293 vertices[3] = vp[sv[1]];
294 vertices[4] = vp[sv[2]];
295 vertices[5] = vp[sv[3]];
297 //IMPORTANT: DON'T CHANGE THIS CODE WITHOUT CHANGING GET_SEG_MASKS()
298 //CREATE_ABS_VERTEX_LISTS(), CREATE_ALL_VERTEX_LISTS(), CREATE_ALL_VERTNUM_LISTS()
301 Error("Illegal side type (3), type = %i, segment # = %i, side # = %i caller:%s:%i\n Please report this bug.\n", sidep->type, segnum, sidenum, calling_file, calling_linenum);
308 //returns 3 different bitmasks with info telling if this sphere is in
309 //this segment. See segmasks structure for info on fields
310 segmasks get_seg_masks(vms_vector *checkp, int segnum, fix rad, char *calling_file, int calling_linenum)
312 int sn,facebit,sidebit;
319 Error("segnum == -1 in get_seg_masks()");
321 Assert((segnum <= Highest_segment_index) && (segnum >= 0));
323 seg = &Segments[segnum];
325 //check point against each side of segment. return bitmask
327 masks.sidemask = masks.facemask = masks.centermask = 0;
329 for (sn=0,facebit=sidebit=1;sn<6;sn++,sidebit<<=1) {
331 side *s = &seg->sides[sn];
336 // Get number of faces on this side, and at vertex_list, store vertices.
337 // If one face, then vertex_list indicates a quadrilateral.
338 // If two faces, then 0,1,2 define one triangle, 3,4,5 define the second.
339 create_abs_vertex_lists(&num_faces, vertex_list, segnum, sn, calling_file, calling_linenum);
341 //ok...this is important. If a side has 2 faces, we need to know if
342 //those faces form a concave or convex side. If the side pokes out,
343 //then a point is on the back of the side if it is behind BOTH faces,
344 //but if the side pokes in, a point is on the back if behind EITHER face.
348 int side_count,center_count;
350 vms_vector normals[2];
353 vertnum = min(vertex_list[0],vertex_list[2]);
356 get_side_normals(seg, sn, &normals[0], &normals[1] );
359 if (vertex_list[4] < vertex_list[1])
361 dist = vm_dist_to_plane(&Vertices[vertex_list[4]],&normals[0],&Vertices[vertnum]);
363 dist = vm_dist_to_plane(&Vertices[vertex_list[4]],&s->normals[0],&Vertices[vertnum]);
367 dist = vm_dist_to_plane(&Vertices[vertex_list[1]],&normals[1],&Vertices[vertnum]);
369 dist = vm_dist_to_plane(&Vertices[vertex_list[1]],&s->normals[1],&Vertices[vertnum]);
372 side_pokes_out = (dist > PLANE_DIST_TOLERANCE);
374 side_count = center_count = 0;
376 for (fn=0;fn<2;fn++,facebit<<=1) {
379 dist = vm_dist_to_plane(checkp, &normals[fn], &Vertices[vertnum]);
381 dist = vm_dist_to_plane(checkp, &s->normals[fn], &Vertices[vertnum]);
384 if (dist < -PLANE_DIST_TOLERANCE) //in front of face
387 if (dist-rad < -PLANE_DIST_TOLERANCE) {
388 masks.facemask |= facebit;
393 if (!side_pokes_out) { //must be behind both faces
396 masks.sidemask |= sidebit;
399 masks.centermask |= sidebit;
402 else { //must be behind at least one face
405 masks.sidemask |= sidebit;
408 masks.centermask |= sidebit;
414 else { //only one face on this side
421 //use lowest point number
423 vertnum = vertex_list[0];
425 if (vertex_list[i] < vertnum)
426 vertnum = vertex_list[i];
429 get_side_normal(seg, sn, 0, &normal );
430 dist = vm_dist_to_plane(checkp, &normal, &Vertices[vertnum]);
432 dist = vm_dist_to_plane(checkp, &s->normals[0], &Vertices[vertnum]);
436 if (dist < -PLANE_DIST_TOLERANCE)
437 masks.centermask |= sidebit;
439 if (dist-rad < -PLANE_DIST_TOLERANCE) {
440 masks.facemask |= facebit;
441 masks.sidemask |= sidebit;
453 //this was converted from get_seg_masks()...it fills in an array of 6
454 //elements for the distace behind each side, or zero if not behind
455 //only gets centermask, and assumes zero rad
456 ubyte get_side_dists(vms_vector *checkp,int segnum,fix *side_dists)
458 int sn,facebit,sidebit;
464 Assert((segnum <= Highest_segment_index) && (segnum >= 0));
467 Error("segnum == -1 in get_seg_dists()");
469 seg = &Segments[segnum];
471 //check point against each side of segment. return bitmask
475 for (sn=0,facebit=sidebit=1;sn<6;sn++,sidebit<<=1) {
477 side *s = &seg->sides[sn];
484 // Get number of faces on this side, and at vertex_list, store vertices.
485 // If one face, then vertex_list indicates a quadrilateral.
486 // If two faces, then 0,1,2 define one triangle, 3,4,5 define the second.
487 create_abs_vertex_lists(&num_faces, vertex_list, segnum, sn, __FILE__, __LINE__);
489 //ok...this is important. If a side has 2 faces, we need to know if
490 //those faces form a concave or convex side. If the side pokes out,
491 //then a point is on the back of the side if it is behind BOTH faces,
492 //but if the side pokes in, a point is on the back if behind EITHER face.
499 vms_vector normals[2];
502 vertnum = min(vertex_list[0],vertex_list[2]);
505 get_side_normals(seg, sn, &normals[0], &normals[1] );
508 if (vertex_list[4] < vertex_list[1])
510 dist = vm_dist_to_plane(&Vertices[vertex_list[4]],&normals[0],&Vertices[vertnum]);
512 dist = vm_dist_to_plane(&Vertices[vertex_list[4]],&s->normals[0],&Vertices[vertnum]);
516 dist = vm_dist_to_plane(&Vertices[vertex_list[1]],&normals[1],&Vertices[vertnum]);
518 dist = vm_dist_to_plane(&Vertices[vertex_list[1]],&s->normals[1],&Vertices[vertnum]);
521 side_pokes_out = (dist > PLANE_DIST_TOLERANCE);
525 for (fn=0;fn<2;fn++,facebit<<=1) {
528 dist = vm_dist_to_plane(checkp, &normals[fn], &Vertices[vertnum]);
530 dist = vm_dist_to_plane(checkp, &s->normals[fn], &Vertices[vertnum]);
533 if (dist < -PLANE_DIST_TOLERANCE) { //in front of face
535 side_dists[sn] += dist;
540 if (!side_pokes_out) { //must be behind both faces
542 if (center_count==2) {
544 side_dists[sn] /= 2; //get average
549 else { //must be behind at least one face
554 side_dists[sn] /= 2; //get average
561 else { //only one face on this side
569 //use lowest point number
571 vertnum = vertex_list[0];
573 if (vertex_list[i] < vertnum)
574 vertnum = vertex_list[i];
577 get_side_normal(seg, sn, 0, &normal );
578 dist = vm_dist_to_plane(checkp, &normal, &Vertices[vertnum]);
580 dist = vm_dist_to_plane(checkp, &s->normals[0], &Vertices[vertnum]);
583 if (dist < -PLANE_DIST_TOLERANCE) {
585 side_dists[sn] = dist;
599 //returns true if errors detected
600 int check_norms(int segnum,int sidenum,int facenum,int csegnum,int csidenum,int cfacenum)
604 n0 = &Segments[segnum].sides[sidenum].normals[facenum];
605 n1 = &Segments[csegnum].sides[csidenum].normals[cfacenum];
607 if (n0->x != -n1->x || n0->y != -n1->y || n0->z != -n1->z) {
608 mprintf((0,"Seg %x, side %d, norm %d doesn't match seg %x, side %d, norm %d:\n"
610 " %8x %8x %8x (negated)\n",
611 segnum,sidenum,facenum,csegnum,csidenum,cfacenum,
612 n0->x,n0->y,n0->z,-n1->x,-n1->y,-n1->z));
619 //heavy-duty error checking
620 int check_segment_connections(void)
625 for (segnum=0;segnum<=Highest_segment_index;segnum++) {
628 seg = &Segments[segnum];
630 for (sidenum=0;sidenum<6;sidenum++) {
634 int num_faces,csegnum,csidenum,con_num_faces;
635 int vertex_list[6],con_vertex_list[6];
637 s = &seg->sides[sidenum];
639 create_abs_vertex_lists(&num_faces, vertex_list, segnum, sidenum, __FILE__, __LINE__);
641 csegnum = seg->children[sidenum];
644 cseg = &Segments[csegnum];
645 csidenum = find_connect_side(seg,cseg);
647 if (csidenum == -1) {
648 mprintf((0,"Could not find connected side for seg %x back to seg %x, side %d\n",csegnum,segnum,sidenum));
653 cs = &cseg->sides[csidenum];
655 create_abs_vertex_lists(&con_num_faces, con_vertex_list, csegnum, csidenum, __FILE__, __LINE__);
657 if (con_num_faces != num_faces) {
658 mprintf((0,"Seg %x, side %d: num_faces (%d) mismatch with seg %x, side %d (%d)\n",segnum,sidenum,num_faces,csegnum,csidenum,con_num_faces));
662 if (num_faces == 1) {
665 for (t=0;t<4 && con_vertex_list[t]!=vertex_list[0];t++);
668 vertex_list[0] != con_vertex_list[t] ||
669 vertex_list[1] != con_vertex_list[(t+3)%4] ||
670 vertex_list[2] != con_vertex_list[(t+2)%4] ||
671 vertex_list[3] != con_vertex_list[(t+1)%4]) {
672 mprintf((0,"Seg %x, side %d: vertex list mismatch with seg %x, side %d\n"
675 segnum,sidenum,csegnum,csidenum,
676 vertex_list[0],vertex_list[1],vertex_list[2],vertex_list[3],
677 con_vertex_list[0],con_vertex_list[1],con_vertex_list[2],con_vertex_list[3]));
681 errors |= check_norms(segnum,sidenum,0,csegnum,csidenum,0);
686 if (vertex_list[1] == con_vertex_list[1]) {
688 if (vertex_list[4] != con_vertex_list[4] ||
689 vertex_list[0] != con_vertex_list[2] ||
690 vertex_list[2] != con_vertex_list[0] ||
691 vertex_list[3] != con_vertex_list[5] ||
692 vertex_list[5] != con_vertex_list[3]) {
693 mprintf((0,"Seg %x, side %d: vertex list mismatch with seg %x, side %d\n"
694 " %x %x %x %x %x %x\n"
695 " %x %x %x %x %x %x\n",
696 segnum,sidenum,csegnum,csidenum,
697 vertex_list[0],vertex_list[1],vertex_list[2],vertex_list[3],vertex_list[4],vertex_list[5],
698 con_vertex_list[0],con_vertex_list[1],con_vertex_list[2],con_vertex_list[3],con_vertex_list[4],con_vertex_list[5]));
699 mprintf((0,"Changing seg:side %4i:%i from %i to %i\n", csegnum, csidenum, Segments[csegnum].sides[csidenum].type, 5-Segments[csegnum].sides[csidenum].type));
700 Segments[csegnum].sides[csidenum].type = 5-Segments[csegnum].sides[csidenum].type;
702 errors |= check_norms(segnum,sidenum,0,csegnum,csidenum,0);
703 errors |= check_norms(segnum,sidenum,1,csegnum,csidenum,1);
708 if (vertex_list[1] != con_vertex_list[4] ||
709 vertex_list[4] != con_vertex_list[1] ||
710 vertex_list[0] != con_vertex_list[5] ||
711 vertex_list[5] != con_vertex_list[0] ||
712 vertex_list[2] != con_vertex_list[3] ||
713 vertex_list[3] != con_vertex_list[2]) {
714 mprintf((0,"Seg %x, side %d: vertex list mismatch with seg %x, side %d\n"
715 " %x %x %x %x %x %x\n"
716 " %x %x %x %x %x %x\n",
717 segnum,sidenum,csegnum,csidenum,
718 vertex_list[0],vertex_list[1],vertex_list[2],vertex_list[3],vertex_list[4],vertex_list[5],
719 con_vertex_list[0],con_vertex_list[1],con_vertex_list[2],con_vertex_list[3],con_vertex_list[4],vertex_list[5]));
720 mprintf((0,"Changing seg:side %4i:%i from %i to %i\n", csegnum, csidenum, Segments[csegnum].sides[csidenum].type, 5-Segments[csegnum].sides[csidenum].type));
721 Segments[csegnum].sides[csidenum].type = 5-Segments[csegnum].sides[csidenum].type;
723 errors |= check_norms(segnum,sidenum,0,csegnum,csidenum,1);
724 errors |= check_norms(segnum,sidenum,1,csegnum,csidenum,0);
732 // mprintf((0,"\n DONE \n"));
740 // Used to become a constant based on editor, but I wanted to be able to set
741 // this for omega blob find_point_seg calls.
742 // Would be better to pass a paremeter to the routine...--MK, 01/17/96
743 int Doing_lighting_hack_flag=0;
745 // figure out what seg the given point is in, tracing through segments
746 // returns segment number, or -1 if can't find segment
747 int trace_segs(vms_vector *p0, int oldsegnum, int recursion_count)
753 int sidenum, bit, check, biggest_side;
754 static ubyte visited [MAX_SEGMENTS];
756 Assert((oldsegnum <= Highest_segment_index) && (oldsegnum >= 0));
758 if (recursion_count >= Num_segments) {
759 con_printf (CON_DEBUG, "trace_segs: Segment not found\n");
760 mprintf ((0,"trace_segs (gameseg.c): Error: infinite loop\n"));
763 if (recursion_count == 0)
764 memset (visited, 0, sizeof (visited));
765 if (visited [oldsegnum])
767 visited [oldsegnum] = 1;
769 centermask = get_side_dists(p0,oldsegnum,side_dists); //check old segment
770 if (centermask == 0) // we are in the old segment
771 return oldsegnum; //..say so
774 seg = &Segments[oldsegnum];
777 for (sidenum = 0, bit = 1; sidenum < 6; sidenum++, bit <<= 1)
778 if ((centermask & bit) && (seg->children[sidenum] > -1)
779 && side_dists[sidenum] < biggest_val) {
780 biggest_val = side_dists[sidenum];
781 biggest_side = sidenum;
784 if (biggest_side == -1)
787 side_dists[biggest_side] = 0;
788 // trace into adjacent segment:
789 check = trace_segs(p0, seg->children[biggest_side], recursion_count + 1);
790 if (check >= 0) //we've found a segment
793 return -1; //we haven't found a segment
797 int Exhaustive_count=0, Exhaustive_failed_count=0;
799 //Tries to find a segment for a point, in the following way:
800 // 1. Check the given segment
801 // 2. Recursively trace through attached segments
802 // 3. Check all the segmentns
803 //Returns segnum if found, or -1
804 int find_point_seg(vms_vector *p,int segnum)
808 //allow segnum==-1, meaning we have no idea what segment point is in
809 Assert((segnum <= Highest_segment_index) && (segnum >= -1));
812 newseg = trace_segs(p, segnum, 0);
814 if (newseg != -1) //we found a segment!
818 //couldn't find via attached segs, so search all segs
821 // This Doing_lighting_hack_flag thing added by mk because the hundreds of scrolling messages were
822 // slowing down lighting, and in about 98% of cases, it would just return -1 anyway.
823 // Matt: This really should be fixed, though. We're probably screwing up our lighting in a few places.
824 if (!Doing_lighting_hack_flag) {
825 mprintf((1,"Warning: doing exhaustive search to find point segment (%i times)\n", ++Exhaustive_count));
827 for (newseg=0;newseg <= Highest_segment_index;newseg++)
828 if (get_seg_masks(p, newseg, 0, __FILE__, __LINE__).centermask == 0)
831 mprintf((1,"Warning: could not find point segment (%i times)\n", ++Exhaustive_failed_count));
833 return -1; //no segment found
839 //--repair-- // ------------------------------------------------------------------------------
840 //--repair-- void clsd_repair_center(int segnum)
842 //--repair-- int sidenum;
844 //--repair-- // --- Set repair center bit for all repair center segments.
845 //--repair-- if (Segments[segnum].special == SEGMENT_IS_REPAIRCEN) {
846 //--repair-- Lsegments[segnum].special_type |= SS_REPAIR_CENTER;
847 //--repair-- Lsegments[segnum].special_segment = segnum;
850 //--repair-- // --- Set repair center bit for all segments adjacent to a repair center.
851 //--repair-- for (sidenum=0; sidenum < MAX_SIDES_PER_SEGMENT; sidenum++) {
852 //--repair-- int s = Segments[segnum].children[sidenum];
854 //--repair-- if ( (s != -1) && (Segments[s].special==SEGMENT_IS_REPAIRCEN) ) {
855 //--repair-- Lsegments[segnum].special_type |= SS_REPAIR_CENTER;
856 //--repair-- Lsegments[segnum].special_segment = s;
861 //--repair-- // ------------------------------------------------------------------------------
862 //--repair-- // --- Set destination points for all Materialization centers.
863 //--repair-- void clsd_materialization_center(int segnum)
865 //--repair-- if (Segments[segnum].special == SEGMENT_IS_ROBOTMAKER) {
870 //--repair-- int Lsegment_highest_segment_index, Lsegment_highest_vertex_index;
872 //--repair-- // ------------------------------------------------------------------------------
873 //--repair-- // Create data specific to mine which doesn't get written to disk.
874 //--repair-- // Highest_segment_index and Highest_object_index must be valid.
875 //--repair-- // 07/21: set repair center bit
876 //--repair-- void create_local_segment_data(void)
878 //--repair-- int segnum;
880 //--repair-- // --- Initialize all Lsegments.
881 //--repair-- for (segnum=0; segnum <= Highest_segment_index; segnum++) {
882 //--repair-- Lsegments[segnum].special_type = 0;
883 //--repair-- Lsegments[segnum].special_segment = -1;
886 //--repair-- for (segnum=0; segnum <= Highest_segment_index; segnum++) {
888 //--repair-- clsd_repair_center(segnum);
889 //--repair-- clsd_materialization_center(segnum);
893 //--repair-- // Set check variables.
894 //--repair-- // In main game loop, make sure these are valid, else Lsegments is not valid.
895 //--repair-- Lsegment_highest_segment_index = Highest_segment_index;
896 //--repair-- Lsegment_highest_vertex_index = Highest_vertex_index;
899 //--repair-- // ------------------------------------------------------------------------------------------
900 //--repair-- // Sort of makes sure create_local_segment_data has been called for the currently executing mine.
901 //--repair-- // It is not failsafe, as you will see if you look at the code.
902 //--repair-- // Returns 1 if Lsegments appears valid, 0 if not.
903 //--repair-- int check_lsegments_validity(void)
905 //--repair-- return ((Lsegment_highest_segment_index == Highest_segment_index) && (Lsegment_highest_vertex_index == Highest_vertex_index));
908 #define MAX_LOC_POINT_SEGS 64
910 int Connected_segment_distance;
912 #define MIN_CACHE_FCD_DIST (F1_0*80) // Must be this far apart for cache lookup to succeed. Recognizes small changes in distance matter at small distances.
913 #define MAX_FCD_CACHE 8
921 fcd_data Fcd_cache[MAX_FCD_CACHE];
922 fix Last_fcd_flush_time;
924 // ----------------------------------------------------------------------------------------------------------
925 void flush_fcd_cache(void)
931 for (i=0; i<MAX_FCD_CACHE; i++)
932 Fcd_cache[i].seg0 = -1;
935 // ----------------------------------------------------------------------------------------------------------
936 void add_to_fcd_cache(int seg0, int seg1, int depth, fix dist)
938 if (dist > MIN_CACHE_FCD_DIST) {
939 Fcd_cache[Fcd_index].seg0 = seg0;
940 Fcd_cache[Fcd_index].seg1 = seg1;
941 Fcd_cache[Fcd_index].csd = depth;
942 Fcd_cache[Fcd_index].dist = dist;
946 if (Fcd_index >= MAX_FCD_CACHE)
949 // -- mprintf((0, "Adding seg0=%i, seg1=%i to cache.\n", seg0, seg1));
951 // If it's in the cache, remove it.
954 for (i=0; i<MAX_FCD_CACHE; i++)
955 if (Fcd_cache[i].seg0 == seg0)
956 if (Fcd_cache[i].seg1 == seg1) {
957 Fcd_cache[Fcd_index].seg0 = -1;
964 // ----------------------------------------------------------------------------------------------------------
965 // Determine whether seg0 and seg1 are reachable in a way that allows sound to pass.
966 // Search up to a maximum depth of max_depth.
967 // Return the distance.
968 fix find_connected_distance(vms_vector *p0, int seg0, vms_vector *p1, int seg1, int max_depth, int wid_flag)
972 int qtail = 0, qhead = 0;
974 sbyte visited[MAX_SEGMENTS];
975 seg_seg seg_queue[MAX_SEGMENTS];
976 short depth[MAX_SEGMENTS];
979 point_seg point_segs[MAX_LOC_POINT_SEGS];
982 // If > this, will overrun point_segs buffer
984 if (max_depth == -1) max_depth = 200;
987 if (max_depth > MAX_LOC_POINT_SEGS-2) {
988 mprintf((1, "Warning: In find_connected_distance, max_depth = %i, limited to %i\n", max_depth, MAX_LOC_POINT_SEGS-2));
989 max_depth = MAX_LOC_POINT_SEGS-2;
993 Connected_segment_distance = 0;
994 return vm_vec_dist_quick(p0, p1);
997 if ((conn_side = find_connect_side(&Segments[seg0], &Segments[seg1])) != -1) {
998 if (WALL_IS_DOORWAY(&Segments[seg1], conn_side) & wid_flag) {
999 Connected_segment_distance = 1;
1000 //mprintf((0, "\n"));
1001 return vm_vec_dist_quick(p0, p1);
1006 // Periodically flush cache.
1007 if ((GameTime - Last_fcd_flush_time > F1_0*2) || (GameTime < Last_fcd_flush_time)) {
1009 Last_fcd_flush_time = GameTime;
1012 // Can't quickly get distance, so see if in Fcd_cache.
1013 for (i=0; i<MAX_FCD_CACHE; i++)
1014 if ((Fcd_cache[i].seg0 == seg0) && (Fcd_cache[i].seg1 == seg1)) {
1015 Connected_segment_distance = Fcd_cache[i].csd;
1016 // -- mprintf((0, "In cache, seg0=%i, seg1=%i. Returning.\n", seg0, seg1));
1017 return Fcd_cache[i].dist;
1022 memset(visited, 0, Highest_segment_index+1);
1023 memset(depth, 0, sizeof(depth[0]) * (Highest_segment_index+1));
1026 visited[cur_seg] = 1;
1029 while (cur_seg != seg1) {
1030 segment *segp = &Segments[cur_seg];
1032 for (sidenum = 0; sidenum < MAX_SIDES_PER_SEGMENT; sidenum++) {
1036 if (WALL_IS_DOORWAY(segp, snum) & wid_flag) {
1037 int this_seg = segp->children[snum];
1039 if (!visited[this_seg]) {
1040 seg_queue[qtail].start = cur_seg;
1041 seg_queue[qtail].end = this_seg;
1042 visited[this_seg] = 1;
1043 depth[qtail++] = cur_depth+1;
1044 if (max_depth != -1) {
1045 if (depth[qtail-1] == max_depth) {
1046 Connected_segment_distance = 1000;
1047 add_to_fcd_cache(seg0, seg1, Connected_segment_distance, F1_0*1000);
1050 } else if (this_seg == seg1) {
1056 } // for (sidenum...
1058 if (qhead >= qtail) {
1059 Connected_segment_distance = 1000;
1060 add_to_fcd_cache(seg0, seg1, Connected_segment_distance, F1_0*1000);
1064 cur_seg = seg_queue[qhead].end;
1065 cur_depth = depth[qhead];
1069 } // while (cur_seg ...
1071 // Set qtail to the segment which ends at the goal.
1072 while (seg_queue[--qtail].end != seg1)
1074 Connected_segment_distance = 1000;
1075 add_to_fcd_cache(seg0, seg1, Connected_segment_distance, F1_0*1000);
1079 while (qtail >= 0) {
1080 int parent_seg, this_seg;
1082 this_seg = seg_queue[qtail].end;
1083 parent_seg = seg_queue[qtail].start;
1084 point_segs[num_points].segnum = this_seg;
1085 compute_segment_center(&point_segs[num_points].point,&Segments[this_seg]);
1088 if (parent_seg == seg0)
1091 while (seg_queue[--qtail].end != parent_seg)
1095 point_segs[num_points].segnum = seg0;
1096 compute_segment_center(&point_segs[num_points].point,&Segments[seg0]);
1099 if (num_points == 1) {
1100 Connected_segment_distance = num_points;
1101 return vm_vec_dist_quick(p0, p1);
1103 dist = vm_vec_dist_quick(p1, &point_segs[1].point);
1104 dist += vm_vec_dist_quick(p0, &point_segs[num_points-2].point);
1106 for (i=1; i<num_points-2; i++) {
1108 ndist = vm_vec_dist_quick(&point_segs[i].point, &point_segs[i+1].point);
1114 Connected_segment_distance = num_points;
1115 add_to_fcd_cache(seg0, seg1, num_points, dist);
1121 sbyte convert_to_byte(fix f)
1123 if (f >= 0x00010000)
1125 else if (f <= -0x00010000)
1128 return f >> MATRIX_PRECISION;
1131 #define VEL_PRECISION 12
1133 // Create a shortpos struct from an object.
1134 // Extract the matrix into byte values.
1135 // Create a position relative to vertex 0 with 1/256 normal "fix" precision.
1136 // Stuff segment in a short.
1137 void create_shortpos(shortpos *spp, object *objp, int swap_bytes)
1144 *sp++ = convert_to_byte(objp->orient.rvec.x);
1145 *sp++ = convert_to_byte(objp->orient.uvec.x);
1146 *sp++ = convert_to_byte(objp->orient.fvec.x);
1147 *sp++ = convert_to_byte(objp->orient.rvec.y);
1148 *sp++ = convert_to_byte(objp->orient.uvec.y);
1149 *sp++ = convert_to_byte(objp->orient.fvec.y);
1150 *sp++ = convert_to_byte(objp->orient.rvec.z);
1151 *sp++ = convert_to_byte(objp->orient.uvec.z);
1152 *sp++ = convert_to_byte(objp->orient.fvec.z);
1154 spp->xo = (objp->pos.x - Vertices[Segments[objp->segnum].verts[0]].x) >> RELPOS_PRECISION;
1155 spp->yo = (objp->pos.y - Vertices[Segments[objp->segnum].verts[0]].y) >> RELPOS_PRECISION;
1156 spp->zo = (objp->pos.z - Vertices[Segments[objp->segnum].verts[0]].z) >> RELPOS_PRECISION;
1158 spp->segment = objp->segnum;
1160 spp->velx = (objp->mtype.phys_info.velocity.x) >> VEL_PRECISION;
1161 spp->vely = (objp->mtype.phys_info.velocity.y) >> VEL_PRECISION;
1162 spp->velz = (objp->mtype.phys_info.velocity.z) >> VEL_PRECISION;
1164 // swap the short values for the big-endian machines.
1167 spp->xo = INTEL_SHORT(spp->xo);
1168 spp->yo = INTEL_SHORT(spp->yo);
1169 spp->zo = INTEL_SHORT(spp->zo);
1170 spp->segment = INTEL_SHORT(spp->segment);
1171 spp->velx = INTEL_SHORT(spp->velx);
1172 spp->vely = INTEL_SHORT(spp->vely);
1173 spp->velz = INTEL_SHORT(spp->velz);
1175 // mprintf((0, "Matrix: %08x %08x %08x %08x %08x %08x\n", objp->orient.m1,objp->orient.m2,objp->orient.m3,
1176 // spp->bytemat[0] << MATRIX_PRECISION,spp->bytemat[1] << MATRIX_PRECISION,spp->bytemat[2] << MATRIX_PRECISION));
1178 // mprintf((0, " %08x %08x %08x %08x %08x %08x\n", objp->orient.m4,objp->orient.m5,objp->orient.m6,
1179 // spp->bytemat[3] << MATRIX_PRECISION,spp->bytemat[4] << MATRIX_PRECISION,spp->bytemat[5] << MATRIX_PRECISION));
1181 // mprintf((0, " %08x %08x %08x %08x %08x %08x\n", objp->orient.m7,objp->orient.m8,objp->orient.m9,
1182 // spp->bytemat[6] << MATRIX_PRECISION,spp->bytemat[7] << MATRIX_PRECISION,spp->bytemat[8] << MATRIX_PRECISION));
1184 // mprintf((0, "Positn: %08x %08x %08x %08x %08x %08x\n", objp->pos.x, objp->pos.y, objp->pos.z,
1185 // (spp->xo << RELPOS_PRECISION) + Vertices[Segments[segnum].verts[0]].x,
1186 // (spp->yo << RELPOS_PRECISION) + Vertices[Segments[segnum].verts[0]].y,
1187 // (spp->zo << RELPOS_PRECISION) + Vertices[Segments[segnum].verts[0]].z));
1188 // mprintf((0, "Segment: %3i %3i\n", objp->segnum, spp->segment));
1192 void extract_shortpos(object *objp, shortpos *spp, int swap_bytes)
1199 objp->orient.rvec.x = *sp++ << MATRIX_PRECISION;
1200 objp->orient.uvec.x = *sp++ << MATRIX_PRECISION;
1201 objp->orient.fvec.x = *sp++ << MATRIX_PRECISION;
1202 objp->orient.rvec.y = *sp++ << MATRIX_PRECISION;
1203 objp->orient.uvec.y = *sp++ << MATRIX_PRECISION;
1204 objp->orient.fvec.y = *sp++ << MATRIX_PRECISION;
1205 objp->orient.rvec.z = *sp++ << MATRIX_PRECISION;
1206 objp->orient.uvec.z = *sp++ << MATRIX_PRECISION;
1207 objp->orient.fvec.z = *sp++ << MATRIX_PRECISION;
1210 spp->xo = INTEL_SHORT(spp->xo);
1211 spp->yo = INTEL_SHORT(spp->yo);
1212 spp->zo = INTEL_SHORT(spp->zo);
1213 spp->segment = INTEL_SHORT(spp->segment);
1214 spp->velx = INTEL_SHORT(spp->velx);
1215 spp->vely = INTEL_SHORT(spp->vely);
1216 spp->velz = INTEL_SHORT(spp->velz);
1219 segnum = spp->segment;
1221 Assert((segnum >= 0) && (segnum <= Highest_segment_index));
1223 objp->pos.x = (spp->xo << RELPOS_PRECISION) + Vertices[Segments[segnum].verts[0]].x;
1224 objp->pos.y = (spp->yo << RELPOS_PRECISION) + Vertices[Segments[segnum].verts[0]].y;
1225 objp->pos.z = (spp->zo << RELPOS_PRECISION) + Vertices[Segments[segnum].verts[0]].z;
1227 objp->mtype.phys_info.velocity.x = (spp->velx << VEL_PRECISION);
1228 objp->mtype.phys_info.velocity.y = (spp->vely << VEL_PRECISION);
1229 objp->mtype.phys_info.velocity.z = (spp->velz << VEL_PRECISION);
1231 obj_relink(OBJECT_NUMBER(objp), segnum);
1233 // mprintf((0, "Matrix: %08x %08x %08x %08x %08x %08x\n", objp->orient.m1,objp->orient.m2,objp->orient.m3,
1234 // spp->bytemat[0],spp->bytemat[1],spp->bytemat[2]));
1236 // mprintf((0, " %08x %08x %08x %08x %08x %08x\n", objp->orient.m4,objp->orient.m5,objp->orient.m6,
1237 // spp->bytemat[3],spp->bytemat[4],spp->bytemat[5]));
1239 // mprintf((0, " %08x %08x %08x %08x %08x %08x\n", objp->orient.m7,objp->orient.m8,objp->orient.m9,
1240 // spp->bytemat[6],spp->bytemat[7],spp->bytemat[8]));
1242 // mprintf((0, "Positn: %08x %08x %08x %08x %08x %08x\n", objp->pos.x, objp->pos.y, objp->pos.z,
1243 // (spp->xo << RELPOS_PRECISION) + Vertices[Segments[segnum].verts[0]].x, (spp->yo << RELPOS_PRECISION) + Vertices[Segments[segnum].verts[0]].y, (spp->zo << RELPOS_PRECISION) + Vertices[Segments[segnum].verts[0]].z));
1244 // mprintf((0, "Segment: %3i %3i\n", objp->segnum, spp->segment));
1248 //--unused-- void test_shortpos(void)
1250 //--unused-- shortpos spp;
1252 //--unused-- create_shortpos(&spp, &Objects[0]);
1253 //--unused-- extract_shortpos(&Objects[0], &spp);
1257 // -----------------------------------------------------------------------------
1258 // Segment validation functions.
1259 // Moved from editor to game so we can compute surface normals at load time.
1260 // -------------------------------------------------------------------------------
1262 // ------------------------------------------------------------------------------------------
1263 // Extract a vector from a segment. The vector goes from the start face to the end face.
1264 // The point on each face is the average of the four points forming the face.
1265 void extract_vector_from_segment(segment *sp, vms_vector *vp, int start, int end)
1273 for (i=0; i<4; i++) {
1274 vm_vec_add2(&vs,&Vertices[sp->verts[Side_to_verts[start][i]]]);
1275 vm_vec_add2(&ve,&Vertices[sp->verts[Side_to_verts[end][i]]]);
1278 vm_vec_sub(vp,&ve,&vs);
1279 vm_vec_scale(vp,F1_0/4);
1283 //create a matrix that describes the orientation of the given segment
1284 void extract_orient_from_segment(vms_matrix *m,segment *seg)
1286 vms_vector fvec,uvec;
1288 extract_vector_from_segment(seg,&fvec,WFRONT,WBACK);
1289 extract_vector_from_segment(seg,&uvec,WBOTTOM,WTOP);
1291 //vector to matrix does normalizations and orthogonalizations
1292 vm_vector_2_matrix(m,&fvec,&uvec,NULL);
1296 // ------------------------------------------------------------------------------------------
1297 // Extract the forward vector from segment *sp, return in *vp.
1298 // The forward vector is defined to be the vector from the the center of the front face of the segment
1299 // to the center of the back face of the segment.
1300 void extract_forward_vector_from_segment(segment *sp,vms_vector *vp)
1302 extract_vector_from_segment(sp,vp,WFRONT,WBACK);
1305 // ------------------------------------------------------------------------------------------
1306 // Extract the right vector from segment *sp, return in *vp.
1307 // The forward vector is defined to be the vector from the the center of the left face of the segment
1308 // to the center of the right face of the segment.
1309 void extract_right_vector_from_segment(segment *sp,vms_vector *vp)
1311 extract_vector_from_segment(sp,vp,WLEFT,WRIGHT);
1314 // ------------------------------------------------------------------------------------------
1315 // Extract the up vector from segment *sp, return in *vp.
1316 // The forward vector is defined to be the vector from the the center of the bottom face of the segment
1317 // to the center of the top face of the segment.
1318 void extract_up_vector_from_segment(segment *sp,vms_vector *vp)
1320 extract_vector_from_segment(sp,vp,WBOTTOM,WTOP);
1324 void add_side_as_quad(segment *sp, int sidenum, vms_vector *normal)
1326 side *sidep = &sp->sides[sidenum];
1328 sidep->type = SIDE_IS_QUAD;
1331 normal = normal; //avoid compiler warning
1333 sidep->normals[0] = *normal;
1334 sidep->normals[1] = *normal;
1337 // If there is a connection here, we only formed the faces for the purpose of determining segment boundaries,
1338 // so don't generate polys, else they will get rendered.
1339 // if (sp->children[sidenum] != -1)
1340 // sidep->render_flag = 0;
1342 // sidep->render_flag = 1;
1347 // -------------------------------------------------------------------------------
1348 // Return v0, v1, v2 = 3 vertices with smallest numbers. If *negate_flag set, then negate normal after computation.
1349 // Note, you cannot just compute the normal by treating the points in the opposite direction as this introduces
1350 // small differences between normals which should merely be opposites of each other.
1351 void get_verts_for_normal(int va, int vb, int vc, int vd, int *v0, int *v1, int *v2, int *v3, int *negate_flag)
1356 // w is a list that shows how things got scrambled so we know if our normal is pointing backwards
1369 t = v[j]; v[j] = v[i]; v[i] = t;
1370 t = w[j]; w[j] = w[i]; w[i] = t;
1373 Assert((v[0] < v[1]) && (v[1] < v[2]) && (v[2] < v[3]));
1375 // Now, if for any w[i] & w[i+1]: w[i+1] = (w[i]+3)%4, then must swap
1381 if ( (((w[0]+3) % 4) == w[1]) || (((w[1]+3) % 4) == w[2]))
1388 // -------------------------------------------------------------------------------
1389 void add_side_as_2_triangles(segment *sp, int sidenum)
1392 sbyte *vs = Side_to_verts[sidenum];
1394 vms_vector vec_13; // vector from vertex 1 to vertex 3
1396 side *sidep = &sp->sides[sidenum];
1398 // Choose how to triangulate.
1400 // Always triangulate so segment is convex.
1401 // Use Matt's formula: Na . AD > 0, where ABCD are vertices on side, a is face formed by A,B,C, Na is normal from face a.
1402 // If not a wall, then triangulate so whatever is on the other side is triangulated the same (ie, between the same absoluate vertices)
1403 if (!IS_CHILD(sp->children[sidenum])) {
1404 vm_vec_normal(&norm, &Vertices[sp->verts[vs[0]]], &Vertices[sp->verts[vs[1]]], &Vertices[sp->verts[vs[2]]]);
1405 vm_vec_sub(&vec_13, &Vertices[sp->verts[vs[3]]], &Vertices[sp->verts[vs[1]]]);
1406 dot = vm_vec_dot(&norm, &vec_13);
1408 // Now, signifiy whether to triangulate from 0:2 or 1:3
1410 sidep->type = SIDE_IS_TRI_02;
1412 sidep->type = SIDE_IS_TRI_13;
1414 #ifndef COMPACT_SEGS
1415 // Now, based on triangulation type, set the normals.
1416 if (sidep->type == SIDE_IS_TRI_02) {
1417 vm_vec_normal(&norm, &Vertices[sp->verts[vs[0]]], &Vertices[sp->verts[vs[1]]], &Vertices[sp->verts[vs[2]]]);
1418 sidep->normals[0] = norm;
1419 vm_vec_normal(&norm, &Vertices[sp->verts[vs[0]]], &Vertices[sp->verts[vs[2]]], &Vertices[sp->verts[vs[3]]]);
1420 sidep->normals[1] = norm;
1422 vm_vec_normal(&norm, &Vertices[sp->verts[vs[0]]], &Vertices[sp->verts[vs[1]]], &Vertices[sp->verts[vs[3]]]);
1423 sidep->normals[0] = norm;
1424 vm_vec_normal(&norm, &Vertices[sp->verts[vs[1]]], &Vertices[sp->verts[vs[2]]], &Vertices[sp->verts[vs[3]]]);
1425 sidep->normals[1] = norm;
1429 int i,v[4], vsorted[4];
1433 v[i] = sp->verts[vs[i]];
1435 get_verts_for_normal(v[0], v[1], v[2], v[3], &vsorted[0], &vsorted[1], &vsorted[2], &vsorted[3], &negate_flag);
1437 if ((vsorted[0] == v[0]) || (vsorted[0] == v[2])) {
1438 sidep->type = SIDE_IS_TRI_02;
1439 #ifndef COMPACT_SEGS
1440 // Now, get vertices for normal for each triangle based on triangulation type.
1441 get_verts_for_normal(v[0], v[1], v[2], 32767, &vsorted[0], &vsorted[1], &vsorted[2], &vsorted[3], &negate_flag);
1442 vm_vec_normal(&norm, &Vertices[vsorted[0]], &Vertices[vsorted[1]], &Vertices[vsorted[2]]);
1444 vm_vec_negate(&norm);
1445 sidep->normals[0] = norm;
1447 get_verts_for_normal(v[0], v[2], v[3], 32767, &vsorted[0], &vsorted[1], &vsorted[2], &vsorted[3], &negate_flag);
1448 vm_vec_normal(&norm, &Vertices[vsorted[0]], &Vertices[vsorted[1]], &Vertices[vsorted[2]]);
1450 vm_vec_negate(&norm);
1451 sidep->normals[1] = norm;
1454 sidep->type = SIDE_IS_TRI_13;
1455 #ifndef COMPACT_SEGS
1456 // Now, get vertices for normal for each triangle based on triangulation type.
1457 get_verts_for_normal(v[0], v[1], v[3], 32767, &vsorted[0], &vsorted[1], &vsorted[2], &vsorted[3], &negate_flag);
1458 vm_vec_normal(&norm, &Vertices[vsorted[0]], &Vertices[vsorted[1]], &Vertices[vsorted[2]]);
1460 vm_vec_negate(&norm);
1461 sidep->normals[0] = norm;
1463 get_verts_for_normal(v[1], v[2], v[3], 32767, &vsorted[0], &vsorted[1], &vsorted[2], &vsorted[3], &negate_flag);
1464 vm_vec_normal(&norm, &Vertices[vsorted[0]], &Vertices[vsorted[1]], &Vertices[vsorted[2]]);
1466 vm_vec_negate(&norm);
1467 sidep->normals[1] = norm;
1476 if (v > PLANE_DIST_TOLERANCE)
1478 else if (v < -(PLANE_DIST_TOLERANCE+1)) //neg & pos round differently
1484 // -------------------------------------------------------------------------------
1485 void create_walls_on_side(segment *sp, int sidenum)
1487 int vm0, vm1, vm2, vm3, negate_flag;
1492 v0 = sp->verts[Side_to_verts[sidenum][0]];
1493 v1 = sp->verts[Side_to_verts[sidenum][1]];
1494 v2 = sp->verts[Side_to_verts[sidenum][2]];
1495 v3 = sp->verts[Side_to_verts[sidenum][3]];
1497 get_verts_for_normal(v0, v1, v2, v3, &vm0, &vm1, &vm2, &vm3, &negate_flag);
1499 vm_vec_normal(&vn, &Vertices[vm0], &Vertices[vm1], &Vertices[vm2]);
1500 dist_to_plane = abs(vm_dist_to_plane(&Vertices[vm3], &vn, &Vertices[vm0]));
1502 //if ((SEGMENT_NUMBER(sp) == 0x7b) && (sidenum == 3)) {
1503 // mprintf((0, "Verts = %3i %3i %3i %3i, negate flag = %3i, dist = %8x\n", vm0, vm1, vm2, vm3, negate_flag, dist_to_plane));
1504 // mprintf((0, " Normal = %8x %8x %8x\n", vn.x, vn.y, vn.z));
1505 // mprintf((0, " Vert %3i = [%8x %8x %8x]\n", vm0, Vertices[vm0].x, Vertices[vm0].y, Vertices[vm0].z));
1506 // mprintf((0, " Vert %3i = [%8x %8x %8x]\n", vm1, Vertices[vm1].x, Vertices[vm1].y, Vertices[vm1].z));
1507 // mprintf((0, " Vert %3i = [%8x %8x %8x]\n", vm2, Vertices[vm2].x, Vertices[vm2].y, Vertices[vm2].z));
1508 // mprintf((0, " Vert %3i = [%8x %8x %8x]\n", vm3, Vertices[vm3].x, Vertices[vm3].y, Vertices[vm3].z));
1511 //if ((SEGMENT_NUMBER(sp) == 0x86) && (sidenum == 5)) {
1512 // mprintf((0, "Verts = %3i %3i %3i %3i, negate flag = %3i, dist = %8x\n", vm0, vm1, vm2, vm3, negate_flag, dist_to_plane));
1513 // mprintf((0, " Normal = %8x %8x %8x\n", vn.x, vn.y, vn.z));
1514 // mprintf((0, " Vert %3i = [%8x %8x %8x]\n", vm0, Vertices[vm0].x, Vertices[vm0].y, Vertices[vm0].z));
1515 // mprintf((0, " Vert %3i = [%8x %8x %8x]\n", vm1, Vertices[vm1].x, Vertices[vm1].y, Vertices[vm1].z));
1516 // mprintf((0, " Vert %3i = [%8x %8x %8x]\n", vm2, Vertices[vm2].x, Vertices[vm2].y, Vertices[vm2].z));
1517 // mprintf((0, " Vert %3i = [%8x %8x %8x]\n", vm3, Vertices[vm3].x, Vertices[vm3].y, Vertices[vm3].z));
1523 if (dist_to_plane <= PLANE_DIST_TOLERANCE)
1524 add_side_as_quad(sp, sidenum, &vn);
1526 add_side_as_2_triangles(sp, sidenum);
1528 //this code checks to see if we really should be triangulated, and
1529 //de-triangulates if we shouldn't be.
1539 create_abs_vertex_lists(&num_faces, vertex_list, SEGMENT_NUMBER(sp), sidenum, __FILE__, __LINE__);
1541 Assert(num_faces == 2);
1543 s = &sp->sides[sidenum];
1545 vertnum = min(vertex_list[0],vertex_list[2]);
1549 vms_vector normals[2];
1550 get_side_normals(sp, sidenum, &normals[0], &normals[1] );
1551 dist0 = vm_dist_to_plane(&Vertices[vertex_list[1]],&normals[1],&Vertices[vertnum]);
1552 dist1 = vm_dist_to_plane(&Vertices[vertex_list[4]],&normals[0],&Vertices[vertnum]);
1555 dist0 = vm_dist_to_plane(&Vertices[vertex_list[1]],&s->normals[1],&Vertices[vertnum]);
1556 dist1 = vm_dist_to_plane(&Vertices[vertex_list[4]],&s->normals[0],&Vertices[vertnum]);
1562 if (s0==0 || s1==0 || s0!=s1) {
1563 sp->sides[sidenum].type = SIDE_IS_QUAD; //detriangulate!
1564 #ifndef COMPACT_SEGS
1565 sp->sides[sidenum].normals[0] = vn;
1566 sp->sides[sidenum].normals[1] = vn;
1578 //#define CACHE_DEBUG 1
1579 #define MAX_CACHE_NORMALS 128
1580 #define CACHE_MASK 127
1582 typedef struct ncache_element {
1585 vms_vector normals[2];
1588 int ncache_initialized = 0;
1589 ncache_element ncache[MAX_CACHE_NORMALS];
1592 int ncache_counter = 0;
1593 int ncache_hits = 0;
1594 int ncache_misses = 0;
1600 ncache_initialized = 1;
1606 for (i=0; i<MAX_CACHE_NORMALS; i++ ) {
1607 ncache[i].segnum = -1;
1613 // -------------------------------------------------------------------------------
1614 int find_ncache_element( int segnum, int sidenum, int face_flags )
1618 if (!ncache_initialized) ncache_init();
1621 if (((++ncache_counter % 5000)==1) && (ncache_hits+ncache_misses > 0))
1622 mprintf(( 0, "NCACHE %d%% missed, H:%d, M:%d\n", (ncache_misses*100)/(ncache_hits+ncache_misses), ncache_hits, ncache_misses ));
1625 i = ((segnum<<2) ^ sidenum) & CACHE_MASK;
1627 if ((ncache[i].segnum == segnum) && ((ncache[i].sidenum&0xf)==sidenum) ) {
1632 f1 = ncache[i].sidenum>>4;
1633 if ( (f1&face_flags)==face_flags )
1636 uncached_get_side_normal( &Segments[segnum], sidenum, 1, &ncache[i].normals[1] );
1638 uncached_get_side_normal( &Segments[segnum], sidenum, 0, &ncache[i].normals[0] );
1639 ncache[i].sidenum |= face_flags<<4;
1646 switch( face_flags ) {
1648 uncached_get_side_normal( &Segments[segnum], sidenum, 0, &ncache[i].normals[0] );
1651 uncached_get_side_normal( &Segments[segnum], sidenum, 1, &ncache[i].normals[1] );
1654 uncached_get_side_normals(&Segments[segnum], sidenum, &ncache[i].normals[0], &ncache[i].normals[1] );
1657 ncache[i].segnum = segnum;
1658 ncache[i].sidenum = sidenum | (face_flags<<4);
1662 void get_side_normal(segment *sp, int sidenum, int face_num, vms_vector * vm )
1665 i = find_ncache_element( SEGMENT_NUMBER(sp), sidenum, 1 << face_num );
1666 *vm = ncache[i].normals[face_num];
1669 uncached_get_side_normal(sp, sidenum, face_num, &tmp );
1670 Assert( tmp.x == vm->x );
1671 Assert( tmp.y == vm->y );
1672 Assert( tmp.z == vm->z );
1676 void get_side_normals(segment *sp, int sidenum, vms_vector * vm1, vms_vector * vm2 )
1679 i = find_ncache_element( SEGMENT_NUMBER(sp), sidenum, 3 );
1680 *vm1 = ncache[i].normals[0];
1681 *vm2 = ncache[i].normals[1];
1685 uncached_get_side_normal(sp, sidenum, 0, &tmp );
1686 Assert( tmp.x == vm1->x );
1687 Assert( tmp.y == vm1->y );
1688 Assert( tmp.z == vm1->z );
1689 uncached_get_side_normal(sp, sidenum, 1, &tmp );
1690 Assert( tmp.x == vm2->x );
1691 Assert( tmp.y == vm2->y );
1692 Assert( tmp.z == vm2->z );
1697 void uncached_get_side_normal(segment *sp, int sidenum, int face_num, vms_vector * vm )
1699 int vm0, vm1, vm2, vm3, negate_flag;
1700 char *vs = Side_to_verts[sidenum];
1702 switch( sp->sides[sidenum].type ) {
1704 get_verts_for_normal(sp->verts[vs[0]], sp->verts[vs[1]], sp->verts[vs[2]], sp->verts[vs[3]], &vm0, &vm1, &vm2, &vm3, &negate_flag);
1705 vm_vec_normal(vm, &Vertices[vm0], &Vertices[vm1], &Vertices[vm2]);
1709 case SIDE_IS_TRI_02:
1710 if ( face_num == 0 )
1711 vm_vec_normal(vm, &Vertices[sp->verts[vs[0]]], &Vertices[sp->verts[vs[1]]], &Vertices[sp->verts[vs[2]]]);
1713 vm_vec_normal(vm, &Vertices[sp->verts[vs[0]]], &Vertices[sp->verts[vs[2]]], &Vertices[sp->verts[vs[3]]]);
1715 case SIDE_IS_TRI_13:
1716 if ( face_num == 0 )
1717 vm_vec_normal(vm, &Vertices[sp->verts[vs[0]]], &Vertices[sp->verts[vs[1]]], &Vertices[sp->verts[vs[3]]]);
1719 vm_vec_normal(vm, &Vertices[sp->verts[vs[1]]], &Vertices[sp->verts[vs[2]]], &Vertices[sp->verts[vs[3]]]);
1724 void uncached_get_side_normals(segment *sp, int sidenum, vms_vector * vm1, vms_vector * vm2 )
1726 int vvm0, vvm1, vvm2, vvm3, negate_flag;
1727 char *vs = Side_to_verts[sidenum];
1729 switch( sp->sides[sidenum].type ) {
1731 get_verts_for_normal(sp->verts[vs[0]], sp->verts[vs[1]], sp->verts[vs[2]], sp->verts[vs[3]], &vvm0, &vvm1, &vvm2, &vvm3, &negate_flag);
1732 vm_vec_normal(vm1, &Vertices[vvm0], &Vertices[vvm1], &Vertices[vvm2]);
1737 case SIDE_IS_TRI_02:
1738 vm_vec_normal(vm1, &Vertices[sp->verts[vs[0]]], &Vertices[sp->verts[vs[1]]], &Vertices[sp->verts[vs[2]]]);
1739 vm_vec_normal(vm2, &Vertices[sp->verts[vs[0]]], &Vertices[sp->verts[vs[2]]], &Vertices[sp->verts[vs[3]]]);
1741 case SIDE_IS_TRI_13:
1742 vm_vec_normal(vm1, &Vertices[sp->verts[vs[0]]], &Vertices[sp->verts[vs[1]]], &Vertices[sp->verts[vs[3]]]);
1743 vm_vec_normal(vm2, &Vertices[sp->verts[vs[1]]], &Vertices[sp->verts[vs[2]]], &Vertices[sp->verts[vs[3]]]);
1750 // -------------------------------------------------------------------------------
1751 void validate_removable_wall(segment *sp, int sidenum, int tmap_num)
1753 create_walls_on_side(sp, sidenum);
1755 sp->sides[sidenum].tmap_num = tmap_num;
1757 // assign_default_uvs_to_side(sp, sidenum);
1758 // assign_light_to_side(sp, sidenum);
1761 // -------------------------------------------------------------------------------
1762 // Make a just-modified segment side valid.
1763 void validate_segment_side(segment *sp, int sidenum)
1765 if (sp->sides[sidenum].wall_num == -1)
1766 create_walls_on_side(sp, sidenum);
1768 // create_removable_wall(sp, sidenum, sp->sides[sidenum].tmap_num);
1769 validate_removable_wall(sp, sidenum, sp->sides[sidenum].tmap_num);
1772 // If side doesn't have a child, then render wall. If it does have a child, but there is a temporary
1773 // wall there, then do render wall.
1774 // if (sp->children[sidenum] == -1)
1775 // sp->sides[sidenum].render_flag = 1;
1776 // else if (sp->sides[sidenum].wall_num != -1)
1777 // sp->sides[sidenum].render_flag = 1;
1779 // sp->sides[sidenum].render_flag = 0;
1782 extern int check_for_degenerate_segment(segment *sp);
1784 // -------------------------------------------------------------------------------
1785 // Make a just-modified segment valid.
1786 // check all sides to see how many faces they each should have (0,1,2)
1787 // create new vector normals
1788 void validate_segment(segment *sp)
1793 check_for_degenerate_segment(sp);
1796 for (side = 0; side < MAX_SIDES_PER_SEGMENT; side++)
1797 validate_segment_side(sp, side);
1799 // assign_default_uvs_to_segment(sp);
1802 // -------------------------------------------------------------------------------
1803 // Validate all segments.
1804 // Highest_segment_index must be set.
1805 // For all used segments (number <= Highest_segment_index), segnum field must be != -1.
1806 void validate_segment_all(void)
1810 for (s=0; s<=Highest_segment_index; s++)
1812 if (Segments[s].segnum != -1)
1814 validate_segment(&Segments[s]);
1819 for (s=Highest_segment_index+1; s<MAX_SEGMENTS; s++)
1820 if (Segments[s].segnum != -1) {
1822 mprintf((0, "Segment %i has invalid segnum. Bashing to -1. Silently bashing all others...", s));
1825 Segments[s].segnum = -1;
1829 mprintf((0, "%i fixed.\n", said));
1834 #ifndef COMPACT_SEGS
1835 if (check_segment_connections())
1836 Int3(); //Get Matt, si vous plait.
1842 // ------------------------------------------------------------------------------------------------------
1843 // Picks a random point in a segment like so:
1844 // From center, go up to 50% of way towards any of the 8 vertices.
1845 void pick_random_point_in_seg(vms_vector *new_pos, int segnum)
1850 compute_segment_center(new_pos, &Segments[segnum]);
1851 vnum = (d_rand() * MAX_VERTICES_PER_SEGMENT) >> 15;
1852 vm_vec_sub(&vec2, &Vertices[Segments[segnum].verts[vnum]], new_pos);
1853 vm_vec_scale(&vec2, d_rand()); // d_rand() always in 0..1/2
1854 vm_vec_add2(new_pos, &vec2);
1858 // ----------------------------------------------------------------------------------------------------------
1859 // Set the segment depth of all segments from start_seg in *segbuf.
1860 // Returns maximum depth value.
1861 int set_segment_depths(int start_seg, ubyte *segbuf)
1864 ubyte visited[MAX_SEGMENTS];
1865 int queue[MAX_SEGMENTS];
1874 for (i=0; i<=Highest_segment_index; i++)
1877 if (segbuf[start_seg] == 0)
1880 queue[tail++] = start_seg;
1881 visited[start_seg] = 1;
1882 segbuf[start_seg] = depth++;
1887 while (head < tail) {
1888 curseg = queue[head++];
1889 parent_depth = segbuf[curseg];
1891 for (i=0; i<MAX_SIDES_PER_SEGMENT; i++) {
1894 childnum = Segments[curseg].children[i];
1896 if (segbuf[childnum])
1897 if (!visited[childnum]) {
1898 visited[childnum] = 1;
1899 segbuf[childnum] = parent_depth+1;
1900 queue[tail++] = childnum;
1905 return parent_depth+1;
1908 //these constants should match the ones in seguvs
1909 #define LIGHT_DISTANCE_THRESHOLD (F1_0*80)
1910 #define Magical_light_constant (F1_0*16)
1912 #define MAX_CHANGED_SEGS 30
1913 short changed_segs[MAX_CHANGED_SEGS];
1916 // ------------------------------------------------------------------------------------------
1917 //cast static light from a segment to nearby segments
1918 void apply_light_to_segment(segment *segp,vms_vector *segment_center, fix light_intensity,int recursion_depth)
1920 vms_vector r_segment_center;
1922 int i, segnum = SEGMENT_NUMBER(segp), sidenum;
1924 for (i=0;i<n_changed_segs;i++)
1925 if (changed_segs[i] == segnum)
1928 if (i == n_changed_segs) {
1929 compute_segment_center(&r_segment_center, segp);
1930 dist_to_rseg = vm_vec_dist_quick(&r_segment_center, segment_center);
1932 if (dist_to_rseg <= LIGHT_DISTANCE_THRESHOLD) {
1934 if (dist_to_rseg > F1_0)
1935 light_at_point = fixdiv(Magical_light_constant, dist_to_rseg);
1937 light_at_point = Magical_light_constant;
1939 if (light_at_point >= 0) {
1940 segment2 *seg2p = &Segment2s[segnum];
1941 light_at_point = fixmul(light_at_point, light_intensity);
1942 #if 0 // don't see the point, static_light can be greater than F1_0
1943 if (light_at_point >= F1_0)
1944 light_at_point = F1_0-1;
1945 if (light_at_point <= -F1_0)
1946 light_at_point = -(F1_0-1);
1948 seg2p->static_light += light_at_point;
1949 if (seg2p->static_light < 0) // if it went negative, saturate
1950 seg2p->static_light = 0;
1951 } // end if (light_at_point...
1952 } // end if (dist_to_rseg...
1954 changed_segs[n_changed_segs++] = segnum;
1957 if (recursion_depth < 2)
1958 for (sidenum=0; sidenum<6; sidenum++) {
1959 if (WALL_IS_DOORWAY(segp,sidenum) & WID_RENDPAST_FLAG)
1960 apply_light_to_segment(&Segments[segp->children[sidenum]],segment_center,light_intensity,recursion_depth+1);
1966 extern object *old_viewer;
1968 //update the static_light field in a segment, which is used for object lighting
1969 //this code is copied from the editor routine calim_process_all_lights()
1970 void change_segment_light(int segnum,int sidenum,int dir)
1972 segment *segp = &Segments[segnum];
1974 if (WALL_IS_DOORWAY(segp, sidenum) & WID_RENDER_FLAG) {
1975 side *sidep = &segp->sides[sidenum];
1976 fix light_intensity;
1978 light_intensity = TmapInfo[sidep->tmap_num].lighting + TmapInfo[sidep->tmap_num2 & 0x3fff].lighting;
1980 light_intensity *= dir;
1984 if (light_intensity) {
1985 vms_vector segment_center;
1986 compute_segment_center(&segment_center, segp);
1987 apply_light_to_segment(segp,&segment_center,light_intensity,0);
1991 //this is a horrible hack to get around the horrible hack used to
1992 //smooth lighting values when an object moves between segments
1997 // ------------------------------------------------------------------------------------------
1998 // dir = +1 -> add light
1999 // dir = -1 -> subtract light
2000 // dir = 17 -> add 17x light
2001 // dir = 0 -> you are dumb
2002 void change_light(int segnum, int sidenum, int dir)
2006 for (i=0; i<Num_static_lights; i++) {
2007 if ((Dl_indices[i].segnum == segnum) && (Dl_indices[i].sidenum == sidenum)) {
2009 dlp = &Delta_lights[Dl_indices[i].index];
2011 for (j=0; j<Dl_indices[i].count; j++) {
2012 for (k=0; k<4; k++) {
2014 dl = dir * dlp->vert_light[k] * DL_SCALE;
2015 Assert((dlp->segnum >= 0) && (dlp->segnum <= Highest_segment_index));
2016 Assert((dlp->sidenum >= 0) && (dlp->sidenum < MAX_SIDES_PER_SEGMENT));
2017 new_l = (Segments[dlp->segnum].sides[dlp->sidenum].uvls[k].l += dl);
2019 Segments[dlp->segnum].sides[dlp->sidenum].uvls[k].l = 0;
2026 //recompute static light for segment
2027 change_segment_light(segnum,sidenum,dir);
2030 // Subtract light cast by a light source from all surfaces to which it applies light.
2031 // This is precomputed data, stored at static light application time in the editor (the slow lighting function).
2032 // returns 1 if lights actually subtracted, else 0
2033 int subtract_light(int segnum, int sidenum)
2035 if (Light_subtracted[segnum] & (1 << sidenum)) {
2036 //mprintf((0, "Warning: Trying to subtract light from a source twice!\n"));
2040 Light_subtracted[segnum] |= (1 << sidenum);
2041 change_light(segnum, sidenum, -1);
2045 // Add light cast by a light source from all surfaces to which it applies light.
2046 // This is precomputed data, stored at static light application time in the editor (the slow lighting function).
2047 // You probably only want to call this after light has been subtracted.
2048 // returns 1 if lights actually added, else 0
2049 int add_light(int segnum, int sidenum)
2051 if (!(Light_subtracted[segnum] & (1 << sidenum))) {
2052 //mprintf((0, "Warning: Trying to add light which has never been subtracted!\n"));
2056 Light_subtracted[segnum] &= ~(1 << sidenum);
2057 change_light(segnum, sidenum, 1);
2061 // Light_subtracted[i] contains bit indicators for segment #i.
2062 // If bit n (1 << n) is set, then side #n in segment #i has had light subtracted from original (editor-computed) value.
2063 ubyte Light_subtracted[MAX_SEGMENTS];
2065 // Parse the Light_subtracted array, turning on or off all lights.
2066 void apply_all_changed_light(void)
2070 for (i=0; i<=Highest_segment_index; i++) {
2071 for (j=0; j<MAX_SIDES_PER_SEGMENT; j++)
2072 if (Light_subtracted[i] & (1 << j))
2073 change_light(i, j, -1);
2077 //@@// Scans Light_subtracted bit array.
2078 //@@// For all light sources which have had their light subtracted, adds light back in.
2079 //@@void restore_all_lights_in_mine(void)
2083 //@@ for (i=0; i<Num_static_lights; i++) {
2084 //@@ int segnum, sidenum;
2085 //@@ delta_light *dlp;
2087 //@@ segnum = Dl_indices[i].segnum;
2088 //@@ sidenum = Dl_indices[i].sidenum;
2089 //@@ if (Light_subtracted[segnum] & (1 << sidenum)) {
2090 //@@ dlp = &Delta_lights[Dl_indices[i].index];
2092 //@@ Light_subtracted[segnum] &= ~(1 << sidenum);
2093 //@@ for (j=0; j<Dl_indices[i].count; j++) {
2094 //@@ for (k=0; k<4; k++) {
2096 //@@ dl = dlp->vert_light[k] * DL_SCALE;
2097 //@@ Assert((dlp->segnum >= 0) && (dlp->segnum <= Highest_segment_index));
2098 //@@ Assert((dlp->sidenum >= 0) && (dlp->sidenum < MAX_SIDES_PER_SEGMENT));
2099 //@@ Segments[dlp->segnum].sides[dlp->sidenum].uvls[k].l += dl;
2107 // Should call this whenever a new mine gets loaded.
2108 // More specifically, should call this whenever something global happens
2109 // to change the status of static light in the mine.
2110 void clear_light_subtracted(void)
2114 for (i=0; i<=Highest_segment_index; i++)
2115 Light_subtracted[i] = 0;
2119 // -----------------------------------------------------------------------------
2120 fix find_connected_distance_segments( int seg0, int seg1, int depth, int wid_flag)
2124 compute_segment_center(&p0, &Segments[seg0]);
2125 compute_segment_center(&p1, &Segments[seg1]);
2127 return find_connected_distance(&p0, seg0, &p1, seg1, depth, wid_flag);
2130 #define AMBIENT_SEGMENT_DEPTH 5
2132 // -----------------------------------------------------------------------------
2133 // Do a bfs from segnum, marking slots in marked_segs if the segment is reachable.
2134 void ambient_mark_bfs(int segnum, sbyte *marked_segs, int depth)
2141 marked_segs[segnum] = 1;
2143 for (i=0; i<MAX_SIDES_PER_SEGMENT; i++) {
2144 int child = Segments[segnum].children[i];
2146 if (IS_CHILD(child) && (WALL_IS_DOORWAY(&Segments[segnum],i) & WID_RENDPAST_FLAG) && !marked_segs[child])
2147 ambient_mark_bfs(child, marked_segs, depth-1);
2152 // -----------------------------------------------------------------------------
2153 // Indicate all segments which are within audible range of falling water or lava,
2154 // and so should hear ambient gurgles.
2155 void set_ambient_sound_flags_common(int tmi_bit, int s2f_bit)
2158 sbyte marked_segs[MAX_SEGMENTS];
2160 // Now, all segments containing ambient lava or water sound makers are flagged.
2161 // Additionally flag all segments which are within range of them.
2162 for (i=0; i<=Highest_segment_index; i++) {
2164 Segment2s[i].s2_flags &= ~s2f_bit;
2167 // Mark all segments which are sources of the sound.
2168 for (i=0; i<=Highest_segment_index; i++) {
2169 segment *segp = &Segments[i];
2170 segment2 *seg2p = &Segment2s[i];
2172 for (j=0; j<MAX_SIDES_PER_SEGMENT; j++) {
2173 side *sidep = &segp->sides[j];
2175 if ((TmapInfo[sidep->tmap_num].flags & tmi_bit) || (TmapInfo[sidep->tmap_num2 & 0x3fff].flags & tmi_bit)) {
2176 if (!IS_CHILD(segp->children[j]) || (sidep->wall_num != -1)) {
2177 seg2p->s2_flags |= s2f_bit;
2178 marked_segs[i] = 1; // Say it's itself that it is close enough to to hear something.
2186 // Next mark all segments within N segments of a source.
2187 for (i=0; i<=Highest_segment_index; i++) {
2188 segment2 *seg2p = &Segment2s[i];
2190 if (seg2p->s2_flags & s2f_bit)
2191 ambient_mark_bfs(i, marked_segs, AMBIENT_SEGMENT_DEPTH);
2194 // Now, flip bits in all segments which can hear the ambient sound.
2195 for (i=0; i<=Highest_segment_index; i++)
2197 Segment2s[i].s2_flags |= s2f_bit;
2202 // -----------------------------------------------------------------------------
2203 // Indicate all segments which are within audible range of falling water or lava,
2204 // and so should hear ambient gurgles.
2205 // Bashes values in Segment2s array.
2206 void set_ambient_sound_flags(void)
2208 set_ambient_sound_flags_common(TMI_VOLATILE, S2F_AMBIENT_LAVA);
2209 set_ambient_sound_flags_common(TMI_WATER, S2F_AMBIENT_WATER);