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-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
14 * $Source: /cvs/cvsroot/d2x/main/editor/seguvs.c,v $
17 * $Date: 2004-12-19 13:54:27 $
19 * u,v coordinate computation for segment faces
21 * $Log: not supported by cvs2svn $
22 * Revision 1.2 2003/03/09 06:34:09 donut
23 * change byte typedef to sbyte to avoid conflict with win32 byte which is unsigned
25 * Revision 1.1.1.1 1999/06/14 22:04:31 donut
26 * Import of d1x 1.37 source.
28 * Revision 2.1 1995/05/08 10:49:34 mike
29 * fix lighting bug: oblong segments could be very dark.
31 * Revision 2.0 1995/02/27 11:36:37 john
32 * Version 2.0. Ansi-fied.
34 * Revision 1.84 1994/11/27 23:17:18 matt
35 * Made changes for new mprintf calling convention
37 * Revision 1.83 1994/11/17 14:48:02 mike
38 * validation functions moved from editor to game.
40 * Revision 1.82 1994/10/15 19:08:26 mike
41 * Disable exhaustive search mprintfs in find_point_seg during lighting.
43 * Revision 1.81 1994/08/25 21:55:50 mike
46 * Revision 1.80 1994/08/04 19:13:22 matt
47 * Changed a bunch of vecmat calls to use multiple-function routines, and to
48 * allow the use of C macros for some functions
50 * Revision 1.79 1994/08/03 10:31:33 mike
51 * Texture map propagation without uv assignment.
53 * Revision 1.78 1994/08/01 13:31:12 matt
54 * Made fvi() check holes in transparent walls, and changed fvi() calling
55 * parms to take all input data in query structure.
57 * Revision 1.77 1994/07/08 14:31:24 matt
60 * Revision 1.76 1994/06/23 14:01:04 mike
61 * Fix cache bug which caused some vertices to not get light, mainly
62 * noticeable at joints which had doors.
64 * Revision 1.75 1994/06/22 17:33:11 mike
65 * Make position of light (which is always towards center of segment from
66 * actual light panel) constant, not dependent on segment size, which fixes
67 * bug of dark light panels in very large segments.
69 * Revision 1.74 1994/06/21 18:58:18 mike
70 * Fix stupid bug in light propagation, was using wrong vector in fvi caching.
72 * Revision 1.73 1994/06/20 11:20:24 mike
73 * Fix stupid lighting bug introduced when I went to cached fvi results.
75 * Revision 1.72 1994/06/19 16:26:37 mike
76 * Speed up lighting by storing and hashing fvi results.
78 * Revision 1.71 1994/06/17 16:05:56 mike
79 * Support optional quick lighting propagation: no find_vector_intersection.
81 * Revision 1.70 1994/06/15 15:42:30 mike
82 * Propagate static_light.
84 * Revision 1.69 1994/06/14 16:59:37 mike
85 * Fix references to tmap_num2, must strip off orientation bits.
87 * Revision 1.68 1994/06/09 09:58:58 matt
88 * Moved find_vector_intersection() from physics.c to new file fvi.c
91 * Revision 1.67 1994/06/08 18:14:02 mike
92 * mprintf a dot in light casting.
94 * Revision 1.66 1994/06/08 14:37:45 mike
95 * double static light value in going from value (a short) to static_light (a fix).
97 * Revision 1.65 1994/06/08 14:29:44 matt
98 * Added static_light field to segment structure, and padded side struct
99 * to be longword aligned.
101 * Revision 1.64 1994/06/08 11:45:24 mike
102 * New, supercool, superslow lighting function.
104 * Revision 1.63 1994/06/07 09:38:11 mike
105 * Make lighting function yet better by calling find_vector_intersection.
107 * Revision 1.62 1994/06/06 13:14:33 mike
108 * Make illusory walls cast light.
110 * Revision 1.61 1994/06/05 20:39:47 mike
111 * Add new distance and dot product based lighting function.
113 * Revision 1.60 1994/05/31 12:31:18 mike
114 * fix bugs in lighting, though it's not perfect, will be changing all
115 * lighting to be distance based. Bug had to do with not handling one
116 * of the return values from WALL_IS_DOORWAY, so assuming light couldn't
117 * be recursively propagated almost all the time.
119 * Revision 1.59 1994/05/19 23:35:26 mike
120 * Support uv coordinates in range 0..1.0.
122 * Revision 1.58 1994/05/19 12:10:21 matt
123 * Use new vecmat macros and globals
125 * Revision 1.57 1994/05/04 19:15:53 mike
126 * Error checking for degenerate segments.
128 * Revision 1.56 1994/05/03 11:02:34 mike
129 * Change how default texture map assignment works; now pixels are constant size.
131 * Revision 1.55 1994/04/28 23:25:26 yuan
132 * Obliterated warnings.
138 static char rcsid[] = "$Id: seguvs.c,v 1.1 2004-12-19 13:54:27 btb Exp $";
149 #include "editor/editor.h"
158 #include "editor/kdefs.h"
159 #include "bm.h" // Needed for TmapInfo
160 #include "effects.h" // Needed for effects_bm_num
163 void cast_all_light_in_mine(int quick_flag);
164 //--rotate_uvs-- vms_vector Rightvec;
166 // ---------------------------------------------------------------------------------------------
167 // Returns approximate area of a side
168 fix area_on_side(side *sidep)
170 fix du,dv,width,height;
172 du = sidep->uvls[1].u - sidep->uvls[0].u;
173 dv = sidep->uvls[1].v - sidep->uvls[0].v;
175 width = fix_sqrt(fixmul(du,du) + fixmul(dv,dv));
177 du = sidep->uvls[3].u - sidep->uvls[0].u;
178 dv = sidep->uvls[3].v - sidep->uvls[0].v;
180 height = fix_sqrt(fixmul(du,du) + fixmul(dv,dv));
182 return fixmul(width, height);
185 // -------------------------------------------------------------------------------------------
186 // DEBUG function -- callable from debugger.
187 // Returns approximate area of all sides which get mapped (ie, are not a connection).
188 // I wrote this because I was curious how much memory would be required to texture map all
189 // sides individually with custom artwork. For demo1.min on 2/18/94, it would be about 5 meg.
190 int area_on_all_sides(void)
195 for (i=0; i<=Highest_segment_index; i++) {
196 segment *segp = &Segments[i];
198 for (s=0; s<MAX_SIDES_PER_SEGMENT; s++)
199 if (!IS_CHILD(segp->children[s]))
200 total_area += f2i(area_on_side(&segp->sides[s]));
206 fix average_connectivity(void)
209 int total_sides = 0, total_mapped_sides = 0;
211 for (i=0; i<=Highest_segment_index; i++) {
212 segment *segp = &Segments[i];
214 for (s=0; s<MAX_SIDES_PER_SEGMENT; s++) {
215 if (!IS_CHILD(segp->children[s]))
216 total_mapped_sides++;
221 return 6 * fixdiv(total_mapped_sides, total_sides);
224 #define MAX_LIGHT_SEGS 16
226 // ---------------------------------------------------------------------------------------------
227 // Scan all polys in all segments, return average light value for vnum.
228 // segs = output array for segments containing vertex, terminated by -1.
229 fix get_average_light_at_vertex(int vnum, short *segs)
231 int segnum, relvnum, sidenum;
234 // #ifndef NDEBUG //Removed this ifdef because the version of Assert that I used to get it to compile doesn't work without this symbol. -KRB
235 short *original_segs;
237 original_segs = segs;
244 for (segnum=0; segnum<=Highest_segment_index; segnum++) {
245 segment *segp = &Segments[segnum];
246 short *vp = segp->verts;
248 for (relvnum=0; relvnum<MAX_VERTICES_PER_SEGMENT; relvnum++)
252 if (relvnum < MAX_VERTICES_PER_SEGMENT) {
255 Assert(segs - original_segs < MAX_LIGHT_SEGS);
257 for (sidenum=0; sidenum < MAX_SIDES_PER_SEGMENT; sidenum++) {
258 if (!IS_CHILD(segp->children[sidenum])) {
259 side *sidep = &segp->sides[sidenum];
260 sbyte *vp = Side_to_verts[sidenum];
264 if (*vp++ == relvnum) {
265 total_light += sidep->uvls[v].l;
276 return total_light/num_occurrences;
282 void set_average_light_at_vertex(int vnum)
284 int relvnum, sidenum;
285 short Segment_indices[MAX_LIGHT_SEGS];
290 average_light = get_average_light_at_vertex(vnum, Segment_indices);
296 while (Segment_indices[segind] != -1) {
297 int segnum = Segment_indices[segind++];
299 segment *segp = &Segments[segnum];
301 for (relvnum=0; relvnum<MAX_VERTICES_PER_SEGMENT; relvnum++)
302 if (segp->verts[relvnum] == vnum)
305 if (relvnum < MAX_VERTICES_PER_SEGMENT) {
306 for (sidenum=0; sidenum < MAX_SIDES_PER_SEGMENT; sidenum++) {
307 if (!IS_CHILD(segp->children[sidenum])) {
308 side *sidep = &segp->sides[sidenum];
309 sbyte *vp = Side_to_verts[sidenum];
313 if (*vp++ == relvnum)
314 sidep->uvls[v].l = average_light;
320 Update_flags |= UF_WORLD_CHANGED;
323 void set_average_light_on_side(segment *segp, int sidenum)
327 if (!IS_CHILD(segp->children[sidenum]))
328 for (v=0; v<4; v++) {
329 // mprintf((0,"Vertex %i\n", segp->verts[Side_to_verts[side][v]]));
330 set_average_light_at_vertex(segp->verts[Side_to_verts[sidenum][v]]);
335 int set_average_light_on_curside(void)
337 set_average_light_on_side(Cursegp, Curside);
341 // -----------------------------------------------------------------------------------------
342 void set_average_light_on_all_fast(void)
347 int seglist[MAX_LIGHT_SEGS];
352 // Set total light value for all vertices in array average_light.
353 for (v=0; v<=Highest_vertex_index; v++) {
357 if (Vertex_active[v]) {
360 for (s=0; s<=Highest_segment_index; s++) {
361 segment *segp = &Segments[s];
362 for (relvnum=0; relvnum<MAX_VERTICES_PER_SEGMENT; relvnum++)
363 if (segp->verts[relvnum] == v)
366 if (relvnum != MAX_VERTICES_PER_SEGMENT) {
369 *segptr++ = s; // Note this segment in list, so we can process it below.
370 Assert(segptr - seglist < MAX_LIGHT_SEGS);
372 for (si=0; si<MAX_SIDES_PER_SEGMENT; si++) {
373 if (!IS_CHILD(segp->children[si])) {
374 side *sidep = &segp->sides[si];
375 sbyte *vp = Side_to_verts[si];
378 for (vv=0; vv<4; vv++)
379 if (*vp++ == relvnum) {
380 al += sidep->uvls[vv].l;
383 } // if (segp->children[si == -1) {
385 } // if (relvnum != ...
390 // Now, divide average_light by number of number of occurrences for each vertex
397 while (*segptr != -1) {
398 int segnum = *segptr++;
399 segment *segp = &Segments[segnum];
402 for (relvnum=0; relvnum<MAX_VERTICES_PER_SEGMENT; relvnum++)
403 if (segp->verts[relvnum] == v)
406 Assert(relvnum < MAX_VERTICES_PER_SEGMENT); // IMPOSSIBLE! This segment is in seglist, but vertex v does not occur!
407 for (sidenum=0; sidenum < MAX_SIDES_PER_SEGMENT; sidenum++) {
409 wid_result = WALL_IS_DOORWAY(segp, sidenum);
410 if ((wid_result != WID_FLY_FLAG) && (wid_result != WID_NO_WALL)) {
411 side *sidep = &segp->sides[sidenum];
412 sbyte *vp = Side_to_verts[sidenum];
416 if (*vp++ == relvnum)
417 sidep->uvls[v].l = al;
422 } // if (Vertex_active[v]...
428 extern int Doing_lighting_hack_flag; // If set, don't mprintf warning messages in gameseg.c/find_point_seg
429 int set_average_light_on_all(void)
431 // set_average_light_on_all_fast();
433 Doing_lighting_hack_flag = 1;
434 cast_all_light_in_mine(0);
435 Doing_lighting_hack_flag = 0;
436 Update_flags |= UF_WORLD_CHANGED;
440 // for (seg=0; seg<=Highest_segment_index; seg++)
441 // for (side=0; side<MAX_SIDES_PER_SEGMENT; side++)
442 // if (Segments[seg].segnum != -1)
443 // set_average_light_on_side(&Segments[seg], side);
447 int set_average_light_on_all_quick(void)
449 cast_all_light_in_mine(1);
450 Update_flags |= UF_WORLD_CHANGED;
455 // ---------------------------------------------------------------------------------------------
456 fix compute_uv_dist(uvl *uv0, uvl *uv1)
468 return vm_vec_dist(&v0,&v1);
471 // ---------------------------------------------------------------------------------------------
472 // Given a polygon, compress the uv coordinates so that they are as close to 0 as possible.
473 // Do this by adding a constant u and v to each uv pair.
474 void compress_uv_coordinates(side *sidep)
482 for (v=0; v<4; v++) {
483 uc += sidep->uvls[v].u;
484 vc += sidep->uvls[v].v;
489 uc = uc & 0xffff0000;
490 vc = vc & 0xffff0000;
492 for (v=0; v<4; v++) {
493 sidep->uvls[v].u -= uc;
494 sidep->uvls[v].v -= vc;
499 // ---------------------------------------------------------------------------------------------
500 void compress_uv_coordinates_on_side(side *sidep)
502 compress_uv_coordinates(sidep);
505 // ---------------------------------------------------------------------------------------------
506 void validate_uv_coordinates_on_side(segment *segp, int sidenum)
509 // fix uv_dist,threed_dist;
511 // fix dist_ratios[MAX_VERTICES_PER_POLY];
512 side *sidep = &segp->sides[sidenum];
513 // sbyte *vp = Side_to_verts[sidenum];
515 // This next hunk doesn't seem to affect anything. @mk, 02/13/94
516 // for (v=1; v<4; v++) {
517 // uv_dist = compute_uv_dist(&sidep->uvls[v],&sidep->uvls[0]);
518 // threed_dist = vm_vec_mag(vm_vec_sub(&tvec,&Vertices[segp->verts[vp[v]],&Vertices[vp[0]]));
519 // dist_ratios[v-1] = fixdiv(uv_dist,threed_dist);
522 compress_uv_coordinates_on_side(sidep);
525 void compress_uv_coordinates_in_segment(segment *segp)
529 for (side=0; side<MAX_SIDES_PER_SEGMENT; side++)
530 compress_uv_coordinates_on_side(&segp->sides[side]);
533 void compress_uv_coordinates_all(void)
537 for (seg=0; seg<=Highest_segment_index; seg++)
538 if (Segments[seg].segnum != -1)
539 compress_uv_coordinates_in_segment(&Segments[seg]);
542 void check_lighting_side(segment *sp, int sidenum)
545 side *sidep = &sp->sides[sidenum];
548 if ((sidep->uvls[v].l > F1_0*16) || (sidep->uvls[v].l < 0))
549 Int3(); //mprintf(0,"Bogus lighting value in segment %i, side %i, vert %i = %x\n",sp-Segments, side, v, sidep->uvls[v].l);
552 void check_lighting_segment(segment *segp)
556 for (side=0; side<MAX_SIDES_PER_SEGMENT; side++)
557 check_lighting_side(segp, side);
560 // Flag bogus lighting values.
561 void check_lighting_all(void)
565 for (seg=0; seg<=Highest_segment_index; seg++)
566 if (Segments[seg].segnum != -1)
567 check_lighting_segment(&Segments[seg]);
570 void assign_default_lighting_on_side(segment *segp, int sidenum)
573 side *sidep = &segp->sides[sidenum];
576 sidep->uvls[v].l = DEFAULT_LIGHTING;
579 void assign_default_lighting(segment *segp)
583 for (sidenum=0; sidenum<MAX_SIDES_PER_SEGMENT; sidenum++)
584 assign_default_lighting_on_side(segp, sidenum);
587 void assign_default_lighting_all(void)
591 for (seg=0; seg<=Highest_segment_index; seg++)
592 if (Segments[seg].segnum != -1)
593 assign_default_lighting(&Segments[seg]);
596 // ---------------------------------------------------------------------------------------------
597 void validate_uv_coordinates(segment *segp)
601 for (s=0; s<MAX_SIDES_PER_SEGMENT; s++)
602 validate_uv_coordinates_on_side(segp,s);
606 // ---------------------------------------------------------------------------------------------
607 // For all faces in side, copy uv coordinates from uvs array to face.
608 void copy_uvs_from_side_to_faces(segment *segp, int sidenum, uvl uvls[])
611 side *sidep = &segp->sides[sidenum];
614 sidep->uvls[v] = uvls[v];
619 fix zhypot(fix a,fix b);
620 #pragma aux zhypot parm [eax] [ebx] value [eax] modify [eax ebx ecx edx] = \
629 fix zhypot(fix a,fix b) {
630 double x = (double)a / 65536;
631 double y = (double)b / 65536;
632 return (long)(sqrt(x * x + y * y) * 65536);
636 // ---------------------------------------------------------------------------------------------
637 // Assign lighting value to side, a function of the normal vector.
638 void assign_light_to_side(segment *sp, int sidenum)
641 side *sidep = &sp->sides[sidenum];
644 sidep->uvls[v].l = DEFAULT_LIGHTING;
647 fix Stretch_scale_x = F1_0;
648 fix Stretch_scale_y = F1_0;
650 // ---------------------------------------------------------------------------------------------
651 // Given u,v coordinates at two vertices, assign u,v coordinates to other two vertices on a side.
652 // (Actually, assign them to the coordinates in the faces.)
653 // va, vb = face-relative vertex indices corresponding to uva, uvb. Ie, they are always in 0..3 and should be looked up in
654 // Side_to_verts[side] to get the segment relative index.
655 void assign_uvs_to_side(segment *segp, int sidenum, uvl *uva, uvl *uvb, int va, int vb)
657 int vlo,vhi,v0,v1,v2,v3;
658 vms_vector fvec,rvec,tvec;
660 uvl uvls[4],ruvmag,fuvmag,uvlo,uvhi;
664 Assert( (va<4) && (vb<4) );
665 Assert((abs(va - vb) == 1) || (abs(va - vb) == 3)); // make sure the verticies specify an edge
667 vp = (sbyte *)&Side_to_verts[sidenum];
669 // We want vlo precedes vhi, ie vlo < vhi, or vlo = 3, vhi = 0
670 if (va == ((vb + 1) % 4)) { // va = vb + 1
682 Assert(((vlo+1) % 4) == vhi); // If we are on an edge, then uvhi is one more than uvlo (mod 4)
686 // Now we have vlo precedes vhi, compute vertices ((vhi+1) % 4) and ((vhi+2) % 4)
688 // Assign u,v scale to a unit length right vector.
689 fmag = zhypot(uvhi.v - uvlo.v,uvhi.u - uvlo.u);
690 if (fmag < 64) { // this is a fix, so 64 = 1/1024
691 mprintf((0,"Warning: fmag = %7.3f, using approximate u,v values\n",f2fl(fmag)));
697 ruvmag.u = uvhi.v - uvlo.v;
698 ruvmag.v = uvlo.u - uvhi.u;
700 fuvmag.u = uvhi.u - uvlo.u;
701 fuvmag.v = uvhi.v - uvlo.v;
704 v0 = segp->verts[vp[vlo]];
705 v1 = segp->verts[vp[vhi]];
706 v2 = segp->verts[vp[(vhi+1)%4]];
707 v3 = segp->verts[vp[(vhi+2)%4]];
709 // Compute right vector by computing orientation matrix from:
710 // forward vector = vlo:vhi
711 // right vector = vlo:(vhi+2) % 4
712 vm_vec_sub(&fvec,&Vertices[v1],&Vertices[v0]);
713 vm_vec_sub(&rvec,&Vertices[v3],&Vertices[v0]);
715 if (((fvec.x == 0) && (fvec.y == 0) && (fvec.z == 0)) || ((rvec.x == 0) && (rvec.y == 0) && (rvec.z == 0))) {
716 mprintf((1, "Trapped null vector in assign_uvs_to_side, using identity matrix.\n"));
717 rotmat = vmd_identity_matrix;
719 vm_vector_2_matrix(&rotmat,&fvec,0,&rvec);
721 rvec = rotmat.rvec; vm_vec_negate(&rvec);
724 // mprintf((0, "va = %i, vb = %i\n", va, vb));
725 mag01 = vm_vec_dist(&Vertices[v1],&Vertices[v0]);
726 if ((va == 0) || (va == 2))
727 mag01 = fixmul(mag01, Stretch_scale_x);
729 mag01 = fixmul(mag01, Stretch_scale_y);
731 if (mag01 < F1_0/1024 )
732 editor_status("U, V bogosity in segment #%i, probably on side #%i. CLEAN UP YOUR MESS!", segp-Segments, sidenum);
734 vm_vec_sub(&tvec,&Vertices[v2],&Vertices[v1]);
735 uvls[(vhi+1)%4].u = uvhi.u +
736 fixdiv(fixmul(ruvmag.u,vm_vec_dotprod(&rvec,&tvec)),mag01) +
737 fixdiv(fixmul(fuvmag.u,vm_vec_dotprod(&fvec,&tvec)),mag01);
739 uvls[(vhi+1)%4].v = uvhi.v +
740 fixdiv(fixmul(ruvmag.v,vm_vec_dotprod(&rvec,&tvec)),mag01) +
741 fixdiv(fixmul(fuvmag.v,vm_vec_dotprod(&fvec,&tvec)),mag01);
744 vm_vec_sub(&tvec,&Vertices[v3],&Vertices[v0]);
745 uvls[(vhi+2)%4].u = uvlo.u +
746 fixdiv(fixmul(ruvmag.u,vm_vec_dotprod(&rvec,&tvec)),mag01) +
747 fixdiv(fixmul(fuvmag.u,vm_vec_dotprod(&fvec,&tvec)),mag01);
749 uvls[(vhi+2)%4].v = uvlo.v +
750 fixdiv(fixmul(ruvmag.v,vm_vec_dotprod(&rvec,&tvec)),mag01) +
751 fixdiv(fixmul(fuvmag.v,vm_vec_dotprod(&fvec,&tvec)),mag01);
753 uvls[(vhi+1)%4].l = uvhi.l;
754 uvls[(vhi+2)%4].l = uvlo.l;
756 copy_uvs_from_side_to_faces(segp, sidenum, uvls);
763 // -----------------------------------------------------------------------------------------------------------
764 // Assign default uvs to side.
767 // v1 = k,0 where k is 3d size dependent
768 // v2, v3 assigned by assign_uvs_to_side
769 void assign_default_uvs_to_side(segment *segp,int side)
777 vp = Side_to_verts[side];
780 uv1.v = Num_tilings * fixmul(Vmag, vm_vec_dist(&Vertices[segp->verts[vp[1]]],&Vertices[segp->verts[vp[0]]]));
782 assign_uvs_to_side(segp, side, &uv0, &uv1, 0, 1);
785 // -----------------------------------------------------------------------------------------------------------
786 // Assign default uvs to side.
789 // v1 = k,0 where k is 3d size dependent
790 // v2, v3 assigned by assign_uvs_to_side
791 void stretch_uvs_from_curedge(segment *segp, int side)
799 uv0.u = segp->sides[side].uvls[v0].u;
800 uv0.v = segp->sides[side].uvls[v0].v;
802 uv1.u = segp->sides[side].uvls[v1].u;
803 uv1.v = segp->sides[side].uvls[v1].v;
805 assign_uvs_to_side(segp, side, &uv0, &uv1, v0, v1);
808 // --------------------------------------------------------------------------------------------------------------
809 // Assign default uvs to a segment.
810 void assign_default_uvs_to_segment(segment *segp)
814 for (s=0; s<MAX_SIDES_PER_SEGMENT; s++) {
815 assign_default_uvs_to_side(segp,s);
816 assign_light_to_side(segp, s);
821 // -- mk021394 -- // --------------------------------------------------------------------------------------------------------------
822 // -- mk021394 -- // Find the face:poly:vertex index in base_seg:base_common_side which is segment relative vertex v1
823 // -- mk021394 -- // This very specific routine is subsidiary to med_assign_uvs_to_side.
824 // -- mk021394 -- void get_face_and_vert(segment *base_seg, int base_common_side, int v1, int *ff, int *vv, int *pi)
826 // -- mk021394 -- int p,f,v;
828 // -- mk021394 -- for (f=0; f<base_seg->sides[base_common_side].num_faces; f++) {
829 // -- mk021394 -- face *fp = &base_seg->sides[base_common_side].faces[f];
830 // -- mk021394 -- for (p=0; p<fp->num_polys; p++) {
831 // -- mk021394 -- poly *pp = &fp->polys[p];
832 // -- mk021394 -- for (v=0; v<pp->num_vertices; v++)
833 // -- mk021394 -- if (pp->verts[v] == v1) {
834 // -- mk021394 -- *ff = f;
835 // -- mk021394 -- *vv = v;
836 // -- mk021394 -- *pi = p;
837 // -- mk021394 -- return;
842 // -- mk021394 -- Assert(0); // Error -- Couldn't find face:vertex which matched vertex v1 on base_seg:base_common_side
845 // -- mk021394 -- // --------------------------------------------------------------------------------------------------------------
846 // -- mk021394 -- // Find the vertex index in base_seg:base_common_side which is segment relative vertex v1
847 // -- mk021394 -- // This very specific routine is subsidiary to med_assign_uvs_to_side.
848 // -- mk021394 -- void get_side_vert(segment *base_seg,int base_common_side,int v1,int *vv)
850 // -- mk021394 -- int p,f,v;
852 // -- mk021394 -- Assert((base_seg->sides[base_common_side].tri_edge == 0) || (base_seg->sides[base_common_side].tri_edge == 1));
853 // -- mk021394 -- Assert(base_seg->sides[base_common_side].num_faces <= 2);
855 // -- mk021394 -- for (f=0; f<base_seg->sides[base_common_side].num_faces; f++) {
856 // -- mk021394 -- face *fp = &base_seg->sides[base_common_side].faces[f];
857 // -- mk021394 -- for (p=0; p<fp->num_polys; p++) {
858 // -- mk021394 -- poly *pp = &fp->polys[p];
859 // -- mk021394 -- for (v=0; v<pp->num_vertices; v++)
860 // -- mk021394 -- if (pp->verts[v] == v1) {
861 // -- mk021394 -- if (pp->num_vertices == 4) {
862 // -- mk021394 -- *vv = v;
863 // -- mk021394 -- return;
866 // -- mk021394 -- if (base_seg->sides[base_common_side].tri_edge == 0) { // triangulated 012, 023, so if f==0, *vv = v, if f==1, *vv = v if v=0, else v+1
867 // -- mk021394 -- if ((f == 1) && (v > 0))
868 // -- mk021394 -- v++;
869 // -- mk021394 -- *vv = v;
870 // -- mk021394 -- return;
871 // -- mk021394 -- } else { // triangulated 013, 123
872 // -- mk021394 -- if (f == 0) {
873 // -- mk021394 -- if (v == 2)
874 // -- mk021394 -- v++;
875 // -- mk021394 -- } else
876 // -- mk021394 -- v++;
877 // -- mk021394 -- *vv = v;
878 // -- mk021394 -- return;
884 // -- mk021394 -- Assert(0); // Error -- Couldn't find face:vertex which matched vertex v1 on base_seg:base_common_side
887 //--rotate_uvs-- // --------------------------------------------------------------------------------------------------------------
888 //--rotate_uvs-- // Rotate uvl coordinates uva, uvb about their center point by heading
889 //--rotate_uvs-- void rotate_uvs(uvl *uva, uvl *uvb, vms_vector *rvec)
891 //--rotate_uvs-- uvl uvc, uva1, uvb1;
893 //--rotate_uvs-- uvc.u = (uva->u + uvb->u)/2;
894 //--rotate_uvs-- uvc.v = (uva->v + uvb->v)/2;
896 //--rotate_uvs-- uva1.u = fixmul(uva->u - uvc.u, rvec->x) - fixmul(uva->v - uvc.v, rvec->z);
897 //--rotate_uvs-- uva1.v = fixmul(uva->u - uvc.u, rvec->z) + fixmul(uva->v - uvc.v, rvec->x);
899 //--rotate_uvs-- uva->u = uva1.u + uvc.u;
900 //--rotate_uvs-- uva->v = uva1.v + uvc.v;
902 //--rotate_uvs-- uvb1.u = fixmul(uvb->u - uvc.u, rvec->x) - fixmul(uvb->v - uvc.v, rvec->z);
903 //--rotate_uvs-- uvb1.v = fixmul(uvb->u - uvc.u, rvec->z) + fixmul(uvb->v - uvc.v, rvec->x);
905 //--rotate_uvs-- uvb->u = uvb1.u + uvc.u;
906 //--rotate_uvs-- uvb->v = uvb1.v + uvc.v;
910 // --------------------------------------------------------------------------------------------------------------
911 void med_assign_uvs_to_side(segment *con_seg, int con_common_side, segment *base_seg, int base_common_side, int abs_id1, int abs_id2)
914 int v,bv1,bv2, vv1, vv2;
919 // Find which vertices in segment match abs_id1, abs_id2
920 for (v=0; v<MAX_VERTICES_PER_SEGMENT; v++) {
921 if (base_seg->verts[v] == abs_id1)
923 if (base_seg->verts[v] == abs_id2)
925 if (con_seg->verts[v] == abs_id1)
927 if (con_seg->verts[v] == abs_id2)
931 // Now, bv1, bv2 are segment relative vertices in base segment which are the same as absolute vertices abs_id1, abs_id2
932 // cv1, cv2 are segment relative vertices in conn segment which are the same as absolute vertices abs_id1, abs_id2
934 Assert((bv1 != -1) && (bv2 != -1) && (cv1 != -1) && (cv2 != -1));
935 Assert((uv1.u != uv2.u) || (uv1.v != uv2.v));
937 // Now, scan 4 vertices in base side and 4 vertices in connected side.
938 // Set uv1, uv2 to uv coordinates from base side which correspond to vertices bv1, bv2.
939 // Set vv1, vv2 to relative vertex ids (in 0..3) in connecting side which correspond to cv1, cv2
941 for (v=0; v<4; v++) {
942 if (bv1 == Side_to_verts[base_common_side][v])
943 uv1 = base_seg->sides[base_common_side].uvls[v];
945 if (bv2 == Side_to_verts[base_common_side][v])
946 uv2 = base_seg->sides[base_common_side].uvls[v];
948 if (cv1 == Side_to_verts[con_common_side][v])
951 if (cv2 == Side_to_verts[con_common_side][v])
955 Assert( (vv1 != -1) && (vv2 != -1) );
956 assign_uvs_to_side(con_seg, con_common_side, &uv1, &uv2, vv1, vv2);
960 // -----------------------------------------------------------------------------
961 // Given a base and a connecting segment, a side on each of those segments and two global vertex ids,
962 // determine which side in each of the segments shares those two vertices.
963 // This is used to propagate a texture map id to a connecting segment in an expected and desired way.
964 // Since we can attach any side of a segment to any side of another segment, and do so in each case in
965 // four different rotations (for a total of 6*6*4 = 144 ways), not having this nifty function will cause
967 void get_side_ids(segment *base_seg, segment *con_seg, int base_side, int con_side, int abs_id1, int abs_id2, int *base_common_side, int *con_common_side)
969 char *base_vp,*con_vp;
972 *base_common_side = -1;
974 // Find side in base segment which contains the two global vertex ids.
975 for (side=0; side<MAX_SIDES_PER_SEGMENT; side++) {
976 if (side != base_side) {
977 base_vp = Side_to_verts[side];
978 for (v0=0; v0<4; v0++)
979 if (((base_seg->verts[(int) base_vp[v0]] == abs_id1) && (base_seg->verts[(int) base_vp[(v0+1) % 4]] == abs_id2)) || ((base_seg->verts[(int) base_vp[v0]] == abs_id2) && (base_seg->verts[(int)base_vp[ (v0+1) % 4]] == abs_id1))) {
980 Assert(*base_common_side == -1); // This means two different sides shared the same edge with base_side == impossible!
981 *base_common_side = side;
986 // Note: For connecting segment, process vertices in reversed order.
987 *con_common_side = -1;
989 // Find side in connecting segment which contains the two global vertex ids.
990 for (side=0; side<MAX_SIDES_PER_SEGMENT; side++) {
991 if (side != con_side) {
992 con_vp = Side_to_verts[side];
993 for (v0=0; v0<4; v0++)
994 if (((con_seg->verts[(int) con_vp[(v0 + 1) % 4]] == abs_id1) && (con_seg->verts[(int) con_vp[v0]] == abs_id2)) || ((con_seg->verts[(int) con_vp[(v0 + 1) % 4]] == abs_id2) && (con_seg->verts[(int) con_vp[v0]] == abs_id1))) {
995 Assert(*con_common_side == -1); // This means two different sides shared the same edge with con_side == impossible!
996 *con_common_side = side;
1001 // mprintf((0,"side %3i adjacent to side %3i\n",*base_common_side,*con_common_side));
1003 Assert((*base_common_side != -1) && (*con_common_side != -1));
1006 // -----------------------------------------------------------------------------
1007 // Propagate texture map u,v coordinates from base_seg:base_side to con_seg:con_side.
1008 // The two vertices abs_id1 and abs_id2 are the only two vertices common to the two sides.
1009 // If uv_only_flag is 1, then don't assign texture map ids, only update the uv coordinates
1010 // If uv_only_flag is -1, then ONLY assign texture map ids, don't update the uv coordinates
1011 void propagate_tmaps_to_segment_side(segment *base_seg, int base_side, segment *con_seg, int con_side, int abs_id1, int abs_id2, int uv_only_flag)
1013 int base_common_side,con_common_side;
1016 Assert ((uv_only_flag == -1) || (uv_only_flag == 0) || (uv_only_flag == 1));
1018 // Set base_common_side = side in base_seg which contains edge abs_id1:abs_id2
1019 // Set con_common_side = side in con_seg which contains edge abs_id1:abs_id2
1020 if (base_seg != con_seg)
1021 get_side_ids(base_seg, con_seg, base_side, con_side, abs_id1, abs_id2, &base_common_side, &con_common_side);
1023 base_common_side = base_side;
1024 con_common_side = con_side;
1027 // Now, all faces in con_seg which are on side con_common_side get their tmap_num set to whatever tmap is assigned
1028 // to whatever face I find which is on side base_common_side.
1029 // First, find tmap_num for base_common_side. If it doesn't exist (ie, there is a connection there), look at the segment
1030 // that is connected through it.
1031 if (!IS_CHILD(con_seg->children[con_common_side])) {
1032 if (!IS_CHILD(base_seg->children[base_common_side])) {
1033 // There is at least one face here, so get the tmap_num from there.
1034 tmap_num = base_seg->sides[base_common_side].tmap_num;
1036 // Now assign all faces in the connecting segment on side con_common_side to tmap_num.
1037 if ((uv_only_flag == -1) || (uv_only_flag == 0))
1038 con_seg->sides[con_common_side].tmap_num = tmap_num;
1040 if (uv_only_flag != -1)
1041 med_assign_uvs_to_side(con_seg, con_common_side, base_seg, base_common_side, abs_id1, abs_id2);
1043 } else { // There are no faces here, there is a connection, trace through the connection.
1046 cside = find_connect_side(base_seg, &Segments[base_seg->children[base_common_side]]);
1047 propagate_tmaps_to_segment_side(&Segments[base_seg->children[base_common_side]], cside, con_seg, con_side, abs_id1, abs_id2, uv_only_flag);
1053 sbyte Edge_between_sides[MAX_SIDES_PER_SEGMENT][MAX_SIDES_PER_SEGMENT][2] = {
1054 // left top right bottom back front
1055 { {-1,-1}, { 3, 7}, {-1,-1}, { 2, 6}, { 6, 7}, { 2, 3} }, // left
1056 { { 3, 7}, {-1,-1}, { 0, 4}, {-1,-1}, { 4, 7}, { 0, 3} }, // top
1057 { {-1,-1}, { 0, 4}, {-1,-1}, { 1, 5}, { 4, 5}, { 0, 1} }, // right
1058 { { 2, 6}, {-1,-1}, { 1, 5}, {-1,-1}, { 5, 6}, { 1, 2} }, // bottom
1059 { { 6, 7}, { 4, 7}, { 4, 5}, { 5, 6}, {-1,-1}, {-1,-1} }, // back
1060 { { 2, 3}, { 0, 3}, { 0, 1}, { 1, 2}, {-1,-1}, {-1,-1} }}; // front
1062 // -----------------------------------------------------------------------------
1063 // Propagate texture map u,v coordinates to base_seg:back_side from base_seg:some-other-side
1064 // There is no easy way to figure out which side is adjacent to another side along some edge, so we do a bit of searching.
1065 void med_propagate_tmaps_to_back_side(segment *base_seg, int back_side, int uv_only_flag)
1068 int s,ss,tmap_num,back_side_tmap;
1070 if (IS_CHILD(base_seg->children[back_side]))
1071 return; // connection, so no sides here.
1073 // Scan all sides, look for an occupied side which is not back_side or Side_opposite[back_side]
1074 for (s=0; s<MAX_SIDES_PER_SEGMENT; s++)
1075 if ((s != back_side) && (s != Side_opposite[back_side])) {
1076 v1 = Edge_between_sides[s][back_side][0];
1077 v2 = Edge_between_sides[s][back_side][1];
1080 Assert(0); // Error -- couldn't find edge != back_side and Side_opposite[back_side]
1082 Assert( (v1 != -1) && (v2 != -1)); // This means there was no shared edge between the two sides.
1084 propagate_tmaps_to_segment_side(base_seg, s, base_seg, back_side, base_seg->verts[v1], base_seg->verts[v2], uv_only_flag);
1086 // Assign an unused tmap id to the back side.
1087 // Note that this can get undone by the caller if this was not part of a new attach, but a rotation or a scale (which
1088 // both do attaches).
1089 // First see if tmap on back side is anywhere else.
1090 if (!uv_only_flag) {
1091 back_side_tmap = base_seg->sides[back_side].tmap_num;
1092 for (s=0; s<MAX_SIDES_PER_SEGMENT; s++) {
1094 if (base_seg->sides[s].tmap_num == back_side_tmap) {
1095 for (tmap_num=0; tmap_num < MAX_SIDES_PER_SEGMENT; tmap_num++) {
1096 for (ss=0; ss<MAX_SIDES_PER_SEGMENT; ss++)
1097 if (ss != back_side)
1098 if (base_seg->sides[ss].tmap_num == New_segment.sides[tmap_num].tmap_num)
1099 goto found2; // current texture map (tmap_num) is used on current (ss) side, so try next one
1100 // Current texture map (tmap_num) has not been used, assign to all faces on back_side.
1101 base_seg->sides[back_side].tmap_num = New_segment.sides[tmap_num].tmap_num;
1112 int fix_bogus_uvs_on_side(void)
1114 med_propagate_tmaps_to_back_side(Cursegp, Curside, 1);
1118 void fix_bogus_uvs_on_side1(segment *sp, int sidenum, int uvonly_flag)
1120 side *sidep = &sp->sides[sidenum];
1122 if ((sidep->uvls[0].u == 0) && (sidep->uvls[1].u == 0) && (sidep->uvls[2].u == 0)) {
1123 mprintf((0,"Found bogus segment %i, side %i\n", sp-Segments, sidenum));
1124 med_propagate_tmaps_to_back_side(sp, sidenum, uvonly_flag);
1128 void fix_bogus_uvs_seg(segment *segp)
1132 for (s=0; s<MAX_SIDES_PER_SEGMENT; s++) {
1133 if (!IS_CHILD(segp->children[s]))
1134 fix_bogus_uvs_on_side1(segp, s, 1);
1138 int fix_bogus_uvs_all(void)
1142 for (seg=0; seg<=Highest_segment_index; seg++)
1143 if (Segments[seg].segnum != -1)
1144 fix_bogus_uvs_seg(&Segments[seg]);
1148 // -----------------------------------------------------------------------------
1149 // Propagate texture map u,v coordinates to base_seg:back_side from base_seg:some-other-side
1150 // There is no easy way to figure out which side is adjacent to another side along some edge, so we do a bit of searching.
1151 void med_propagate_tmaps_to_any_side(segment *base_seg, int back_side, int tmap_num, int uv_only_flag)
1156 // Scan all sides, look for an occupied side which is not back_side or Side_opposite[back_side]
1157 for (s=0; s<MAX_SIDES_PER_SEGMENT; s++)
1158 if ((s != back_side) && (s != Side_opposite[back_side])) {
1159 v1 = Edge_between_sides[s][back_side][0];
1160 v2 = Edge_between_sides[s][back_side][1];
1163 Assert(0); // Error -- couldn't find edge != back_side and Side_opposite[back_side]
1165 Assert( (v1 != -1) && (v2 != -1)); // This means there was no shared edge between the two sides.
1167 propagate_tmaps_to_segment_side(base_seg, s, base_seg, back_side, base_seg->verts[v1], base_seg->verts[v2], uv_only_flag);
1169 base_seg->sides[back_side].tmap_num = tmap_num;
1173 // -----------------------------------------------------------------------------
1174 // Segment base_seg is connected through side base_side to segment con_seg on con_side.
1175 // For all walls in con_seg, find the wall in base_seg which shares an edge. Copy tmap_num
1176 // from that side in base_seg to the wall in con_seg. If the wall in base_seg is not present
1177 // (ie, there is another segment connected through it), follow the connection through that
1178 // segment to get the wall in the connected segment which shares the edge, and get tmap_num from there.
1179 void propagate_tmaps_to_segment_sides(segment *base_seg, int base_side, segment *con_seg, int con_side, int uv_only_flag)
1181 char *base_vp,*con_vp;
1182 short abs_id1,abs_id2;
1185 base_vp = Side_to_verts[base_side];
1186 con_vp = Side_to_verts[con_side];
1188 // Do for each edge on connecting face.
1189 for (v=0; v<4; v++) {
1190 abs_id1 = base_seg->verts[(int) base_vp[v]];
1191 abs_id2 = base_seg->verts[(int) base_vp[(v+1) % 4]];
1192 propagate_tmaps_to_segment_side(base_seg, base_side, con_seg, con_side, abs_id1, abs_id2, uv_only_flag);
1197 // -----------------------------------------------------------------------------
1198 // Propagate texture maps in base_seg to con_seg.
1199 // For each wall in con_seg, find the wall in base_seg which shared an edge. Copy tmap_num from that
1200 // wall in base_seg to the wall in con_seg. If the wall in base_seg is not present, then look at the
1201 // segment connected through base_seg through the wall. The wall with a common edge is the new wall
1202 // of interest. Continue searching in this way until a wall of interest is present.
1203 void med_propagate_tmaps_to_segments(segment *base_seg,segment *con_seg, int uv_only_flag)
1207 // mprintf((0,"Propagating segments from %i to %i\n",base_seg-Segments,con_seg-Segments));
1208 for (s=0; s<MAX_SIDES_PER_SEGMENT; s++)
1209 if (base_seg->children[s] == con_seg-Segments)
1210 propagate_tmaps_to_segment_sides(base_seg, s, con_seg, find_connect_side(base_seg, con_seg), uv_only_flag);
1212 con_seg->static_light = base_seg->static_light;
1214 validate_uv_coordinates(con_seg);
1218 // -------------------------------------------------------------------------------
1219 // Copy texture map uvs from srcseg to destseg.
1220 // If two segments have different face structure (eg, destseg has two faces on side 3, srcseg has only 1)
1221 // then assign uvs according to side vertex id, not face vertex id.
1222 void copy_uvs_seg_to_seg(segment *destseg,segment *srcseg)
1226 for (s=0; s<MAX_SIDES_PER_SEGMENT; s++) {
1227 destseg->sides[s].tmap_num = srcseg->sides[s].tmap_num;
1228 destseg->sides[s].tmap_num2 = srcseg->sides[s].tmap_num2;
1231 destseg->static_light = srcseg->static_light;
1234 // _________________________________________________________________________________________________________________________
1235 // Maximum distance between a segment containing light to a segment to receive light.
1236 #define LIGHT_DISTANCE_THRESHOLD (F1_0*80)
1237 fix Magical_light_constant = (F1_0*16);
1244 sbyte flag, hit_type;
1248 #define FVI_HASH_SIZE 8
1249 #define FVI_HASH_AND_MASK (FVI_HASH_SIZE - 1)
1251 // Note: This should be malloced.
1252 // Also, the vector should not be 12 bytes, you should only care about some smaller portion of it.
1253 hash_info fvi_cache[FVI_HASH_SIZE];
1254 int Hash_hits=0, Hash_retries=0, Hash_calcs=0;
1256 // -----------------------------------------------------------------------------------------
1257 // Set light from a light source.
1258 // Light incident on a surface is defined by the light incident at its points.
1259 // Light at a point = K * (V . N) / d
1261 // K = some magical constant to make everything look good
1262 // V = normalized vector from light source to point
1263 // N = surface normal at point
1264 // d = distance from light source to point
1265 // (Note that the above equation can be simplified to K * (VV . N) / d^2 where VV = non-normalized V)
1266 // Light intensity emitted from a light source is defined to be cast from four points.
1267 // These four points are 1/64 of the way from the corners of the light source to the center
1268 // of its segment. By assuming light is cast from these points, rather than from on the
1269 // light surface itself, light will be properly cast on the light surface. Otherwise, the
1270 // vector V would be the null vector.
1271 // If quick_light set, then don't use find_vector_intersection
1272 void cast_light_from_side(segment *segp, int light_side, fix light_intensity, int quick_light)
1274 vms_vector segment_center;
1275 int segnum,sidenum,vertnum, lightnum;
1277 compute_segment_center(&segment_center, segp);
1279 //mprintf((0, "From [%i %i %7.3f]: ", segp-Segments, light_side, f2fl(light_intensity)));
1281 // Do for four lights, one just inside each corner of side containing light.
1282 for (lightnum=0; lightnum<4; lightnum++) {
1283 int light_vertex_num, i;
1284 vms_vector vector_to_center;
1285 vms_vector light_location;
1286 // fix inverse_segment_magnitude;
1288 light_vertex_num = segp->verts[Side_to_verts[light_side][lightnum]];
1289 light_location = Vertices[light_vertex_num];
1292 // New way, 5/8/95: Move towards center irrespective of size of segment.
1293 vm_vec_sub(&vector_to_center, &segment_center, &light_location);
1294 vm_vec_normalize_quick(&vector_to_center);
1295 vm_vec_add2(&light_location, &vector_to_center);
1297 // -- Old way, before 5/8/95 -- // -- This way was kind of dumb. In larger segments, you move LESS towards the center.
1298 // -- Old way, before 5/8/95 -- // Main problem, though, is vertices don't illuminate themselves well in oblong segments because the dot product is small.
1299 // -- Old way, before 5/8/95 -- vm_vec_sub(&vector_to_center, &segment_center, &light_location);
1300 // -- Old way, before 5/8/95 -- inverse_segment_magnitude = fixdiv(F1_0/5, vm_vec_mag(&vector_to_center));
1301 // -- Old way, before 5/8/95 -- vm_vec_scale_add(&light_location, &light_location, &vector_to_center, inverse_segment_magnitude);
1303 for (segnum=0; segnum<=Highest_segment_index; segnum++) {
1304 segment *rsegp = &Segments[segnum];
1305 vms_vector r_segment_center;
1308 for (i=0; i<FVI_HASH_SIZE; i++)
1309 fvi_cache[i].flag = 0;
1311 // efficiency hack (I hope!), for faraway segments, don't check each point.
1312 compute_segment_center(&r_segment_center, rsegp);
1313 dist_to_rseg = vm_vec_dist_quick(&r_segment_center, &segment_center);
1315 if (dist_to_rseg <= LIGHT_DISTANCE_THRESHOLD) {
1316 for (sidenum=0; sidenum<MAX_SIDES_PER_SEGMENT; sidenum++) {
1317 if (WALL_IS_DOORWAY(rsegp, sidenum) != WID_NO_WALL) {
1318 side *rsidep = &rsegp->sides[sidenum];
1319 vms_vector *side_normalp = &rsidep->normals[0]; // kinda stupid? always use vector 0.
1321 //mprintf((0, "[%i %i], ", rsegp-Segments, sidenum));
1322 for (vertnum=0; vertnum<4; vertnum++) {
1323 fix distance_to_point, light_at_point, light_dot;
1324 vms_vector vert_location, vector_to_light;
1327 abs_vertnum = rsegp->verts[Side_to_verts[sidenum][vertnum]];
1328 vert_location = Vertices[abs_vertnum];
1329 distance_to_point = vm_vec_dist_quick(&vert_location, &light_location);
1330 vm_vec_sub(&vector_to_light, &light_location, &vert_location);
1331 vm_vec_normalize(&vector_to_light);
1333 // Hack: In oblong segments, it's possible to get a very small dot product
1334 // but the light source is very nearby (eg, illuminating light itself!).
1335 light_dot = vm_vec_dot(&vector_to_light, side_normalp);
1336 if (distance_to_point < F1_0)
1338 light_dot = (light_dot + F1_0)/2;
1340 if (light_dot > 0) {
1341 light_at_point = fixdiv(fixmul(light_dot, light_dot), distance_to_point);
1342 light_at_point = fixmul(light_at_point, Magical_light_constant);
1343 if (light_at_point >= 0) {
1346 vms_vector vert_location_1, r_vector_to_center;
1347 fix inverse_segment_magnitude;
1349 vm_vec_sub(&r_vector_to_center, &r_segment_center, &vert_location);
1350 inverse_segment_magnitude = fixdiv(F1_0/3, vm_vec_mag(&r_vector_to_center));
1351 vm_vec_scale_add(&vert_location_1, &vert_location, &r_vector_to_center, inverse_segment_magnitude);
1352 vert_location = vert_location_1;
1354 //if ((segp-Segments == 199) && (rsegp-Segments==199))
1356 // Seg0 = segp-Segments;
1357 // Seg1 = rsegp-Segments;
1359 int hash_value = Side_to_verts[sidenum][vertnum];
1360 hash_info *hashp = &fvi_cache[hash_value];
1363 if ((hashp->vector.x == vector_to_light.x) && (hashp->vector.y == vector_to_light.y) && (hashp->vector.z == vector_to_light.z)) {
1364 //mprintf((0, "{CACHE %4x} ", hash_value));
1365 hit_type = hashp->hit_type;
1369 Int3(); // How is this possible? Should be no hits!
1371 hash_value = (hash_value+1) & FVI_HASH_AND_MASK;
1372 hashp = &fvi_cache[hash_value];
1375 //mprintf((0, "\nH:%04x ", hash_value));
1379 hashp->vector = vector_to_light;
1382 fq.p0 = &light_location;
1383 fq.startseg = segp-Segments;
1384 fq.p1 = &vert_location;
1387 fq.ignore_obj_list = NULL;
1390 hit_type = find_vector_intersection(&fq,&hit_data);
1391 hashp->hit_type = hit_type;
1396 hit_type = HIT_NONE;
1397 //mprintf((0, "hit=%i ", hit_type));
1400 light_at_point = fixmul(light_at_point, light_intensity);
1401 rsidep->uvls[vertnum].l += light_at_point;
1402 //mprintf((0, "(%5.2f) ", f2fl(light_at_point)));
1403 if (rsidep->uvls[vertnum].l > F1_0)
1404 rsidep->uvls[vertnum].l = F1_0;
1409 Int3(); // Hit object, should be ignoring objects!
1412 Int3(); // Ugh, this thing again, what happened, what does it mean?
1415 } // end if (light_at_point...
1416 } // end if (light_dot >...
1417 } // end for (vertnum=0...
1418 } // end if (rsegp...
1419 } // end for (sidenum=0...
1420 } // end if (dist_to_rseg...
1422 } // end for (segnum=0...
1424 } // end for (lightnum=0...
1426 //mprintf((0, "\n"));
1430 // ------------------------------------------------------------------------------------------
1431 // Zero all lighting values.
1432 void calim_zero_light_values(void)
1434 int segnum, sidenum, vertnum;
1436 for (segnum=0; segnum<=Highest_segment_index; segnum++) {
1437 segment *segp = &Segments[segnum];
1438 for (sidenum=0; sidenum<MAX_SIDES_PER_SEGMENT; sidenum++) {
1439 side *sidep = &segp->sides[sidenum];
1440 for (vertnum=0; vertnum<4; vertnum++)
1441 sidep->uvls[vertnum].l = F1_0/64; // Put a tiny bit of light here.
1443 Segments[segnum].static_light = F1_0/64;
1448 // ------------------------------------------------------------------------------------------
1449 // Used in setting average light value in a segment, cast light from a side to the center
1451 void cast_light_from_side_to_center(segment *segp, int light_side, fix light_intensity, int quick_light)
1453 vms_vector segment_center;
1454 int segnum, lightnum;
1456 compute_segment_center(&segment_center, segp);
1458 // Do for four lights, one just inside each corner of side containing light.
1459 for (lightnum=0; lightnum<4; lightnum++) {
1460 int light_vertex_num;
1461 vms_vector vector_to_center;
1462 vms_vector light_location;
1464 light_vertex_num = segp->verts[Side_to_verts[light_side][lightnum]];
1465 light_location = Vertices[light_vertex_num];
1466 vm_vec_sub(&vector_to_center, &segment_center, &light_location);
1467 vm_vec_scale_add(&light_location, &light_location, &vector_to_center, F1_0/64);
1469 for (segnum=0; segnum<=Highest_segment_index; segnum++) {
1470 segment *rsegp = &Segments[segnum];
1471 vms_vector r_segment_center;
1473 //if ((segp == &Segments[Bugseg]) && (rsegp == &Segments[Bugseg]))
1475 compute_segment_center(&r_segment_center, rsegp);
1476 dist_to_rseg = vm_vec_dist_quick(&r_segment_center, &segment_center);
1478 if (dist_to_rseg <= LIGHT_DISTANCE_THRESHOLD) {
1480 if (dist_to_rseg > F1_0)
1481 light_at_point = fixdiv(Magical_light_constant, dist_to_rseg);
1483 light_at_point = Magical_light_constant;
1485 if (light_at_point >= 0) {
1492 fq.p0 = &light_location;
1493 fq.startseg = segp-Segments;
1494 fq.p1 = &r_segment_center;
1497 fq.ignore_obj_list = NULL;
1500 hit_type = find_vector_intersection(&fq,&hit_data);
1503 hit_type = HIT_NONE;
1507 light_at_point = fixmul(light_at_point, light_intensity);
1508 if (light_at_point >= F1_0)
1509 light_at_point = F1_0-1;
1510 rsegp->static_light += light_at_point;
1511 if (segp->static_light < 0) // if it went negative, saturate
1512 segp->static_light = 0;
1517 Int3(); // Hit object, should be ignoring objects!
1520 Int3(); // Ugh, this thing again, what happened, what does it mean?
1523 } // end if (light_at_point...
1524 } // end if (dist_to_rseg...
1526 } // end for (segnum=0...
1528 } // end for (lightnum=0...
1532 // ------------------------------------------------------------------------------------------
1533 // Process all lights.
1534 void calim_process_all_lights(int quick_light)
1536 int segnum, sidenum;
1538 for (segnum=0; segnum<=Highest_segment_index; segnum++) {
1539 segment *segp = &Segments[segnum];
1541 for (sidenum=0; sidenum<MAX_SIDES_PER_SEGMENT; sidenum++) {
1542 // if (!IS_CHILD(segp->children[sidenum])) {
1543 if (WALL_IS_DOORWAY(segp, sidenum) != WID_NO_WALL) {
1544 side *sidep = &segp->sides[sidenum];
1545 fix light_intensity;
1547 light_intensity = TmapInfo[sidep->tmap_num].lighting + TmapInfo[sidep->tmap_num2 & 0x3fff].lighting;
1549 // if (segp->sides[sidenum].wall_num != -1) {
1550 // int wall_num, bitmap_num, effect_num;
1551 // wall_num = segp->sides[sidenum].wall_num;
1552 // effect_num = Walls[wall_num].type;
1553 // bitmap_num = effects_bm_num[effect_num];
1555 // light_intensity += TmapInfo[bitmap_num].lighting;
1558 if (light_intensity) {
1559 light_intensity /= 4; // casting light from four spots, so divide by 4.
1560 cast_light_from_side(segp, sidenum, light_intensity, quick_light);
1561 cast_light_from_side_to_center(segp, sidenum, light_intensity, quick_light);
1568 // ------------------------------------------------------------------------------------------
1569 // Apply static light in mine.
1570 // First, zero all light values.
1571 // Then, for all light sources, cast their light.
1572 void cast_all_light_in_mine(int quick_flag)
1575 validate_segment_all();
1577 calim_zero_light_values();
1579 calim_process_all_lights(quick_flag);
1583 // int Fvit_num = 1000;
1585 // fix find_vector_intersection_test(void)
1588 // fvi_info hit_data;
1589 // int p0_seg, p1_seg, this_objnum, ignore_obj, check_obj_flag;
1591 // int start_time = timer_get_milliseconds();;
1592 // vms_vector p0,p1;
1595 // check_obj_flag = 0;
1596 // this_objnum = -1;
1599 // for (i=0; i<Fvit_num; i++) {
1600 // p0_seg = d_rand()*(Highest_segment_index+1)/32768;
1601 // compute_segment_center(&p0, &Segments[p0_seg]);
1603 // p1_seg = d_rand()*(Highest_segment_index+1)/32768;
1604 // compute_segment_center(&p1, &Segments[p1_seg]);
1606 // find_vector_intersection(&hit_data, &p0, p0_seg, &p1, rad, this_objnum, ignore_obj, check_obj_flag);
1609 // return timer_get_milliseconds() - start_time;
1612 vms_vector Normals[MAX_SEGMENTS*12];
1614 int Normal_nearness = 4;
1616 int normal_near(vms_vector *v1, vms_vector *v2)
1618 if (abs(v1->x - v2->x) < Normal_nearness)
1619 if (abs(v1->y - v2->y) < Normal_nearness)
1620 if (abs(v1->z - v2->z) < Normal_nearness)
1625 int Total_normals=0;
1628 void print_normals(void)
1631 // vms_vector *normal;
1637 for (i=0; i<=Highest_segment_index; i++)
1638 for (s=0; s<6; s++) {
1639 if (Segments[i].sides[s].type == SIDE_IS_QUAD)
1643 for (n=0; n<nn; n++) {
1644 for (j=0; j<num_normals; j++)
1645 if (normal_near(&Segments[i].sides[s].normals[n],&Normals[j]))
1647 if (j == num_normals) {
1648 Normals[num_normals++] = Segments[i].sides[s].normals[n];