/* * Descent 3 * Copyright (C) 2024 Parallax Software * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . --- HISTORICAL COMMENTS FOLLOW --- * $Logfile: /DescentIII/Main/editor/rad_cast.cpp $ * $Revision: 1.1.1.1 $ * $Date: 2003-08-26 03:57:38 $ * $Author: kevinb $ * * Ray casting for radiosity, I think. * * $Log: not supported by cvs2svn $ * * 87 5/20/99 11:50a Jason * made super detail not do volume lights super detail * * 86 4/18/99 3:37p 3dsmax * tweaks * * 85 4/18/99 5:42a Chris * Added the FQ_IGNORE_RENDER_THROUGH_PORTALS flag * * 84 4/16/99 5:50p Jason * tweaked smooth specular stuff some more * * 83 4/15/99 2:56p Jason * fixed stupid lighting bug * * 82 4/05/99 10:36a 3dsmax * took out mprintfs * * 81 4/02/99 5:34p Jason * added verbose mprintfs for super detail * * 80 3/23/99 4:09p Jason * upped smooth specular sensitivity * * 79 3/11/99 1:07p Jason * more fixes for smooth specular lighting * * 78 3/10/99 7:12p Jason * added smooth specular shading for curved surfaces * * 77 3/10/99 2:09p Jason * made better specular lighting * * 76 2/24/99 5:14p 3dsmax * * * 75 2/09/99 9:59a Chris * Massive BOA update :) Terrain happy now. Vis happy now. Sound happy * now. * * 74 1/27/99 12:19p Dan * another clipping fix * * 73 1/27/99 12:16p Dan * finally fixed dumb clipping problem * * 72 1/27/99 11:06a Jason * fixed satellite clipping problem * * 71 1/24/99 1:17p Jason * fixed satellite casting problem * * 70 12/21/98 11:52a Jason * changes for specular lighting * * 69 11/19/98 12:22p Jason * optimizations * * 68 10/28/98 12:18p Jason * sped up volume lighting a bit * * 67 10/05/98 6:53p Jason * took out some unused variables * * 66 10/02/98 11:55a Jason * more fixes for satellite clipping * * 65 9/24/98 11:27a Jason * fixed satellite clipping * * 64 8/21/98 12:29p Jason * upped specular lighting threshold * * 63 8/10/98 11:25a Jason * added better specular lighting * * 62 6/30/98 3:12p Jason * sped up super detail by not doing surper-detail from surfaces that * aren't lightsources * * 61 6/03/98 12:22p Jason * specular lighting optimizations * * 60 6/02/98 6:03p Jason * added specular lightmaps * * 59 6/02/98 11:01a Jason * Post E3 Checkin * * 58 5/26/98 10:11p Sean * don't do specular lighting for single rooms * * 57 5/25/98 3:46p Jason * added better light glows * * 56 5/22/98 3:28p Jason * added specular lighting * * 55 5/21/98 11:51a Jason * made volume lights work with super detail * * 54 5/20/98 1:37p Jason * upped facelimit on volume raycasting * * 53 5/19/98 2:36p Jason * improved volume light casting * * 52 5/15/98 5:41p Jason * implemented volume lighting system * * 51 5/01/98 4:32p Jason * temp fix for lighting * * 50 4/19/98 5:23p Jason * made terrain satellites only cast light on rooms that touch terrain * * 49 4/08/98 3:26p Jason * made terrain satellites automatically cast light into rooms * * 48 3/17/98 5:15p Jason * changed normal casting length * * 47 3/16/98 5:47p Jason * added FQ_NO_RELINK * * 46 3/11/98 6:14p Jason * better lighting, again * * 45 3/11/98 5:13p Jason * always draw an object if any point is behind you * * 44 3/06/98 3:54p Jason * fixed bug with satellite lighting indoors * * 43 3/06/98 3:23p Jason * added lighting from satellites to indoor rooms * * 42 2/27/98 5:58p Jason * fixed terrain lighting problem * * 41 2/25/98 1:02p Jason * offset lights and dests by 1/8 of a normal * * 40 2/23/98 6:57p Jason * fixed bug caused by my last rev * * 39 2/23/98 6:50p Jason * changes to help facilitate fast lighting with shadow volumes * * * 38 2/22/98 3:05p Jason * sped up raycasting by switching the directions rays get shot. This * allows us to ignore backfaces * * 37 2/19/98 5:44p Jason * made super detail work correctly * * 36 2/09/98 3:45p Jason * changed normal distance offset to be friendly with BSP tree stuff * * 35 2/06/98 12:35p Jason * fixed problem with external rooms * * 34 2/05/98 4:20p Matt * Fixed terrain lighting broken in roomnum/cellnum change * * 33 2/04/98 6:23p Matt * Changed object room number to indicate a terrain cell via a flag. Got * rid of the object flag which used to indicate terrain. * */ #include #include #include "radiosity.h" #include "rad_cast.h" #include "terrain.h" #include "room.h" #include "editor_lighting.h" #include "findintersection.h" #include "special_face.h" #include "bsp.h" #include "boa.h" // A ray must contribute at least this amount to be accepted (currently .5%) #define DEFAULT_IGNORE_LIMIT .005f float Ignore_limit=DEFAULT_IGNORE_LIMIT; extern rad_element *rad_MaxElement; float Current_max_specular_strength; spectra Current_max_specular_color; // Returns 1 if a src vector can hit dest vector for a volume point int ShootRayToVolumePoint (vector *src,vector *dest,int start_room) { fvi_info hit_info; fvi_query fq; if (UseBSP) { int fate=BSPRayOccluded (src,dest,MineBSP.root); if (!fate) return 1; return 0; } // shoot a ray from the light position to the current vertex fq.p0=src; fq.p1=dest; fq.startroom=start_room; fq.rad=0.0f; fq.flags=FQ_CHECK_OBJS|FQ_IGNORE_NON_LIGHTMAP_OBJECTS|FQ_NO_RELINK|FQ_IGNORE_RENDER_THROUGH_PORTALS; fq.thisobjnum = -1; fq.ignore_obj_list = NULL; int fate = fvi_FindIntersection(&fq,&hit_info); float dist=vm_VectorDistance(&hit_info.hit_pnt,dest); if (dist>.1) return 0; return 1; } void ClipSatelliteToTerrain (vector *answer,vector *src_vec,vector *dest_vec) { vector cur_vec=*src_vec; float terrain_limit=256*TERRAIN_SIZE; float mag,diff; vector ray; // Check ceiling if (cur_vec.y>(MAX_TERRAIN_HEIGHT*30)) { ray=cur_vec-*dest_vec; mag=vm_GetMagnitude (&ray); ray/=mag; diff=((MAX_TERRAIN_HEIGHT*30)-dest_vec->y)/ray.y; cur_vec=(*dest_vec+(ray*diff))-(ray/4); } // Check right edge if (cur_vec.x>terrain_limit) { ray=cur_vec-*dest_vec; mag=vm_GetMagnitude (&ray); ray/=mag; diff=(terrain_limit-dest_vec->x)/ray.x; cur_vec=(*dest_vec+(ray*diff))-(ray/4); } // Check left edge if (cur_vec.x<0) { ray=cur_vec-*dest_vec; mag=vm_GetMagnitude (&ray); ray/=mag; diff=(-dest_vec->x)/ray.x; cur_vec=(*dest_vec+(ray*diff))-(ray/4); } // Check top edge if (cur_vec.z>terrain_limit) { ray=cur_vec-*dest_vec; mag=vm_GetMagnitude (&ray); ray/=mag; diff=(terrain_limit-dest_vec->z)/ray.z; cur_vec=(*dest_vec+(ray*diff))-(ray/4); } // Check bottom edge if (cur_vec.z<0) { ray=cur_vec-*dest_vec; mag=vm_GetMagnitude (&ray); ray/=mag; diff=(-dest_vec->z)/ray.z; cur_vec=(*dest_vec+(ray*diff))-(ray/4); } if (cur_vec.x>4095) cur_vec.x=4095; if (cur_vec.z>4095) cur_vec.z=4095; *answer=cur_vec; } // Returns 1 if a src vector can hit dest vector unobstructed, else 0 int ShootRayFromPoint (vector *src,vector *dest,rad_surface *src_surf,rad_surface *dest_surf) { float dist; bool do_backface=0; fvi_info hit_info; fvi_query fq; vector temp_src=*src; vector temp_dest=*dest; int from_satellite=0; // Trivially reject all rooms if (dest_surf->surface_type==ST_ROOM || dest_surf->surface_type==ST_ROOM_OBJECT) { if (src_surf->surface_type==ST_ROOM || src_surf->surface_type==ST_ROOM_OBJECT) { if (!BOA_IsVisible(dest_surf->roomnum,src_surf->roomnum)) return 0; } } if (UseBSP) { if (dest_surf->surface_type==ST_ROOM || dest_surf->surface_type==ST_ROOM_OBJECT) { if (src_surf->surface_type==ST_ROOM || src_surf->surface_type==ST_ROOM_OBJECT) { int fate=BSPRayOccluded (src,dest,MineBSP.root); if (!fate) return 1; return 0; } } } // If this ray is too high, clip it to the ceiling if (src_surf->surface_type==ST_SATELLITE) { if (1 || dest->y>=MAX_TERRAIN_HEIGHT) { from_satellite=1; // swap the src/dest the variables because we now want to shoot from the ground to the satellite rad_surface *temp_surf; vector *temp_vec; temp_surf=src_surf; src_surf=dest_surf; dest_surf=temp_surf; temp_vec=src; src=dest; dest=temp_vec; temp_dest=*dest; temp_src=*src; ClipSatelliteToTerrain (&temp_src,src,&temp_dest); } else { ClipSatelliteToTerrain (&temp_src,src,&temp_dest); int src_cell=GetTerrainCellFromPos (&temp_src); if (src_cell<0) { src_cell=0; Int3(); // Get Jason, satellite clipped off terrain? } src_surf->roomnum=MAKE_ROOMNUM (src_cell); } } // shoot a ray from the light position to the current vertex fq.p0=&temp_src; fq.p1=&temp_dest; if (src_surf->surface_type==ST_EXTERNAL_ROOM) fq.startroom= GetTerrainRoomFromPos (src); else fq.startroom= src_surf->roomnum; fq.rad=0.0f; fq.flags=FQ_CHECK_OBJS|FQ_IGNORE_NON_LIGHTMAP_OBJECTS|FQ_NO_RELINK|FQ_IGNORE_RENDER_THROUGH_PORTALS; fq.thisobjnum = -1; fq.ignore_obj_list = NULL; int fate = fvi_FindIntersection(&fq,&hit_info); if (from_satellite) { if (fate==HIT_NONE || fate==HIT_OUT_OF_TERRAIN_BOUNDS) return 1; else return 0; } dist=vm_VectorDistance(&hit_info.hit_pnt,&temp_dest); if (dist>.1) { //mprintf ((0,"Didn't hit!\n")); return 0; } return 1; } int Rays_ignored=0; float GetMaxColor (spectra *sp); float GetFormFactorForElementAndSatellite (rad_surface *dest_surf,rad_element *dest_element,vector *src_center) { vector dest_center; vector light_center=*src_center; float form_factor=0.0; if (Ignore_satellites) return 0; // Bash src center to first element vertex (if sun or moon) light_center=rad_MaxSurface->elements[0].verts[0]; for (int j=0;jnum_verts;j++) { dest_center=dest_element->verts[j]; dest_center+=(dest_surf->normal/32.0); float temp_factor=0; int hit=0; vector ray=light_center-dest_center; if (dest_surf->surface_type!=ST_TERRAIN) { if ((vm_DotProduct (&ray,&dest_surf->normal))<0) continue; } // If this surface is a terrain surface, use the terrain speedup table if (dest_surf->surface_type==ST_TERRAIN) { ASSERT(ROOMNUM_OUTSIDE(dest_surf->roomnum)); int cellnum = CELLNUM(dest_surf->roomnum); if (dest_surf->facenum==0) { if (j==1) cellnum+=TERRAIN_WIDTH; else if (j==2) cellnum+=(TERRAIN_WIDTH+1); } else { if (j==1) cellnum+=(TERRAIN_WIDTH+1); else if (j==2) cellnum++; } hit=TerrainLightSpeedup[rad_MaxSurface->roomnum][cellnum]; } else hit=ShootRayFromPoint (&light_center,&dest_center,rad_MaxSurface,dest_surf); if (hit) { float ray_length=vm_GetMagnitude (&ray); vector dest_norm_ray=ray/ray_length; vector dest_normal=dest_surf->normal; float ff; ff=vm_DotProduct(&dest_normal,&dest_norm_ray); if (ff>0) temp_factor+=ff; } form_factor+=temp_factor; } form_factor/=dest_element->num_verts; if (form_factor>1) mprintf ((0,"form factor >1!\n")); return form_factor; } // Calculates the percentage of specular light that is coming from the // currently shooting patch void CheckToUpdateSpecularFace (rad_surface *dest_surf,spectra *color,vector *src_center) { vector light_center; float total_strength=(color->r*.3)+(color->g*.33)+(color->b*.33); float threshold=.7f; if (dest_surf->surface_type!=ST_ROOM) return; if (Rooms[dest_surf->roomnum].faces[dest_surf->facenum].special_handle==BAD_SPECIAL_FACE_INDEX) return; if (src_center==NULL) GetCenterOfSurface (rad_MaxSurface,&light_center); else light_center=*src_center; room *rp=&Rooms[dest_surf->roomnum]; face *fp=&rp->faces[dest_surf->facenum]; if (GameTextures[fp->tmap].flags & TF_SMOOTH_SPECULAR) threshold=.01f; else { if (!(rad_MaxSurface->flags & SF_LIGHTSOURCE)) return; } int i,t; for (i=0;i<4;i++) { if (total_strength>threshold && total_strength>Room_strongest_value[dest_surf->roomnum][i][dest_surf->facenum]) { float scalar=(total_strength/50.0)+.5; if (scalar>1) scalar=1.0; int special_index=Rooms[dest_surf->roomnum].faces[dest_surf->facenum].special_handle; // Move the others down for (t=2;t>=i;t--) { Room_strongest_value[dest_surf->roomnum][t+1][dest_surf->facenum]=Room_strongest_value[dest_surf->roomnum][t][dest_surf->facenum]; SpecialFaces[special_index].spec_instance[t+1].bright_color=SpecialFaces[special_index].spec_instance[t].bright_color; SpecialFaces[special_index].spec_instance[t+1].bright_center=SpecialFaces[special_index].spec_instance[t].bright_center; } // Update our arrays with strongest light and src patch center Room_strongest_value[dest_surf->roomnum][i][dest_surf->facenum]=total_strength; float rmax=GetMaxColor (color); float r=color->r; float g=color->g; float b=color->b; // Normalize colors if (rmax>1) { r/=rmax; g/=rmax; b/=rmax; } r*=(255.0*scalar); g*=(255.0*scalar); b*=(255.0*scalar); SpecialFaces[special_index].spec_instance[i].bright_color=GR_RGB16((int)r,(int)g,(int)b); SpecialFaces[special_index].spec_instance[i].bright_center=light_center; return; } } } float GetFormFactorForElement (rad_surface *dest_surf,rad_element *dest_element,vector *src_center) { int touched=0; vector dest_center; int i,limit; float ray_area; int ignored=0; vector light_center=*src_center; float form_factor=0.0; int multiple_shoots=0; ray_area=rad_MaxSurface->area; float rmax=GetMaxColor (&rad_MaxSurface->exitance); multiple_shoots=0; limit=1; for (i=0;ielements[i].flags & EF_IGNORE)) continue; if (multiple_shoots) { GetCenterOfElement (&rad_MaxSurface->elements[i],&light_center); light_center+=(rad_MaxSurface->normal/16.0); ray_area=rad_MaxSurface->elements[i].area; } else ray_area=rad_MaxSurface->area; GetCenterOfElement (dest_element,&dest_center); dest_center+=(dest_surf->normal/16.0); int hit=0; vector ray=light_center-dest_center; vector revray=dest_center-light_center; if ((vm_DotProduct (&ray,&dest_surf->normal))<0) continue; if ((vm_DotProduct (&revray,&rad_MaxSurface->normal))<0) continue; // Check to see if this ray even matters float ray_length=vm_GetMagnitudeFast (&ray); vector dest_norm_ray=ray/ray_length; vector src_norm_ray=-dest_norm_ray; vector dest_normal=dest_surf->normal; float ff; vector src_normal=rad_MaxSurface->normal; ff=(vm_DotProduct (&src_norm_ray,&src_normal) * vm_DotProduct(&dest_normal,&dest_norm_ray))/((3.14 * ray_length * ray_length)+ray_area); ff*=ray_area; ff*=rmax; // If shooting from elements, scale the test up if (multiple_shoots) ff*=rad_MaxSurface->area/rad_MaxSurface->elements[i].area; if (ffnormal; src_normal=rad_MaxSurface->normal; ff=(vm_DotProduct (&src_norm_ray,&src_normal) * vm_DotProduct(&dest_normal,&dest_norm_ray))/((3.14 * ray_length * ray_length)+ray_area); if (ff>1) mprintf ((0,"ff >1!\n")); if (ff>0) temp_factor+=ff; // Update specularity if needed if (rad_MaxSurface->surface_type==ST_ROOM && Calculate_specular_lighting) { spectra color; float scalar=ff; scalar*=ray_area; scalar*=5; color.r=rad_MaxSurface->exitance.r*scalar; color.g=rad_MaxSurface->exitance.g*scalar; color.b=rad_MaxSurface->exitance.b*scalar; float total_strength=(color.r*.33)+(color.g*.33)+(color.b*.33); if (total_strength>Current_max_specular_strength) { Current_max_specular_strength=total_strength; Current_max_specular_color=color; } } } temp_factor*=ray_area; //temp_factor/=dest_element->num_verts; //if (multiple_shoots) // temp_factor*=(rad_MaxSurface->elements[i].area/rad_MaxSurface->area); form_factor+=temp_factor; if (form_factor>1) mprintf ((0,"form factor >1! val=%f\n",form_factor)); } if (ignored>0) Rays_ignored++; return form_factor; } float GetFormFactorForElementSuperDetail (rad_surface *dest_surf,rad_element *dest_element) { int touched=0; vector dest_center; float ray_area; int ignored=0; vector light_center; vector patch_center; float form_factor=0.0; int multiple_shoots=0; ray_area=rad_MaxElement->area; if (rad_MaxElement->flags & EF_IGNORE) return 0; float rmax=GetMaxColor (&rad_MaxElement->exitance); float temp_factor=0.0; GetCenterOfSurface (rad_MaxSurface,&patch_center); GetCenterOfElement (rad_MaxElement,&light_center); light_center+=(rad_MaxSurface->normal/16.0); GetCenterOfElement (dest_element,&dest_center); dest_center+=(dest_surf->normal/16.0); int hit=0; vector ray=light_center-dest_center; vector revray=dest_center-light_center; if ((vm_DotProduct (&ray,&dest_surf->normal))<0) return 0; if ((vm_DotProduct (&revray,&rad_MaxSurface->normal))<0) return 0; // Check to see if this ray even matters float ray_length=vm_GetMagnitudeFast (&ray); vector dest_norm_ray=ray/ray_length; vector src_norm_ray=-dest_norm_ray; vector dest_normal=dest_surf->normal; float ff; vector src_normal=rad_MaxSurface->normal; ff=(vm_DotProduct (&src_norm_ray,&src_normal) * vm_DotProduct(&dest_normal,&dest_norm_ray))/((3.14 * ray_length * ray_length)+ray_area); ff*=ray_area; ff*=rmax; // If shooting from elements, scale the test up ff*=rad_MaxSurface->area/rad_MaxElement->area; if (ffnormal; src_normal=rad_MaxSurface->normal; ff=(vm_DotProduct (&src_norm_ray,&src_normal) * vm_DotProduct(&dest_normal,&dest_norm_ray))/((3.14 * ray_length * ray_length)+ray_area); if (ff>1) mprintf ((0,"ff >1!\n")); if (ff>0) temp_factor+=ff; // Update specularity if needed if (rad_MaxSurface->surface_type==ST_ROOM && Calculate_specular_lighting) { spectra color; float scalar=ff; scalar*=ray_area; scalar*=(rad_MaxSurface->area/ray_area); scalar*=5; color.r=rad_MaxSurface->exitance.r*scalar; color.g=rad_MaxSurface->exitance.g*scalar; color.b=rad_MaxSurface->exitance.b*scalar; float total_strength=(color.r*.33)+(color.g*.33)+(color.b*.33); if (total_strength>Current_max_specular_strength) { Current_max_specular_strength=total_strength; Current_max_specular_color=color; } } } temp_factor*=ray_area; form_factor+=temp_factor; if (form_factor>1) mprintf ((0,"form factor >1! val=%f\n",form_factor)); return form_factor; } // Calculates the volume lighting for the currently shooting patch void CalculateVolumeLightsForRay (float total_sphere_dist,vector *src_center) { float sphere_dist=total_sphere_dist; int i,t; // Do volume lighting if ((rad_MaxSurface->surface_type==ST_ROOM || rad_MaxSurface->surface_type==ST_ROOM_OBJECT)) { if (sphere_dist>.1) { fvi_face_room_list facelist[5000]; uint8_t check_room[MAX_VOLUME_ELEMENTS]; memset (check_room,0,MAX_VOLUME_ELEMENTS); // Build a list of rooms to check int num_faces=fvi_QuickDistFaceList (rad_MaxSurface->roomnum,src_center,sphere_dist,facelist,4000); check_room[rad_MaxSurface->roomnum]=1; for (i=0;iroomnum)) { continue; } int w=Rooms[roomnum].volume_width; int h=Rooms[roomnum].volume_height; int d=Rooms[roomnum].volume_depth; if (0 && !Shoot_from_patch && (rad_MaxSurface->flags & SF_LIGHTSOURCE)) // super detail { int src_num_elements=rad_MaxSurface->xresolution*rad_MaxSurface->yresolution; for (int k=0;kelements[k]; if (rad_MaxElement->flags & EF_IGNORE) continue; GetCenterOfElement (rad_MaxElement,&light_center); light_center+=(rad_MaxSurface->normal/4); sphere_dist=total_sphere_dist; //sphere_dist*=(rad_MaxElement->area/rad_MaxSurface->area); for (i=0;icolor.r<0) continue; vector subvec=ve->pos-light_center; float mag=vm_GetMagnitudeFast (&subvec); if (mag>sphere_dist) continue; subvec/=mag; int hit; float scalar=subvec*rad_MaxSurface->normal; if (scalar<0) continue; scalar/=((3.14 * mag * mag)+rad_MaxElement->area); scalar*=rad_MaxElement->area; // Trivially reject all rooms if (!BOA_IsVisible(roomnum,rad_MaxSurface->roomnum)) { hit=0; } else { if (ve->flags & VEF_REVERSE_SHOOT) hit=ShootRayToVolumePoint (&ve->pos,&light_center,roomnum); else hit=ShootRayToVolumePoint (&light_center,&ve->pos,rad_MaxSurface->roomnum); } if (hit) { ve->color.r+=rad_MaxElement->exitance.r*scalar; ve->color.g+=rad_MaxElement->exitance.g*scalar; ve->color.b+=rad_MaxElement->exitance.b*scalar; } } } } } } else { for (i=0;icolor.r<0) continue; vector subvec=ve->pos-*src_center; float mag=vm_GetMagnitudeFast (&subvec); if (mag>sphere_dist) continue; subvec/=mag; int hit; float scalar=subvec*rad_MaxSurface->normal; if (scalar<0) continue; scalar/=((3.14 * mag * mag)+rad_MaxSurface->area); scalar*=rad_MaxSurface->area; if (!BOA_IsVisible(roomnum,rad_MaxSurface->roomnum)) { hit=0; } else { if (ve->flags & VEF_REVERSE_SHOOT) hit=ShootRayToVolumePoint (&ve->pos,src_center,roomnum); else hit=ShootRayToVolumePoint (src_center,&ve->pos,rad_MaxSurface->roomnum); } if (hit) { ve->color.r+=rad_MaxSurface->exitance.r*scalar; ve->color.g+=rad_MaxSurface->exitance.g*scalar; ve->color.b+=rad_MaxSurface->exitance.b*scalar; } } } } } } } } } // Calculates the form factors using a raycasting method void CalculateFormFactorsRaycast () { int i,t,k; int ignore; vector src_center; float form_factor; int raycount=0; Rays_ignored=0; if (rad_MaxSurface->surface_type==ST_SATELLITE) { src_center=rad_MaxSurface->verts[0]; } else { GetCenterOfSurface (rad_MaxSurface,&src_center); src_center+=(rad_MaxSurface->normal/16.0); } float sphere_dist=0; // Get the max area of influence for this light if (rad_MaxSurface->surface_type==ST_ROOM || rad_MaxSurface->surface_type==ST_ROOM_OBJECT) { float rmax=GetMaxColor (&rad_MaxSurface->exitance); float power=rmax*rad_MaxSurface->area; float temp_ignore=Ignore_limit/power; float express=1.0/temp_ignore; express/=3.14f; express-=rad_MaxSurface->area; sphere_dist=sqrt (express); if (sphere_dist>0) fvi_QuickDistFaceList (rad_MaxSurface->roomnum,&src_center,sphere_dist,NULL,rad_NumSurfaces); } // Do volume lighting if (Do_volume_lighting) CalculateVolumeLightsForRay (sphere_dist,&src_center); // Shoot this patches light to each element within range for (i=0;isurface_type==ST_PORTAL) ignore=1; if (dest_surf->surface_type==ST_SATELLITE) ignore=1; if (rad_MaxSurface->surface_type==ST_ROOM || rad_MaxSurface->surface_type==ST_ROOM_OBJECT) { if (dest_surf->surface_type==ST_ROOM) { if (!(Rooms[dest_surf->roomnum].faces[dest_surf->facenum].flags & FF_TOUCHED)) ignore=1; Rooms[dest_surf->roomnum].faces[dest_surf->facenum].flags &=~ FF_TOUCHED; } } if (dest_surf->surface_type==ST_ROOM) Rooms[dest_surf->roomnum].faces[dest_surf->facenum].flags &=~ FF_TOUCHED; int dest_num_elements=dest_surf->xresolution*dest_surf->yresolution; // Ignore this surface if we're shooting from a satellite and we cant possibly see it if (rad_MaxSurface->surface_type==ST_SATELLITE) { if (dest_surf->surface_type==ST_ROOM || dest_surf->surface_type==ST_ROOM_OBJECT) { if (!dest_surf->flags & SF_TOUCHES_TERRAIN) ignore =1; } } if (ignore) { raycount+=dest_num_elements; continue; } for (t=0;telements[t]; if ((raycount%1000)==0) { mprintf_at((2,4,0,"Ray=%d ",raycount)); mprintf_at((2,5,0,"Ignore=%d ",Rays_ignored)); } raycount++; if (ignore) continue; if (dest_element->flags & EF_IGNORE) continue; if (Shoot_from_patch || rad_MaxSurface->surface_type==ST_SATELLITE || !(rad_MaxSurface->flags & SF_LIGHTSOURCE)) { if (rad_MaxSurface->surface_type==ST_SATELLITE) form_factor=GetFormFactorForElementAndSatellite(dest_surf,dest_element,&src_center); else form_factor=GetFormFactorForElement (dest_surf,dest_element,&src_center); // Now extract the form factor info out to exitances if (form_factor > 0) { spectra shoot=rad_MaxSurface->exitance; spectra delta; float reflect_factor=dest_surf->reflectivity; delta.r=shoot.r*reflect_factor * form_factor; delta.g=shoot.g*reflect_factor * form_factor; delta.b=shoot.b*reflect_factor * form_factor; // update element exitance dest_element->exitance.r+=delta.r; dest_element->exitance.g+=delta.g; dest_element->exitance.b+=delta.b; dest_surf->exitance.r+=((dest_element->area/dest_surf->area)*delta.r); dest_surf->exitance.g+=((dest_element->area/dest_surf->area)*delta.g); dest_surf->exitance.b+=((dest_element->area/dest_surf->area)*delta.b); } } else // Do super detail { int src_num_elements=rad_MaxSurface->xresolution*rad_MaxSurface->yresolution; for (k=0;kelements[k]; if (rad_MaxElement->flags & EF_IGNORE) continue; form_factor=GetFormFactorForElementSuperDetail (dest_surf,dest_element); // Now extract the form factor info out to exitances if (form_factor > 0) { spectra shoot=rad_MaxElement->exitance; spectra delta; float reflect_factor=dest_surf->reflectivity; delta.r=shoot.r*reflect_factor * form_factor; delta.g=shoot.g*reflect_factor * form_factor; delta.b=shoot.b*reflect_factor * form_factor; // update element exitance dest_element->exitance.r+=delta.r; dest_element->exitance.g+=delta.g; dest_element->exitance.b+=delta.b; dest_surf->exitance.r+=((dest_element->area/dest_surf->area)*delta.r); dest_surf->exitance.g+=((dest_element->area/dest_surf->area)*delta.g); dest_surf->exitance.b+=((dest_element->area/dest_surf->area)*delta.b); } } } } if (rad_MaxSurface->surface_type==ST_ROOM && Calculate_specular_lighting) CheckToUpdateSpecularFace (dest_surf,&Current_max_specular_color,NULL); //mprintf_at((2,4,0,"Ray=%d ",raycount)); //mprintf_at((2,5,0,"Ignore=%d ",Rays_ignored)); } }