/* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * $Source: /cvsroot/dxx-rebirth/d1x-rebirth/editor/seguvs.c,v $ * $Revision: 1.1.1.1 $ * $Author: zicodxx $ * $Date: 2006/03/17 19:45:42 $ * * u,v coordinate computation for segment faces * * $Log: seguvs.c,v $ * Revision 1.1.1.1 2006/03/17 19:45:42 zicodxx * initial import * * Revision 1.1.1.1 1999/06/14 22:04:31 donut * Import of d1x 1.37 source. * * Revision 2.1 1995/05/08 10:49:34 mike * fix lighting bug: oblong segments could be very dark. * * Revision 2.0 1995/02/27 11:36:37 john * Version 2.0. Ansi-fied. * * Revision 1.84 1994/11/27 23:17:18 matt * Made changes for new mprintf calling convention * * Revision 1.83 1994/11/17 14:48:02 mike * validation functions moved from editor to game. * * Revision 1.82 1994/10/15 19:08:26 mike * Disable exhaustive search mprintfs in find_point_seg during lighting. * * Revision 1.81 1994/08/25 21:55:50 mike * IS_CHILD stuff. * * Revision 1.80 1994/08/04 19:13:22 matt * Changed a bunch of vecmat calls to use multiple-function routines, and to * allow the use of C macros for some functions * * Revision 1.79 1994/08/03 10:31:33 mike * Texture map propagation without uv assignment. * * Revision 1.78 1994/08/01 13:31:12 matt * Made fvi() check holes in transparent walls, and changed fvi() calling * parms to take all input data in query structure. * * Revision 1.77 1994/07/08 14:31:24 matt * New parms for FVI * * Revision 1.76 1994/06/23 14:01:04 mike * Fix cache bug which caused some vertices to not get light, mainly * noticeable at joints which had doors. * * Revision 1.75 1994/06/22 17:33:11 mike * Make position of light (which is always towards center of segment from * actual light panel) constant, not dependent on segment size, which fixes * bug of dark light panels in very large segments. * * Revision 1.74 1994/06/21 18:58:18 mike * Fix stupid bug in light propagation, was using wrong vector in fvi caching. * * Revision 1.73 1994/06/20 11:20:24 mike * Fix stupid lighting bug introduced when I went to cached fvi results. * * Revision 1.72 1994/06/19 16:26:37 mike * Speed up lighting by storing and hashing fvi results. * * Revision 1.71 1994/06/17 16:05:56 mike * Support optional quick lighting propagation: no find_vector_intersection. * * Revision 1.70 1994/06/15 15:42:30 mike * Propagate static_light. * * Revision 1.69 1994/06/14 16:59:37 mike * Fix references to tmap_num2, must strip off orientation bits. * * Revision 1.68 1994/06/09 09:58:58 matt * Moved find_vector_intersection() from physics.c to new file fvi.c * * * Revision 1.67 1994/06/08 18:14:02 mike * mprintf a dot in light casting. * * Revision 1.66 1994/06/08 14:37:45 mike * double static light value in going from value (a short) to static_light (a fix). * * Revision 1.65 1994/06/08 14:29:44 matt * Added static_light field to segment structure, and padded side struct * to be longword aligned. * * Revision 1.64 1994/06/08 11:45:24 mike * New, supercool, superslow lighting function. * * Revision 1.63 1994/06/07 09:38:11 mike * Make lighting function yet better by calling find_vector_intersection. * * Revision 1.62 1994/06/06 13:14:33 mike * Make illusory walls cast light. * * Revision 1.61 1994/06/05 20:39:47 mike * Add new distance and dot product based lighting function. * * Revision 1.60 1994/05/31 12:31:18 mike * fix bugs in lighting, though it's not perfect, will be changing all * lighting to be distance based. Bug had to do with not handling one * of the return values from WALL_IS_DOORWAY, so assuming light couldn't * be recursively propagated almost all the time. * * Revision 1.59 1994/05/19 23:35:26 mike * Support uv coordinates in range 0..1.0. * * Revision 1.58 1994/05/19 12:10:21 matt * Use new vecmat macros and globals * * Revision 1.57 1994/05/04 19:15:53 mike * Error checking for degenerate segments. * * Revision 1.56 1994/05/03 11:02:34 mike * Change how default texture map assignment works; now pixels are constant size. * * Revision 1.55 1994/04/28 23:25:26 yuan * Obliterated warnings. * */ #ifdef RCS static char rcsid[] = "$Id: seguvs.c,v 1.1.1.1 2006/03/17 19:45:42 zicodxx Exp $"; #endif #include #include #include #include #include #include "inferno.h" #include "segment.h" #include "editor/editor.h" #include "gameseg.h" #include "fix.h" #include "mono.h" #include "error.h" #include "wall.h" #include "editor/kdefs.h" #include "bm.h" // Needed for TmapInfo #include "effects.h" // Needed for effects_bm_num #include "fvi.h" void cast_all_light_in_mine(int quick_flag); //--rotate_uvs-- vms_vector Rightvec; // --------------------------------------------------------------------------------------------- // Returns approximate area of a side fix area_on_side(side *sidep) { fix du,dv,width,height; du = sidep->uvls[1].u - sidep->uvls[0].u; dv = sidep->uvls[1].v - sidep->uvls[0].v; width = fix_sqrt(fixmul(du,du) + fixmul(dv,dv)); du = sidep->uvls[3].u - sidep->uvls[0].u; dv = sidep->uvls[3].v - sidep->uvls[0].v; height = fix_sqrt(fixmul(du,du) + fixmul(dv,dv)); return fixmul(width, height); } // ------------------------------------------------------------------------------------------- // DEBUG function -- callable from debugger. // Returns approximate area of all sides which get mapped (ie, are not a connection). // I wrote this because I was curious how much memory would be required to texture map all // sides individually with custom artwork. For demo1.min on 2/18/94, it would be about 5 meg. int area_on_all_sides(void) { int i,s; int total_area = 0; for (i=0; i<=Highest_segment_index; i++) { segment *segp = &Segments[i]; for (s=0; schildren[s])) total_area += f2i(area_on_side(&segp->sides[s])); } return total_area; } fix average_connectivity(void) { int i,s; int total_sides = 0, total_mapped_sides = 0; for (i=0; i<=Highest_segment_index; i++) { segment *segp = &Segments[i]; for (s=0; schildren[s])) total_mapped_sides++; total_sides++; } } return 6 * fixdiv(total_mapped_sides, total_sides); } #define MAX_LIGHT_SEGS 16 // --------------------------------------------------------------------------------------------- // Scan all polys in all segments, return average light value for vnum. // segs = output array for segments containing vertex, terminated by -1. fix get_average_light_at_vertex(int vnum, short *segs) { int segnum, relvnum, sidenum; fix total_light; int num_occurrences; // #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 short *original_segs; original_segs = segs; // #endif num_occurrences = 0; total_light = 0; for (segnum=0; segnum<=Highest_segment_index; segnum++) { segment *segp = &Segments[segnum]; short *vp = segp->verts; for (relvnum=0; relvnumchildren[sidenum])) { side *sidep = &segp->sides[sidenum]; sbyte *vp = Side_to_verts[sidenum]; int v; for (v=0; v<4; v++) if (*vp++ == relvnum) { total_light += sidep->uvls[v].l; num_occurrences++; } } // end if } // end sidenum } } // end segnum *segs = -1; if (num_occurrences) return total_light/num_occurrences; else return 0; } void set_average_light_at_vertex(int vnum) { int relvnum, sidenum; short Segment_indices[MAX_LIGHT_SEGS]; int segind; fix average_light; average_light = get_average_light_at_vertex(vnum, Segment_indices); if (!average_light) return; segind = 0; while (Segment_indices[segind] != -1) { int segnum = Segment_indices[segind++]; segment *segp = &Segments[segnum]; for (relvnum=0; relvnumverts[relvnum] == vnum) break; if (relvnum < MAX_VERTICES_PER_SEGMENT) { for (sidenum=0; sidenum < MAX_SIDES_PER_SEGMENT; sidenum++) { if (!IS_CHILD(segp->children[sidenum])) { side *sidep = &segp->sides[sidenum]; sbyte *vp = Side_to_verts[sidenum]; int v; for (v=0; v<4; v++) if (*vp++ == relvnum) sidep->uvls[v].l = average_light; } // end if } // end sidenum } // end if } // end while Update_flags |= UF_WORLD_CHANGED; } void set_average_light_on_side(segment *segp, int sidenum) { int v; if (!IS_CHILD(segp->children[sidenum])) for (v=0; v<4; v++) { // mprintf((0,"Vertex %i\n", segp->verts[Side_to_verts[side][v]])); set_average_light_at_vertex(segp->verts[Side_to_verts[sidenum][v]]); } } int set_average_light_on_curside(void) { set_average_light_on_side(Cursegp, Curside); return 0; } // ----------------------------------------------------------------------------------------- void set_average_light_on_all_fast(void) { int s,v,relvnum; fix al; int alc; int seglist[MAX_LIGHT_SEGS]; int *segptr; set_vertex_counts(); // Set total light value for all vertices in array average_light. for (v=0; v<=Highest_vertex_index; v++) { al = 0; alc = 0; if (Vertex_active[v]) { segptr = seglist; for (s=0; s<=Highest_segment_index; s++) { segment *segp = &Segments[s]; for (relvnum=0; relvnumverts[relvnum] == v) break; if (relvnum != MAX_VERTICES_PER_SEGMENT) { int si; *segptr++ = s; // Note this segment in list, so we can process it below. Assert(segptr - seglist < MAX_LIGHT_SEGS); for (si=0; sichildren[si])) { side *sidep = &segp->sides[si]; sbyte *vp = Side_to_verts[si]; int vv; for (vv=0; vv<4; vv++) if (*vp++ == relvnum) { al += sidep->uvls[vv].l; alc++; } } // if (segp->children[si == -1) { } // for (si=0... } // if (relvnum != ... } // for (s=0; ... *segptr = -1; // Now, divide average_light by number of number of occurrences for each vertex if (alc) al /= alc; else al = 0; segptr = seglist; while (*segptr != -1) { int segnum = *segptr++; segment *segp = &Segments[segnum]; int sidenum; for (relvnum=0; relvnumverts[relvnum] == v) break; Assert(relvnum < MAX_VERTICES_PER_SEGMENT); // IMPOSSIBLE! This segment is in seglist, but vertex v does not occur! for (sidenum=0; sidenum < MAX_SIDES_PER_SEGMENT; sidenum++) { int wid_result; wid_result = WALL_IS_DOORWAY(segp, sidenum); if ((wid_result != WID_FLY_FLAG) && (wid_result != WID_NO_WALL)) { side *sidep = &segp->sides[sidenum]; sbyte *vp = Side_to_verts[sidenum]; int v; for (v=0; v<4; v++) if (*vp++ == relvnum) sidep->uvls[v].l = al; } // end if } // end sidenum } // end while } // if (Vertex_active[v]... } // for (v=0... } extern int Doing_lighting_hack_flag; // If set, don't mprintf warning messages in gameseg.c/find_point_seg int set_average_light_on_all(void) { // set_average_light_on_all_fast(); Doing_lighting_hack_flag = 1; cast_all_light_in_mine(0); Doing_lighting_hack_flag = 0; Update_flags |= UF_WORLD_CHANGED; // int seg, side; // for (seg=0; seg<=Highest_segment_index; seg++) // for (side=0; sideu; v0.y = 0; v0.z = uv0->v; v1.x = uv1->u; v1.y = 0; v1.z = uv1->v; return vm_vec_dist(&v0,&v1); } // --------------------------------------------------------------------------------------------- // Given a polygon, compress the uv coordinates so that they are as close to 0 as possible. // Do this by adding a constant u and v to each uv pair. void compress_uv_coordinates(side *sidep) { int v; fix uc, vc; uc = 0; vc = 0; for (v=0; v<4; v++) { uc += sidep->uvls[v].u; vc += sidep->uvls[v].v; } uc /= 4; vc /= 4; uc = uc & 0xffff0000; vc = vc & 0xffff0000; for (v=0; v<4; v++) { sidep->uvls[v].u -= uc; sidep->uvls[v].v -= vc; } } // --------------------------------------------------------------------------------------------- void compress_uv_coordinates_on_side(side *sidep) { compress_uv_coordinates(sidep); } // --------------------------------------------------------------------------------------------- void validate_uv_coordinates_on_side(segment *segp, int sidenum) { // int v; // fix uv_dist,threed_dist; // vms_vector tvec; // fix dist_ratios[MAX_VERTICES_PER_POLY]; side *sidep = &segp->sides[sidenum]; // byte *vp = Side_to_verts[sidenum]; // This next hunk doesn't seem to affect anything. @mk, 02/13/94 // for (v=1; v<4; v++) { // uv_dist = compute_uv_dist(&sidep->uvls[v],&sidep->uvls[0]); // threed_dist = vm_vec_mag(vm_vec_sub(&tvec,&Vertices[segp->verts[vp[v]],&Vertices[vp[0]])); // dist_ratios[v-1] = fixdiv(uv_dist,threed_dist); // } compress_uv_coordinates_on_side(sidep); } void compress_uv_coordinates_in_segment(segment *segp) { int side; for (side=0; sidesides[side]); } void compress_uv_coordinates_all(void) { int seg; for (seg=0; seg<=Highest_segment_index; seg++) if (Segments[seg].segnum != -1) compress_uv_coordinates_in_segment(&Segments[seg]); } void check_lighting_side(segment *sp, int sidenum) { int v; side *sidep = &sp->sides[sidenum]; for (v=0; v<4; v++) if ((sidep->uvls[v].l > F1_0*16) || (sidep->uvls[v].l < 0)) Int3(); //mprintf(0,"Bogus lighting value in segment %i, side %i, vert %i = %x\n",sp-Segments, side, v, sidep->uvls[v].l); } void check_lighting_segment(segment *segp) { int side; for (side=0; sidesides[sidenum]; for (v=0; v<4; v++) sidep->uvls[v].l = DEFAULT_LIGHTING; } void assign_default_lighting(segment *segp) { int sidenum; for (sidenum=0; sidenumsides[sidenum]; for (v=0; v<4; v++) sidep->uvls[v] = uvls[v]; } #ifdef __WATCOMC__ fix zhypot(fix a,fix b); #pragma aux zhypot parm [eax] [ebx] value [eax] modify [eax ebx ecx edx] = \ "imul eax" \ "xchg eax,ebx" \ "mov ecx,edx" \ "imul eax" \ "add eax,ebx" \ "adc edx,ecx" \ "call quad_sqrt"; #else fix zhypot(fix a,fix b) { double x = (double)a / 65536; double y = (double)b / 65536; return (long)(sqrt(x * x + y * y) * 65536); } #endif // --------------------------------------------------------------------------------------------- // Assign lighting value to side, a function of the normal vector. void assign_light_to_side(segment *sp, int sidenum) { int v; side *sidep = &sp->sides[sidenum]; for (v=0; v<4; v++) sidep->uvls[v].l = DEFAULT_LIGHTING; } fix Stretch_scale_x = F1_0; fix Stretch_scale_y = F1_0; // --------------------------------------------------------------------------------------------- // Given u,v coordinates at two vertices, assign u,v coordinates to other two vertices on a side. // (Actually, assign them to the coordinates in the faces.) // va, vb = face-relative vertex indices corresponding to uva, uvb. Ie, they are always in 0..3 and should be looked up in // Side_to_verts[side] to get the segment relative index. void assign_uvs_to_side(segment *segp, int sidenum, uvl *uva, uvl *uvb, int va, int vb) { int vlo,vhi,v0,v1,v2,v3; vms_vector fvec,rvec,tvec; vms_matrix rotmat; uvl uvls[4],ruvmag,fuvmag,uvlo,uvhi; fix fmag,mag01; sbyte *vp; Assert( (va<4) && (vb<4) ); Assert((abs(va - vb) == 1) || (abs(va - vb) == 3)); // make sure the verticies specify an edge vp = (sbyte *)&Side_to_verts[sidenum]; // We want vlo precedes vhi, ie vlo < vhi, or vlo = 3, vhi = 0 if (va == ((vb + 1) % 4)) { // va = vb + 1 vlo = vb; vhi = va; uvlo = *uvb; uvhi = *uva; } else { vlo = va; vhi = vb; uvlo = *uva; uvhi = *uvb; } Assert(((vlo+1) % 4) == vhi); // If we are on an edge, then uvhi is one more than uvlo (mod 4) uvls[vlo] = uvlo; uvls[vhi] = uvhi; // Now we have vlo precedes vhi, compute vertices ((vhi+1) % 4) and ((vhi+2) % 4) // Assign u,v scale to a unit length right vector. fmag = zhypot(uvhi.v - uvlo.v,uvhi.u - uvlo.u); if (fmag < 64) { // this is a fix, so 64 = 1/1024 mprintf((0,"Warning: fmag = %7.3f, using approximate u,v values\n",f2fl(fmag))); ruvmag.u = F1_0*256; ruvmag.v = F1_0*256; fuvmag.u = F1_0*256; fuvmag.v = F1_0*256; } else { ruvmag.u = uvhi.v - uvlo.v; ruvmag.v = uvlo.u - uvhi.u; fuvmag.u = uvhi.u - uvlo.u; fuvmag.v = uvhi.v - uvlo.v; } v0 = segp->verts[vp[vlo]]; v1 = segp->verts[vp[vhi]]; v2 = segp->verts[vp[(vhi+1)%4]]; v3 = segp->verts[vp[(vhi+2)%4]]; // Compute right vector by computing orientation matrix from: // forward vector = vlo:vhi // right vector = vlo:(vhi+2) % 4 vm_vec_sub(&fvec,&Vertices[v1],&Vertices[v0]); vm_vec_sub(&rvec,&Vertices[v3],&Vertices[v0]); if (((fvec.x == 0) && (fvec.y == 0) && (fvec.z == 0)) || ((rvec.x == 0) && (rvec.y == 0) && (rvec.z == 0))) { mprintf((1, "Trapped null vector in assign_uvs_to_side, using identity matrix.\n")); rotmat = vmd_identity_matrix; } else vm_vector_2_matrix(&rotmat,&fvec,0,&rvec); rvec = rotmat.rvec; vm_vec_negate(&rvec); fvec = rotmat.fvec; // mprintf((0, "va = %i, vb = %i\n", va, vb)); mag01 = vm_vec_dist(&Vertices[v1],&Vertices[v0]); if ((va == 0) || (va == 2)) mag01 = fixmul(mag01, Stretch_scale_x); else mag01 = fixmul(mag01, Stretch_scale_y); if (mag01 < F1_0/1024 ) editor_status("U, V bogosity in segment #%i, probably on side #%i. CLEAN UP YOUR MESS!", segp-Segments, sidenum); else { vm_vec_sub(&tvec,&Vertices[v2],&Vertices[v1]); uvls[(vhi+1)%4].u = uvhi.u + fixdiv(fixmul(ruvmag.u,vm_vec_dotprod(&rvec,&tvec)),mag01) + fixdiv(fixmul(fuvmag.u,vm_vec_dotprod(&fvec,&tvec)),mag01); uvls[(vhi+1)%4].v = uvhi.v + fixdiv(fixmul(ruvmag.v,vm_vec_dotprod(&rvec,&tvec)),mag01) + fixdiv(fixmul(fuvmag.v,vm_vec_dotprod(&fvec,&tvec)),mag01); vm_vec_sub(&tvec,&Vertices[v3],&Vertices[v0]); uvls[(vhi+2)%4].u = uvlo.u + fixdiv(fixmul(ruvmag.u,vm_vec_dotprod(&rvec,&tvec)),mag01) + fixdiv(fixmul(fuvmag.u,vm_vec_dotprod(&fvec,&tvec)),mag01); uvls[(vhi+2)%4].v = uvlo.v + fixdiv(fixmul(ruvmag.v,vm_vec_dotprod(&rvec,&tvec)),mag01) + fixdiv(fixmul(fuvmag.v,vm_vec_dotprod(&fvec,&tvec)),mag01); uvls[(vhi+1)%4].l = uvhi.l; uvls[(vhi+2)%4].l = uvlo.l; copy_uvs_from_side_to_faces(segp, sidenum, uvls); } } int Vmag = VMAG; // ----------------------------------------------------------------------------------------------------------- // Assign default uvs to side. // This means: // v0 = 0,0 // v1 = k,0 where k is 3d size dependent // v2, v3 assigned by assign_uvs_to_side void assign_default_uvs_to_side(segment *segp,int side) { uvl uv0,uv1; sbyte *vp; uv0.u = 0; uv0.v = 0; vp = Side_to_verts[side]; uv1.u = 0; uv1.v = Num_tilings * fixmul(Vmag, vm_vec_dist(&Vertices[segp->verts[vp[1]]],&Vertices[segp->verts[vp[0]]])); assign_uvs_to_side(segp, side, &uv0, &uv1, 0, 1); } // ----------------------------------------------------------------------------------------------------------- // Assign default uvs to side. // This means: // v0 = 0,0 // v1 = k,0 where k is 3d size dependent // v2, v3 assigned by assign_uvs_to_side void stretch_uvs_from_curedge(segment *segp, int side) { uvl uv0,uv1; int v0, v1; v0 = Curedge; v1 = (v0 + 1) % 4; uv0.u = segp->sides[side].uvls[v0].u; uv0.v = segp->sides[side].uvls[v0].v; uv1.u = segp->sides[side].uvls[v1].u; uv1.v = segp->sides[side].uvls[v1].v; assign_uvs_to_side(segp, side, &uv0, &uv1, v0, v1); } // -------------------------------------------------------------------------------------------------------------- // Assign default uvs to a segment. void assign_default_uvs_to_segment(segment *segp) { int s; for (s=0; ssides[base_common_side].num_faces; f++) { // -- mk021394 -- face *fp = &base_seg->sides[base_common_side].faces[f]; // -- mk021394 -- for (p=0; pnum_polys; p++) { // -- mk021394 -- poly *pp = &fp->polys[p]; // -- mk021394 -- for (v=0; vnum_vertices; v++) // -- mk021394 -- if (pp->verts[v] == v1) { // -- mk021394 -- *ff = f; // -- mk021394 -- *vv = v; // -- mk021394 -- *pi = p; // -- mk021394 -- return; // -- mk021394 -- } // -- mk021394 -- } // -- mk021394 -- } // -- mk021394 -- // -- mk021394 -- Assert(0); // Error -- Couldn't find face:vertex which matched vertex v1 on base_seg:base_common_side // -- mk021394 -- } // -- mk021394 -- // -------------------------------------------------------------------------------------------------------------- // -- mk021394 -- // Find the vertex index in base_seg:base_common_side which is segment relative vertex v1 // -- mk021394 -- // This very specific routine is subsidiary to med_assign_uvs_to_side. // -- mk021394 -- void get_side_vert(segment *base_seg,int base_common_side,int v1,int *vv) // -- mk021394 -- { // -- mk021394 -- int p,f,v; // -- mk021394 -- // -- mk021394 -- Assert((base_seg->sides[base_common_side].tri_edge == 0) || (base_seg->sides[base_common_side].tri_edge == 1)); // -- mk021394 -- Assert(base_seg->sides[base_common_side].num_faces <= 2); // -- mk021394 -- // -- mk021394 -- for (f=0; fsides[base_common_side].num_faces; f++) { // -- mk021394 -- face *fp = &base_seg->sides[base_common_side].faces[f]; // -- mk021394 -- for (p=0; pnum_polys; p++) { // -- mk021394 -- poly *pp = &fp->polys[p]; // -- mk021394 -- for (v=0; vnum_vertices; v++) // -- mk021394 -- if (pp->verts[v] == v1) { // -- mk021394 -- if (pp->num_vertices == 4) { // -- mk021394 -- *vv = v; // -- mk021394 -- return; // -- mk021394 -- } // -- mk021394 -- // -- 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 // -- mk021394 -- if ((f == 1) && (v > 0)) // -- mk021394 -- v++; // -- mk021394 -- *vv = v; // -- mk021394 -- return; // -- mk021394 -- } else { // triangulated 013, 123 // -- mk021394 -- if (f == 0) { // -- mk021394 -- if (v == 2) // -- mk021394 -- v++; // -- mk021394 -- } else // -- mk021394 -- v++; // -- mk021394 -- *vv = v; // -- mk021394 -- return; // -- mk021394 -- } // -- mk021394 -- } // -- mk021394 -- } // -- mk021394 -- } // -- mk021394 -- // -- mk021394 -- Assert(0); // Error -- Couldn't find face:vertex which matched vertex v1 on base_seg:base_common_side // -- mk021394 -- } //--rotate_uvs-- // -------------------------------------------------------------------------------------------------------------- //--rotate_uvs-- // Rotate uvl coordinates uva, uvb about their center point by heading //--rotate_uvs-- void rotate_uvs(uvl *uva, uvl *uvb, vms_vector *rvec) //--rotate_uvs-- { //--rotate_uvs-- uvl uvc, uva1, uvb1; //--rotate_uvs-- //--rotate_uvs-- uvc.u = (uva->u + uvb->u)/2; //--rotate_uvs-- uvc.v = (uva->v + uvb->v)/2; //--rotate_uvs-- //--rotate_uvs-- uva1.u = fixmul(uva->u - uvc.u, rvec->x) - fixmul(uva->v - uvc.v, rvec->z); //--rotate_uvs-- uva1.v = fixmul(uva->u - uvc.u, rvec->z) + fixmul(uva->v - uvc.v, rvec->x); //--rotate_uvs-- //--rotate_uvs-- uva->u = uva1.u + uvc.u; //--rotate_uvs-- uva->v = uva1.v + uvc.v; //--rotate_uvs-- //--rotate_uvs-- uvb1.u = fixmul(uvb->u - uvc.u, rvec->x) - fixmul(uvb->v - uvc.v, rvec->z); //--rotate_uvs-- uvb1.v = fixmul(uvb->u - uvc.u, rvec->z) + fixmul(uvb->v - uvc.v, rvec->x); //--rotate_uvs-- //--rotate_uvs-- uvb->u = uvb1.u + uvc.u; //--rotate_uvs-- uvb->v = uvb1.v + uvc.v; //--rotate_uvs-- } // -------------------------------------------------------------------------------------------------------------- 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) { uvl uv1,uv2; int v,bv1,bv2, vv1, vv2; int cv1=0, cv2=0; bv1 = -1; bv2 = -1; // Find which vertices in segment match abs_id1, abs_id2 for (v=0; vverts[v] == abs_id1) bv1 = v; if (base_seg->verts[v] == abs_id2) bv2 = v; if (con_seg->verts[v] == abs_id1) cv1 = v; if (con_seg->verts[v] == abs_id2) cv2 = v; } // Now, bv1, bv2 are segment relative vertices in base segment which are the same as absolute vertices abs_id1, abs_id2 // cv1, cv2 are segment relative vertices in conn segment which are the same as absolute vertices abs_id1, abs_id2 Assert((bv1 != -1) && (bv2 != -1) && (cv1 != -1) && (cv2 != -1)); Assert((uv1.u != uv2.u) || (uv1.v != uv2.v)); // Now, scan 4 vertices in base side and 4 vertices in connected side. // Set uv1, uv2 to uv coordinates from base side which correspond to vertices bv1, bv2. // Set vv1, vv2 to relative vertex ids (in 0..3) in connecting side which correspond to cv1, cv2 vv1 = -1; vv2 = -1; for (v=0; v<4; v++) { if (bv1 == Side_to_verts[base_common_side][v]) uv1 = base_seg->sides[base_common_side].uvls[v]; if (bv2 == Side_to_verts[base_common_side][v]) uv2 = base_seg->sides[base_common_side].uvls[v]; if (cv1 == Side_to_verts[con_common_side][v]) vv1 = v; if (cv2 == Side_to_verts[con_common_side][v]) vv2 = v; } Assert( (vv1 != -1) && (vv2 != -1) ); assign_uvs_to_side(con_seg, con_common_side, &uv1, &uv2, vv1, vv2); } // ----------------------------------------------------------------------------- // Given a base and a connecting segment, a side on each of those segments and two global vertex ids, // determine which side in each of the segments shares those two vertices. // This is used to propagate a texture map id to a connecting segment in an expected and desired way. // Since we can attach any side of a segment to any side of another segment, and do so in each case in // four different rotations (for a total of 6*6*4 = 144 ways), not having this nifty function will cause // great confusion. 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) { sbyte *base_vp,*con_vp; int v0,side; *base_common_side = -1; // Find side in base segment which contains the two global vertex ids. for (side=0; sideverts[(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))) { Assert(*base_common_side == -1); // This means two different sides shared the same edge with base_side == impossible! *base_common_side = side; } } } // Note: For connecting segment, process vertices in reversed order. *con_common_side = -1; // Find side in connecting segment which contains the two global vertex ids. for (side=0; sideverts[(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))) { Assert(*con_common_side == -1); // This means two different sides shared the same edge with con_side == impossible! *con_common_side = side; } } } // mprintf((0,"side %3i adjacent to side %3i\n",*base_common_side,*con_common_side)); Assert((*base_common_side != -1) && (*con_common_side != -1)); } // ----------------------------------------------------------------------------- // Propagate texture map u,v coordinates from base_seg:base_side to con_seg:con_side. // The two vertices abs_id1 and abs_id2 are the only two vertices common to the two sides. // If uv_only_flag is 1, then don't assign texture map ids, only update the uv coordinates // If uv_only_flag is -1, then ONLY assign texture map ids, don't update the uv coordinates 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) { int base_common_side,con_common_side; int tmap_num; Assert ((uv_only_flag == -1) || (uv_only_flag == 0) || (uv_only_flag == 1)); // Set base_common_side = side in base_seg which contains edge abs_id1:abs_id2 // Set con_common_side = side in con_seg which contains edge abs_id1:abs_id2 if (base_seg != con_seg) get_side_ids(base_seg, con_seg, base_side, con_side, abs_id1, abs_id2, &base_common_side, &con_common_side); else { base_common_side = base_side; con_common_side = con_side; } // Now, all faces in con_seg which are on side con_common_side get their tmap_num set to whatever tmap is assigned // to whatever face I find which is on side base_common_side. // First, find tmap_num for base_common_side. If it doesn't exist (ie, there is a connection there), look at the segment // that is connected through it. if (!IS_CHILD(con_seg->children[con_common_side])) { if (!IS_CHILD(base_seg->children[base_common_side])) { // There is at least one face here, so get the tmap_num from there. tmap_num = base_seg->sides[base_common_side].tmap_num; // Now assign all faces in the connecting segment on side con_common_side to tmap_num. if ((uv_only_flag == -1) || (uv_only_flag == 0)) con_seg->sides[con_common_side].tmap_num = tmap_num; if (uv_only_flag != -1) med_assign_uvs_to_side(con_seg, con_common_side, base_seg, base_common_side, abs_id1, abs_id2); } else { // There are no faces here, there is a connection, trace through the connection. int cside; cside = find_connect_side(base_seg, &Segments[base_seg->children[base_common_side]]); propagate_tmaps_to_segment_side(&Segments[base_seg->children[base_common_side]], cside, con_seg, con_side, abs_id1, abs_id2, uv_only_flag); } } } sbyte Edge_between_sides[MAX_SIDES_PER_SEGMENT][MAX_SIDES_PER_SEGMENT][2] = { // left top right bottom back front { {-1,-1}, { 3, 7}, {-1,-1}, { 2, 6}, { 6, 7}, { 2, 3} }, // left { { 3, 7}, {-1,-1}, { 0, 4}, {-1,-1}, { 4, 7}, { 0, 3} }, // top { {-1,-1}, { 0, 4}, {-1,-1}, { 1, 5}, { 4, 5}, { 0, 1} }, // right { { 2, 6}, {-1,-1}, { 1, 5}, {-1,-1}, { 5, 6}, { 1, 2} }, // bottom { { 6, 7}, { 4, 7}, { 4, 5}, { 5, 6}, {-1,-1}, {-1,-1} }, // back { { 2, 3}, { 0, 3}, { 0, 1}, { 1, 2}, {-1,-1}, {-1,-1} }}; // front // ----------------------------------------------------------------------------- // Propagate texture map u,v coordinates to base_seg:back_side from base_seg:some-other-side // 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. void med_propagate_tmaps_to_back_side(segment *base_seg, int back_side, int uv_only_flag) { int v1=0,v2=0; int s,ss,tmap_num,back_side_tmap; if (IS_CHILD(base_seg->children[back_side])) return; // connection, so no sides here. // Scan all sides, look for an occupied side which is not back_side or Side_opposite[back_side] for (s=0; sverts[v1], base_seg->verts[v2], uv_only_flag); // Assign an unused tmap id to the back side. // 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 // both do attaches). // First see if tmap on back side is anywhere else. if (!uv_only_flag) { back_side_tmap = base_seg->sides[back_side].tmap_num; for (s=0; ssides[s].tmap_num == back_side_tmap) { for (tmap_num=0; tmap_num < MAX_SIDES_PER_SEGMENT; tmap_num++) { for (ss=0; sssides[ss].tmap_num == New_segment.sides[tmap_num].tmap_num) goto found2; // current texture map (tmap_num) is used on current (ss) side, so try next one // Current texture map (tmap_num) has not been used, assign to all faces on back_side. base_seg->sides[back_side].tmap_num = New_segment.sides[tmap_num].tmap_num; goto done1; found2: ; } } } done1: ; } } int fix_bogus_uvs_on_side(void) { med_propagate_tmaps_to_back_side(Cursegp, Curside, 1); return 0; } void fix_bogus_uvs_on_side1(segment *sp, int sidenum, int uvonly_flag) { side *sidep = &sp->sides[sidenum]; if ((sidep->uvls[0].u == 0) && (sidep->uvls[1].u == 0) && (sidep->uvls[2].u == 0)) { mprintf((0,"Found bogus segment %i, side %i\n", sp-Segments, sidenum)); med_propagate_tmaps_to_back_side(sp, sidenum, uvonly_flag); } } void fix_bogus_uvs_seg(segment *segp) { int s; for (s=0; schildren[s])) fix_bogus_uvs_on_side1(segp, s, 1); } } int fix_bogus_uvs_all(void) { int seg; for (seg=0; seg<=Highest_segment_index; seg++) if (Segments[seg].segnum != -1) fix_bogus_uvs_seg(&Segments[seg]); return 0; } // ----------------------------------------------------------------------------- // Propagate texture map u,v coordinates to base_seg:back_side from base_seg:some-other-side // 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. void med_propagate_tmaps_to_any_side(segment *base_seg, int back_side, int tmap_num, int uv_only_flag) { int v1=0,v2=0; int s; // Scan all sides, look for an occupied side which is not back_side or Side_opposite[back_side] for (s=0; sverts[v1], base_seg->verts[v2], uv_only_flag); base_seg->sides[back_side].tmap_num = tmap_num; } // ----------------------------------------------------------------------------- // Segment base_seg is connected through side base_side to segment con_seg on con_side. // For all walls in con_seg, find the wall in base_seg which shares an edge. Copy tmap_num // from that side in base_seg to the wall in con_seg. If the wall in base_seg is not present // (ie, there is another segment connected through it), follow the connection through that // segment to get the wall in the connected segment which shares the edge, and get tmap_num from there. void propagate_tmaps_to_segment_sides(segment *base_seg, int base_side, segment *con_seg, int con_side, int uv_only_flag) { sbyte *base_vp,*con_vp; short abs_id1,abs_id2; int v; base_vp = Side_to_verts[base_side]; con_vp = Side_to_verts[con_side]; // Do for each edge on connecting face. for (v=0; v<4; v++) { abs_id1 = base_seg->verts[(int) base_vp[v]]; abs_id2 = base_seg->verts[(int) base_vp[(v+1) % 4]]; propagate_tmaps_to_segment_side(base_seg, base_side, con_seg, con_side, abs_id1, abs_id2, uv_only_flag); } } // ----------------------------------------------------------------------------- // Propagate texture maps in base_seg to con_seg. // For each wall in con_seg, find the wall in base_seg which shared an edge. Copy tmap_num from that // wall in base_seg to the wall in con_seg. If the wall in base_seg is not present, then look at the // segment connected through base_seg through the wall. The wall with a common edge is the new wall // of interest. Continue searching in this way until a wall of interest is present. void med_propagate_tmaps_to_segments(segment *base_seg,segment *con_seg, int uv_only_flag) { int s; // mprintf((0,"Propagating segments from %i to %i\n",base_seg-Segments,con_seg-Segments)); for (s=0; schildren[s] == con_seg-Segments) propagate_tmaps_to_segment_sides(base_seg, s, con_seg, find_connect_side(base_seg, con_seg), uv_only_flag); con_seg->static_light = base_seg->static_light; validate_uv_coordinates(con_seg); } // ------------------------------------------------------------------------------- // Copy texture map uvs from srcseg to destseg. // If two segments have different face structure (eg, destseg has two faces on side 3, srcseg has only 1) // then assign uvs according to side vertex id, not face vertex id. void copy_uvs_seg_to_seg(segment *destseg,segment *srcseg) { int s; for (s=0; ssides[s].tmap_num = srcseg->sides[s].tmap_num; destseg->sides[s].tmap_num2 = srcseg->sides[s].tmap_num2; } destseg->static_light = srcseg->static_light; } // _________________________________________________________________________________________________________________________ // Maximum distance between a segment containing light to a segment to receive light. #define LIGHT_DISTANCE_THRESHOLD (F1_0*80) fix Magical_light_constant = (F1_0*16); // int Seg0, Seg1; //int Bugseg = 27; typedef struct { sbyte flag, hit_type; vms_vector vector; } hash_info; #define FVI_HASH_SIZE 8 #define FVI_HASH_AND_MASK (FVI_HASH_SIZE - 1) // Note: This should be malloced. // Also, the vector should not be 12 bytes, you should only care about some smaller portion of it. hash_info fvi_cache[FVI_HASH_SIZE]; int Hash_hits=0, Hash_retries=0, Hash_calcs=0; // ----------------------------------------------------------------------------------------- // Set light from a light source. // Light incident on a surface is defined by the light incident at its points. // Light at a point = K * (V . N) / d // where: // K = some magical constant to make everything look good // V = normalized vector from light source to point // N = surface normal at point // d = distance from light source to point // (Note that the above equation can be simplified to K * (VV . N) / d^2 where VV = non-normalized V) // Light intensity emitted from a light source is defined to be cast from four points. // These four points are 1/64 of the way from the corners of the light source to the center // of its segment. By assuming light is cast from these points, rather than from on the // light surface itself, light will be properly cast on the light surface. Otherwise, the // vector V would be the null vector. // If quick_light set, then don't use find_vector_intersection void cast_light_from_side(segment *segp, int light_side, fix light_intensity, int quick_light) { vms_vector segment_center; int segnum,sidenum,vertnum, lightnum; compute_segment_center(&segment_center, segp); //mprintf((0, "From [%i %i %7.3f]: ", segp-Segments, light_side, f2fl(light_intensity))); // Do for four lights, one just inside each corner of side containing light. for (lightnum=0; lightnum<4; lightnum++) { int light_vertex_num, i; vms_vector vector_to_center; vms_vector light_location; // fix inverse_segment_magnitude; light_vertex_num = segp->verts[Side_to_verts[light_side][lightnum]]; light_location = Vertices[light_vertex_num]; // New way, 5/8/95: Move towards center irrespective of size of segment. vm_vec_sub(&vector_to_center, &segment_center, &light_location); vm_vec_normalize_quick(&vector_to_center); vm_vec_add2(&light_location, &vector_to_center); // -- Old way, before 5/8/95 -- // -- This way was kind of dumb. In larger segments, you move LESS towards the center. // -- 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. // -- Old way, before 5/8/95 -- vm_vec_sub(&vector_to_center, &segment_center, &light_location); // -- Old way, before 5/8/95 -- inverse_segment_magnitude = fixdiv(F1_0/5, vm_vec_mag(&vector_to_center)); // -- Old way, before 5/8/95 -- vm_vec_scale_add(&light_location, &light_location, &vector_to_center, inverse_segment_magnitude); for (segnum=0; segnum<=Highest_segment_index; segnum++) { segment *rsegp = &Segments[segnum]; vms_vector r_segment_center; fix dist_to_rseg; for (i=0; isides[sidenum]; vms_vector *side_normalp = &rsidep->normals[0]; // kinda stupid? always use vector 0. //mprintf((0, "[%i %i], ", rsegp-Segments, sidenum)); for (vertnum=0; vertnum<4; vertnum++) { fix distance_to_point, light_at_point, light_dot; vms_vector vert_location, vector_to_light; int abs_vertnum; abs_vertnum = rsegp->verts[Side_to_verts[sidenum][vertnum]]; vert_location = Vertices[abs_vertnum]; distance_to_point = vm_vec_dist_quick(&vert_location, &light_location); vm_vec_sub(&vector_to_light, &light_location, &vert_location); vm_vec_normalize(&vector_to_light); // Hack: In oblong segments, it's possible to get a very small dot product // but the light source is very nearby (eg, illuminating light itself!). light_dot = vm_vec_dot(&vector_to_light, side_normalp); if (distance_to_point < F1_0) if (light_dot > 0) light_dot = (light_dot + F1_0)/2; if (light_dot > 0) { light_at_point = fixdiv(fixmul(light_dot, light_dot), distance_to_point); light_at_point = fixmul(light_at_point, Magical_light_constant); if (light_at_point >= 0) { fvi_info hit_data; int hit_type; vms_vector vert_location_1, r_vector_to_center; fix inverse_segment_magnitude; vm_vec_sub(&r_vector_to_center, &r_segment_center, &vert_location); inverse_segment_magnitude = fixdiv(F1_0/3, vm_vec_mag(&r_vector_to_center)); vm_vec_scale_add(&vert_location_1, &vert_location, &r_vector_to_center, inverse_segment_magnitude); vert_location = vert_location_1; //if ((segp-Segments == 199) && (rsegp-Segments==199)) // Int3(); // Seg0 = segp-Segments; // Seg1 = rsegp-Segments; if (!quick_light) { int hash_value = Side_to_verts[sidenum][vertnum]; hash_info *hashp = &fvi_cache[hash_value]; while (1) { if (hashp->flag) { if ((hashp->vector.x == vector_to_light.x) && (hashp->vector.y == vector_to_light.y) && (hashp->vector.z == vector_to_light.z)) { //mprintf((0, "{CACHE %4x} ", hash_value)); hit_type = hashp->hit_type; Hash_hits++; break; } else { Int3(); // How is this possible? Should be no hits! Hash_retries++; hash_value = (hash_value+1) & FVI_HASH_AND_MASK; hashp = &fvi_cache[hash_value]; } } else { //mprintf((0, "\nH:%04x ", hash_value)); fvi_query fq; Hash_calcs++; hashp->vector = vector_to_light; hashp->flag = 1; fq.p0 = &light_location; fq.startseg = segp-Segments; fq.p1 = &vert_location; fq.rad = 0; fq.thisobjnum = -1; fq.ignore_obj_list = NULL; fq.flags = 0; hit_type = find_vector_intersection(&fq,&hit_data); hashp->hit_type = hit_type; break; } } } else hit_type = HIT_NONE; //mprintf((0, "hit=%i ", hit_type)); switch (hit_type) { case HIT_NONE: light_at_point = fixmul(light_at_point, light_intensity); rsidep->uvls[vertnum].l += light_at_point; //mprintf((0, "(%5.2f) ", f2fl(light_at_point))); if (rsidep->uvls[vertnum].l > F1_0) rsidep->uvls[vertnum].l = F1_0; break; case HIT_WALL: break; case HIT_OBJECT: Int3(); // Hit object, should be ignoring objects! break; case HIT_BAD_P0: Int3(); // Ugh, this thing again, what happened, what does it mean? break; } } // end if (light_at_point... } // end if (light_dot >... } // end for (vertnum=0... } // end if (rsegp... } // end for (sidenum=0... } // end if (dist_to_rseg... } // end for (segnum=0... } // end for (lightnum=0... //mprintf((0, "\n")); } // ------------------------------------------------------------------------------------------ // Zero all lighting values. void calim_zero_light_values(void) { int segnum, sidenum, vertnum; for (segnum=0; segnum<=Highest_segment_index; segnum++) { segment *segp = &Segments[segnum]; for (sidenum=0; sidenumsides[sidenum]; for (vertnum=0; vertnum<4; vertnum++) sidep->uvls[vertnum].l = F1_0/64; // Put a tiny bit of light here. } Segments[segnum].static_light = F1_0/64; } } // ------------------------------------------------------------------------------------------ // Used in setting average light value in a segment, cast light from a side to the center // of all segments. void cast_light_from_side_to_center(segment *segp, int light_side, fix light_intensity, int quick_light) { vms_vector segment_center; int segnum, lightnum; compute_segment_center(&segment_center, segp); // Do for four lights, one just inside each corner of side containing light. for (lightnum=0; lightnum<4; lightnum++) { int light_vertex_num; vms_vector vector_to_center; vms_vector light_location; light_vertex_num = segp->verts[Side_to_verts[light_side][lightnum]]; light_location = Vertices[light_vertex_num]; vm_vec_sub(&vector_to_center, &segment_center, &light_location); vm_vec_scale_add(&light_location, &light_location, &vector_to_center, F1_0/64); for (segnum=0; segnum<=Highest_segment_index; segnum++) { segment *rsegp = &Segments[segnum]; vms_vector r_segment_center; fix dist_to_rseg; //if ((segp == &Segments[Bugseg]) && (rsegp == &Segments[Bugseg])) // Int3(); compute_segment_center(&r_segment_center, rsegp); dist_to_rseg = vm_vec_dist_quick(&r_segment_center, &segment_center); if (dist_to_rseg <= LIGHT_DISTANCE_THRESHOLD) { fix light_at_point; if (dist_to_rseg > F1_0) light_at_point = fixdiv(Magical_light_constant, dist_to_rseg); else light_at_point = Magical_light_constant; if (light_at_point >= 0) { int hit_type; if (!quick_light) { fvi_query fq; fvi_info hit_data; fq.p0 = &light_location; fq.startseg = segp-Segments; fq.p1 = &r_segment_center; fq.rad = 0; fq.thisobjnum = -1; fq.ignore_obj_list = NULL; fq.flags = 0; hit_type = find_vector_intersection(&fq,&hit_data); } else hit_type = HIT_NONE; switch (hit_type) { case HIT_NONE: light_at_point = fixmul(light_at_point, light_intensity); if (light_at_point >= F1_0) light_at_point = F1_0-1; rsegp->static_light += light_at_point; if (segp->static_light < 0) // if it went negative, saturate segp->static_light = 0; break; case HIT_WALL: break; case HIT_OBJECT: Int3(); // Hit object, should be ignoring objects! break; case HIT_BAD_P0: Int3(); // Ugh, this thing again, what happened, what does it mean? break; } } // end if (light_at_point... } // end if (dist_to_rseg... } // end for (segnum=0... } // end for (lightnum=0... } // ------------------------------------------------------------------------------------------ // Process all lights. void calim_process_all_lights(int quick_light) { int segnum, sidenum; for (segnum=0; segnum<=Highest_segment_index; segnum++) { segment *segp = &Segments[segnum]; mprintf((0, ".")); for (sidenum=0; sidenumchildren[sidenum])) { if (WALL_IS_DOORWAY(segp, sidenum) != WID_NO_WALL) { side *sidep = &segp->sides[sidenum]; fix light_intensity; light_intensity = TmapInfo[sidep->tmap_num].lighting + TmapInfo[sidep->tmap_num2 & 0x3fff].lighting; // if (segp->sides[sidenum].wall_num != -1) { // int wall_num, bitmap_num, effect_num; // wall_num = segp->sides[sidenum].wall_num; // effect_num = Walls[wall_num].type; // bitmap_num = effects_bm_num[effect_num]; // // light_intensity += TmapInfo[bitmap_num].lighting; // } if (light_intensity) { light_intensity /= 4; // casting light from four spots, so divide by 4. cast_light_from_side(segp, sidenum, light_intensity, quick_light); cast_light_from_side_to_center(segp, sidenum, light_intensity, quick_light); } } } } } // ------------------------------------------------------------------------------------------ // Apply static light in mine. // First, zero all light values. // Then, for all light sources, cast their light. void cast_all_light_in_mine(int quick_flag) { validate_segment_all(); calim_zero_light_values(); calim_process_all_lights(quick_flag); } // int Fvit_num = 1000; // // fix find_vector_intersection_test(void) // { // int i; // fvi_info hit_data; // int p0_seg, p1_seg, this_objnum, ignore_obj, check_obj_flag; // fix rad; // int start_time = timer_get_milliseconds();; // vms_vector p0,p1; // // ignore_obj = 1; // check_obj_flag = 0; // this_objnum = -1; // rad = F1_0/4; // // for (i=0; ix - v2->x) < Normal_nearness) if (abs(v1->y - v2->y) < Normal_nearness) if (abs(v1->z - v2->z) < Normal_nearness) return 1; return 0; } int Total_normals=0; int Diff_normals=0; void print_normals(void) { int i,j,s,n,nn; // vms_vector *normal; int num_normals=0; Total_normals = 0; Diff_normals = 0; for (i=0; i<=Highest_segment_index; i++) for (s=0; s<6; s++) { if (Segments[i].sides[s].type == SIDE_IS_QUAD) nn=1; else nn=2; for (n=0; n