2006-03-20 17:12:09 +00:00
/*
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 - 1999 PARALLAX SOFTWARE CORPORATION . ALL RIGHTS RESERVED .
*/
/*
*
* Lighting functions .
*
*/
# include <stdio.h>
# include <string.h> // for memset()
# include "fix.h"
# include "vecmat.h"
# include "gr.h"
# include "inferno.h"
# include "segment.h"
# include "error.h"
# include "render.h"
# include "game.h"
# include "vclip.h"
# include "lighting.h"
# include "3d.h"
2011-04-07 20:32:51 +00:00
# include "interp.h"
2006-03-20 17:12:09 +00:00
# include "laser.h"
# include "timer.h"
# include "player.h"
2011-04-07 20:32:51 +00:00
# include "playsave.h"
2006-03-20 17:12:09 +00:00
# include "weapon.h"
# include "powerup.h"
# include "fvi.h"
# include "robot.h"
# include "multi.h"
2011-04-07 20:32:51 +00:00
# include "palette.h"
# include "bm.h"
# include "rle.h"
2006-03-20 17:12:09 +00:00
int Do_dynamic_light = 1 ;
//int Use_fvi_lighting = 0;
2011-04-07 20:32:51 +00:00
g3s_lrgb Dynamic_light [ MAX_VERTICES ] ;
2006-03-20 17:12:09 +00:00
# define LIGHTING_CACHE_SIZE 4096 // Must be power of 2!
# define LIGHTING_FRAME_DELTA 256 // Recompute cache value every 8 frames.
# define LIGHTING_CACHE_SHIFT 8
int Lighting_frame_delta = 1 ;
int Lighting_cache [ LIGHTING_CACHE_SIZE ] ;
int Cache_hits = 0 , Cache_lookups = 1 ;
// Return true if we think vertex vertnum is visible from segment segnum.
// If some amount of time has gone by, then recompute, else use cached value.
int lighting_cache_visible ( int vertnum , int segnum , int objnum , vms_vector * obj_pos , int obj_seg , vms_vector * vertpos )
{
int cache_val , cache_frame , cache_vis ;
cache_val = Lighting_cache [ ( ( segnum < < LIGHTING_CACHE_SHIFT ) ^ vertnum ) & ( LIGHTING_CACHE_SIZE - 1 ) ] ;
cache_frame = cache_val > > 1 ;
cache_vis = cache_val & 1 ;
Cache_lookups + + ;
if ( ( cache_frame = = 0 ) | | ( cache_frame + Lighting_frame_delta < = FrameCount ) ) {
int apply_light = 0 ;
fvi_query fq ;
fvi_info hit_data ;
int segnum , hit_type ;
segnum = - 1 ;
# ifndef NDEBUG
segnum = find_point_seg ( obj_pos , obj_seg ) ;
if ( segnum = = - 1 ) {
Int3 ( ) ; // Obj_pos is not in obj_seg!
return 0 ; // Done processing this object.
}
# endif
fq . p0 = obj_pos ;
fq . startseg = obj_seg ;
fq . p1 = vertpos ;
fq . rad = 0 ;
fq . thisobjnum = objnum ;
fq . ignore_obj_list = NULL ;
fq . flags = FQ_TRANSWALL ;
hit_type = find_vector_intersection ( & fq , & hit_data ) ;
// Hit_pos = Hit_data.hit_pnt;
// Hit_seg = Hit_data.hit_seg;
if ( hit_type = = HIT_OBJECT )
Int3 ( ) ; // Hey, we're not supposed to be checking objects!
if ( hit_type = = HIT_NONE )
apply_light = 1 ;
else if ( hit_type = = HIT_WALL ) {
fix dist_dist ;
dist_dist = vm_vec_dist_quick ( & hit_data . hit_pnt , obj_pos ) ;
if ( dist_dist < F1_0 / 4 ) {
apply_light = 1 ;
// -- Int3(); // Curious, did fvi detect intersection with wall containing vertex?
}
}
Lighting_cache [ ( ( segnum < < LIGHTING_CACHE_SHIFT ) ^ vertnum ) & ( LIGHTING_CACHE_SIZE - 1 ) ] = apply_light + ( FrameCount < < 1 ) ;
return apply_light ;
} else {
Cache_hits + + ;
return cache_vis ;
}
}
# define HEADLIGHT_CONE_DOT (F1_0*9 / 10)
# define HEADLIGHT_SCALE (F1_0*10)
// ----------------------------------------------------------------------------------------------
2011-04-07 20:32:51 +00:00
void apply_light ( g3s_lrgb obj_light_emission , int obj_seg , vms_vector * obj_pos , int n_render_vertices , short * render_vertices , int objnum )
2006-03-20 17:12:09 +00:00
{
int vv ;
2011-04-07 20:32:51 +00:00
if ( ( ( obj_light_emission . r + obj_light_emission . g + obj_light_emission . b ) / 3 ) > 0 )
{
fix obji_64 = ( ( obj_light_emission . r + obj_light_emission . g + obj_light_emission . b ) / 3 ) * 64 ;
2006-03-20 17:12:09 +00:00
// for pretty dim sources, only process vertices in object's own segment.
// 12/04/95, MK, markers only cast light in own segment.
if ( ( abs ( obji_64 ) < = F1_0 * 8 ) | | ( Objects [ objnum ] . type = = OBJ_MARKER ) ) {
short * vp = Segments [ obj_seg ] . verts ;
for ( vv = 0 ; vv < MAX_VERTICES_PER_SEGMENT ; vv + + ) {
int vertnum ;
vms_vector * vertpos ;
fix dist ;
vertnum = vp [ vv ] ;
if ( ( vertnum ^ FrameCount ) & 1 ) {
vertpos = & Vertices [ vertnum ] ;
dist = vm_vec_dist_quick ( obj_pos , vertpos ) ;
dist = fixmul ( dist / 4 , dist / 4 ) ;
if ( dist < abs ( obji_64 ) ) {
if ( dist < MIN_LIGHT_DIST )
dist = MIN_LIGHT_DIST ;
2011-04-07 20:32:51 +00:00
Dynamic_light [ vertnum ] . r + = fixdiv ( obj_light_emission . r , dist ) ;
Dynamic_light [ vertnum ] . g + = fixdiv ( obj_light_emission . g , dist ) ;
Dynamic_light [ vertnum ] . b + = fixdiv ( obj_light_emission . b , dist ) ;
2006-03-20 17:12:09 +00:00
}
}
}
} else {
int headlight_shift = 0 ;
fix max_headlight_dist = F1_0 * 200 ;
if ( Objects [ objnum ] . type = = OBJ_PLAYER )
if ( Players [ Objects [ objnum ] . id ] . flags & PLAYER_FLAGS_HEADLIGHT_ON ) {
headlight_shift = 3 ;
if ( Objects [ objnum ] . id ! = Player_num ) {
vms_vector tvec ;
fvi_query fq ;
fvi_info hit_data ;
int fate ;
vm_vec_scale_add ( & tvec , & Objects [ objnum ] . pos , & Objects [ objnum ] . orient . fvec , F1_0 * 200 ) ;
fq . startseg = Objects [ objnum ] . segnum ;
fq . p0 = & Objects [ objnum ] . pos ;
fq . p1 = & tvec ;
fq . rad = 0 ;
fq . thisobjnum = objnum ;
fq . ignore_obj_list = NULL ;
fq . flags = FQ_TRANSWALL ;
fate = find_vector_intersection ( & fq , & hit_data ) ;
if ( fate ! = HIT_NONE )
max_headlight_dist = vm_vec_mag_quick ( vm_vec_sub ( & tvec , & hit_data . hit_pnt , & Objects [ objnum ] . pos ) ) + F1_0 * 4 ;
}
}
// -- for (vv=FrameCount&1; vv<n_render_vertices; vv+=2) {
for ( vv = 0 ; vv < n_render_vertices ; vv + + ) {
int vertnum ;
vms_vector * vertpos ;
fix dist ;
int apply_light ;
vertnum = render_vertices [ vv ] ;
if ( ( vertnum ^ FrameCount ) & 1 ) {
vertpos = & Vertices [ vertnum ] ;
dist = vm_vec_dist_quick ( obj_pos , vertpos ) ;
apply_light = 0 ;
if ( ( dist > > headlight_shift ) < abs ( obji_64 ) ) {
if ( dist < MIN_LIGHT_DIST )
dist = MIN_LIGHT_DIST ;
//if (Use_fvi_lighting) {
// if (lighting_cache_visible(vertnum, obj_seg, objnum, obj_pos, obj_seg, vertpos)) {
// apply_light = 1;
// }
//} else
apply_light = 1 ;
2011-04-07 20:32:51 +00:00
if ( apply_light )
{
if ( headlight_shift )
{
fix dot ;
vms_vector vec_to_point ;
2006-03-20 17:12:09 +00:00
vm_vec_sub ( & vec_to_point , vertpos , obj_pos ) ;
2011-04-07 20:32:51 +00:00
vm_vec_normalize_quick ( & vec_to_point ) ; // MK, Optimization note: You compute distance about 15 lines up, this is partially redundant
2006-03-20 17:12:09 +00:00
dot = vm_vec_dot ( & vec_to_point , & Objects [ objnum ] . orient . fvec ) ;
if ( dot < F1_0 / 2 )
2011-04-07 20:32:51 +00:00
{
// Do the normal thing, but darken around headlight.
Dynamic_light [ vertnum ] . r + = fixdiv ( obj_light_emission . r , fixmul ( HEADLIGHT_SCALE , dist ) ) ;
Dynamic_light [ vertnum ] . g + = fixdiv ( obj_light_emission . g , fixmul ( HEADLIGHT_SCALE , dist ) ) ;
Dynamic_light [ vertnum ] . b + = fixdiv ( obj_light_emission . b , fixmul ( HEADLIGHT_SCALE , dist ) ) ;
}
else
{
if ( Game_mode & GM_MULTI )
{
2006-03-20 17:12:09 +00:00
if ( dist < max_headlight_dist )
2011-04-07 20:32:51 +00:00
{
Dynamic_light [ vertnum ] . r + = fixmul ( fixmul ( dot , dot ) , obj_light_emission . r ) / 8 ;
Dynamic_light [ vertnum ] . g + = fixmul ( fixmul ( dot , dot ) , obj_light_emission . g ) / 8 ;
Dynamic_light [ vertnum ] . b + = fixmul ( fixmul ( dot , dot ) , obj_light_emission . b ) / 8 ;
}
}
else
{
Dynamic_light [ vertnum ] . r + = fixmul ( fixmul ( dot , dot ) , obj_light_emission . r ) / 8 ;
Dynamic_light [ vertnum ] . g + = fixmul ( fixmul ( dot , dot ) , obj_light_emission . g ) / 8 ;
Dynamic_light [ vertnum ] . b + = fixmul ( fixmul ( dot , dot ) , obj_light_emission . b ) / 8 ;
}
2006-03-20 17:12:09 +00:00
}
2011-04-07 20:32:51 +00:00
}
else
{
Dynamic_light [ vertnum ] . r + = fixdiv ( obj_light_emission . r , dist ) ;
Dynamic_light [ vertnum ] . g + = fixdiv ( obj_light_emission . g , dist ) ;
Dynamic_light [ vertnum ] . b + = fixdiv ( obj_light_emission . b , dist ) ;
}
2006-03-20 17:12:09 +00:00
}
}
}
}
}
}
}
2011-04-07 20:32:51 +00:00
# define FLASH_LEN_FIXED_SECONDS (F1_0 / 3)
# define FLASH_SCALE (3*F1_0 / FLASH_LEN_FIXED_SECONDS)
2006-03-20 17:12:09 +00:00
// ----------------------------------------------------------------------------------------------
void cast_muzzle_flash_light ( int n_render_vertices , short * render_vertices )
{
2010-12-10 23:18:17 +00:00
fix64 current_time ;
2011-04-07 20:32:51 +00:00
int i ;
short time_since_flash ;
2006-03-20 17:12:09 +00:00
2010-12-10 23:18:17 +00:00
current_time = timer_query ( ) ;
2006-03-20 17:12:09 +00:00
2011-04-07 20:32:51 +00:00
for ( i = 0 ; i < MUZZLE_QUEUE_MAX ; i + + )
{
if ( Muzzle_data [ i ] . create_time )
{
2006-03-20 17:12:09 +00:00
time_since_flash = current_time - Muzzle_data [ i ] . create_time ;
if ( time_since_flash < FLASH_LEN_FIXED_SECONDS )
2011-04-07 20:32:51 +00:00
{
g3s_lrgb ml ;
ml . r = ml . g = ml . b = ( ( FLASH_LEN_FIXED_SECONDS - time_since_flash ) * FLASH_SCALE ) ;
apply_light ( ml , Muzzle_data [ i ] . segnum , & Muzzle_data [ i ] . pos , n_render_vertices , render_vertices , - 1 ) ;
}
2006-03-20 17:12:09 +00:00
else
2011-04-07 20:32:51 +00:00
{
Muzzle_data [ i ] . create_time = 0 ; // turn off this muzzle flash
}
2006-03-20 17:12:09 +00:00
}
}
}
2011-04-07 20:32:51 +00:00
// Translation table to make flares flicker at different rates
fix Obj_light_xlate [ 16 ] = { 0x1234 , 0x3321 , 0x2468 , 0x1735 ,
0x0123 , 0x19af , 0x3f03 , 0x232a ,
0x2123 , 0x39af , 0x0f03 , 0x132a ,
0x3123 , 0x29af , 0x1f03 , 0x032a } ;
# define MAX_HEADLIGHTS 8
object * Headlights [ MAX_HEADLIGHTS ] ;
int Num_headlights ;
2006-03-20 17:12:09 +00:00
// ---------------------------------------------------------
2011-04-07 20:32:51 +00:00
g3s_lrgb compute_light_emission ( int objnum )
2006-03-20 17:12:09 +00:00
{
2011-04-07 20:32:51 +00:00
object * obj = & Objects [ objnum ] ;
int compute_color = 0 ;
float cscale = 255.0 ;
fix hoardlight , s , light_intensity = 0 ;
g3s_lrgb lemission , obj_color = { 255 , 255 , 255 } ;
2006-03-20 17:12:09 +00:00
2011-04-07 20:32:51 +00:00
switch ( obj - > type )
{
2006-03-20 17:12:09 +00:00
case OBJ_PLAYER :
2011-04-07 20:32:51 +00:00
if ( Players [ obj - > id ] . flags & PLAYER_FLAGS_HEADLIGHT_ON )
{
2006-03-20 17:12:09 +00:00
if ( Num_headlights < MAX_HEADLIGHTS )
Headlights [ Num_headlights + + ] = obj ;
2011-04-07 20:32:51 +00:00
light_intensity = HEADLIGHT_SCALE ;
}
else if ( ( Game_mode & GM_HOARD ) & & Players [ obj - > id ] . secondary_ammo [ PROXIMITY_INDEX ] ) // If hoard game and player, add extra light based on how many orbs you have Pulse as well.
{
hoardlight = i2f ( Players [ obj - > id ] . secondary_ammo [ PROXIMITY_INDEX ] ) / 2 ; //i2f(12));
2006-03-20 17:12:09 +00:00
hoardlight + + ;
2011-04-07 20:32:51 +00:00
fix_sincos ( ( ( fix ) ( GameTime64 / 2 ) ) & 0xFFFF , & s , NULL ) ; // probably a bad way to do it
s + = F1_0 ;
2006-03-20 17:12:09 +00:00
s > > = 1 ;
2011-04-07 20:32:51 +00:00
hoardlight = fixmul ( s , hoardlight ) ;
light_intensity = ( hoardlight ) ;
}
2006-03-20 17:12:09 +00:00
else
2010-03-28 09:53:12 +00:00
{
vms_vector sthrust = obj - > mtype . phys_info . thrust ;
fix k = fixmuldiv ( obj - > mtype . phys_info . mass , obj - > mtype . phys_info . drag , ( f1_0 - obj - > mtype . phys_info . drag ) ) ;
// smooth thrust value like set_thrust_from_velocity()
vm_vec_copy_scale ( & sthrust , & obj - > mtype . phys_info . velocity , k ) ;
2011-04-07 20:32:51 +00:00
light_intensity = max ( vm_vec_mag_quick ( & sthrust ) / 4 , F1_0 * 2 ) + F1_0 / 2 ;
2010-03-28 09:53:12 +00:00
}
2006-03-20 17:12:09 +00:00
break ;
case OBJ_FIREBALL :
2011-04-07 20:32:51 +00:00
if ( obj - > id ! = 0xff )
{
2006-03-20 17:12:09 +00:00
if ( obj - > lifeleft < F1_0 * 4 )
2011-04-07 20:32:51 +00:00
light_intensity = fixmul ( fixdiv ( obj - > lifeleft , Vclip [ obj - > id ] . play_time ) , Vclip [ obj - > id ] . light_value ) ;
2006-03-20 17:12:09 +00:00
else
2011-04-07 20:32:51 +00:00
light_intensity = Vclip [ obj - > id ] . light_value ;
}
else
light_intensity = 0 ;
2006-03-20 17:12:09 +00:00
break ;
case OBJ_ROBOT :
2011-04-07 20:32:51 +00:00
light_intensity = F1_0 * Robot_info [ obj - > id ] . lightcast ;
2006-03-20 17:12:09 +00:00
break ;
2011-04-07 20:32:51 +00:00
case OBJ_WEAPON :
{
2006-03-20 17:12:09 +00:00
fix tval = Weapon_info [ obj - > id ] . light ;
if ( Game_mode & GM_MULTI )
if ( obj - > id = = OMEGA_ID )
if ( d_rand ( ) > 8192 )
2011-04-07 20:32:51 +00:00
light_intensity = 0 ; // 3/4 of time, omega blobs will cast 0 light!
2006-03-20 17:12:09 +00:00
if ( obj - > id = = FLARE_ID )
2011-04-07 20:32:51 +00:00
light_intensity = 2 * ( min ( tval , obj - > lifeleft ) + ( ( ( ( fix ) GameTime64 ) ^ Obj_light_xlate [ objnum & 0x0f ] ) & 0x3fff ) ) ;
2006-03-20 17:12:09 +00:00
else
2011-04-07 20:32:51 +00:00
light_intensity = tval ;
break ;
2006-03-20 17:12:09 +00:00
}
2011-04-07 20:32:51 +00:00
case OBJ_MARKER :
{
fix lightval = obj - > lifeleft ;
2006-03-20 17:12:09 +00:00
lightval & = 0xffff ;
lightval = 8 * abs ( F1_0 / 2 - lightval ) ;
if ( obj - > lifeleft < F1_0 * 1000 )
2011-04-07 20:32:51 +00:00
obj - > lifeleft + = F1_0 ; // Make sure this object doesn't go out.
2006-03-20 17:12:09 +00:00
2011-04-07 20:32:51 +00:00
light_intensity = lightval ;
break ;
2006-03-20 17:12:09 +00:00
}
case OBJ_POWERUP :
2011-04-07 20:32:51 +00:00
light_intensity = Powerup_info [ obj - > id ] . light ;
2006-03-20 17:12:09 +00:00
break ;
case OBJ_DEBRIS :
2011-04-07 20:32:51 +00:00
light_intensity = F1_0 / 4 ;
2006-03-20 17:12:09 +00:00
break ;
case OBJ_LIGHT :
2011-04-07 20:32:51 +00:00
light_intensity = obj - > ctype . light_info . intensity ;
2006-03-20 17:12:09 +00:00
break ;
default :
2011-04-07 20:32:51 +00:00
light_intensity = 0 ;
break ;
}
lemission . r = lemission . g = lemission . b = light_intensity ;
if ( ! PlayerCfg . DynLightColor ) // colored lights not desired so use intensity only OR no intensity (== no light == no color) at all
return lemission ;
switch ( obj - > type ) // find out if given object should cast colored light and compute if so
{
case OBJ_FIREBALL :
case OBJ_WEAPON :
case OBJ_FLARE :
case OBJ_MARKER :
compute_color = 1 ;
break ;
case OBJ_POWERUP :
{
switch ( obj - > id )
{
case POW_EXTRA_LIFE :
case POW_ENERGY :
case POW_SHIELD_BOOST :
case POW_KEY_BLUE :
case POW_KEY_RED :
case POW_KEY_GOLD :
case POW_CLOAK :
case POW_INVULNERABILITY :
case POW_HOARD_ORB :
compute_color = 1 ;
break ;
default :
break ;
}
2006-03-20 17:12:09 +00:00
break ;
2011-04-07 20:32:51 +00:00
}
}
if ( compute_color )
{
2011-04-12 01:02:51 +00:00
int i , t_idx_s = - 1 , t_idx_e = - 1 ;
2011-04-07 20:32:51 +00:00
if ( light_intensity < F1_0 ) // for every effect we want color, increase light_intensity so the effect becomes barely visible
light_intensity = F1_0 ;
2011-04-12 01:02:51 +00:00
obj_color . r = obj_color . g = obj_color . b = 255 ;
switch ( obj - > render_type )
{
case RT_POLYOBJ :
{
polymodel * po = & Polygon_models [ obj - > rtype . pobj_info . model_num ] ;
if ( po - > n_textures < = 0 )
{
int color = g3_poly_get_color ( po - > model_data ) ;
if ( color )
{
obj_color . r = gr_current_pal [ color * 3 ] ;
obj_color . g = gr_current_pal [ color * 3 + 1 ] ;
obj_color . b = gr_current_pal [ color * 3 + 2 ] ;
}
}
else
{
t_idx_s = ObjBitmaps [ ObjBitmapPtrs [ po - > first_texture ] ] . index ;
t_idx_e = t_idx_s + po - > n_textures - 1 ;
}
break ;
}
case RT_WEAPON_VCLIP :
{
t_idx_s = Vclip [ Weapon_info [ obj - > id ] . weapon_vclip ] . frames [ 0 ] . index ;
t_idx_e = Vclip [ Weapon_info [ obj - > id ] . weapon_vclip ] . frames [ Vclip [ Weapon_info [ obj - > id ] . weapon_vclip ] . num_frames - 1 ] . index ;
break ;
}
default :
{
t_idx_s = Vclip [ obj - > id ] . frames [ 0 ] . index ;
t_idx_e = Vclip [ obj - > id ] . frames [ Vclip [ obj - > id ] . num_frames - 1 ] . index ;
break ;
}
}
2011-04-07 20:32:51 +00:00
2011-04-12 01:02:51 +00:00
if ( t_idx_s ! = - 1 & & t_idx_e ! = - 1 )
{
obj_color . r = obj_color . g = obj_color . b = 0 ;
for ( i = t_idx_s ; i < = t_idx_e ; i + + )
{
grs_bitmap * bm = & GameBitmaps [ i ] ;
obj_color . r + = bm - > avg_color_rgb [ 0 ] ;
obj_color . g + = bm - > avg_color_rgb [ 1 ] ;
obj_color . b + = bm - > avg_color_rgb [ 2 ] ;
}
}
2011-04-07 20:32:51 +00:00
2011-04-13 19:18:18 +00:00
// obviously this object did not give us any usable color. so let's do our own but with blackjack and hookers!
if ( obj_color . r < = 0 & & obj_color . g < = 0 & & obj_color . b < = 0 )
obj_color . r = obj_color . g = obj_color . b = 255 ;
2011-04-07 20:32:51 +00:00
// scale color to light intensity
cscale = ( ( float ) ( light_intensity * 3 ) / ( obj_color . r + obj_color . g + obj_color . b ) ) ;
lemission . r = obj_color . r * cscale ;
lemission . g = obj_color . g * cscale ;
lemission . b = obj_color . b * cscale ;
2006-03-20 17:12:09 +00:00
}
2011-04-07 20:32:51 +00:00
return lemission ;
2006-03-20 17:12:09 +00:00
}
// ----------------------------------------------------------------------------------------------
void set_dynamic_light ( void )
{
int vv ;
int objnum ;
int n_render_vertices ;
short render_vertices [ MAX_VERTICES ] ;
sbyte render_vertex_flags [ MAX_VERTICES ] ;
int render_seg , segnum , v ;
Num_headlights = 0 ;
if ( ! Do_dynamic_light )
return ;
memset ( render_vertex_flags , 0 , Highest_vertex_index + 1 ) ;
// Create list of vertices that need to be looked at for setting of ambient light.
n_render_vertices = 0 ;
for ( render_seg = 0 ; render_seg < N_render_segs ; render_seg + + ) {
segnum = Render_list [ render_seg ] ;
if ( segnum ! = - 1 ) {
short * vp = Segments [ segnum ] . verts ;
for ( v = 0 ; v < MAX_VERTICES_PER_SEGMENT ; v + + ) {
int vnum = vp [ v ] ;
if ( vnum < 0 | | vnum > Highest_vertex_index ) {
Int3 ( ) ; //invalid vertex number
continue ; //ignore it, and go on to next one
}
if ( ! render_vertex_flags [ vnum ] ) {
render_vertex_flags [ vnum ] = 1 ;
render_vertices [ n_render_vertices + + ] = vnum ;
}
}
}
}
for ( vv = 0 ; vv < n_render_vertices ; vv + + ) {
int vertnum ;
vertnum = render_vertices [ vv ] ;
Assert ( vertnum > = 0 & & vertnum < = Highest_vertex_index ) ;
if ( ( vertnum ^ FrameCount ) & 1 )
2011-04-07 20:32:51 +00:00
Dynamic_light [ vertnum ] . r = Dynamic_light [ vertnum ] . g = Dynamic_light [ vertnum ] . b = 0 ;
2006-03-20 17:12:09 +00:00
}
cast_muzzle_flash_light ( n_render_vertices , render_vertices ) ;
for ( objnum = 0 ; objnum < = Highest_object_index ; objnum + + )
2011-04-12 01:02:51 +00:00
{
object * obj = & Objects [ objnum ] ;
vms_vector * objpos = & obj - > pos ;
g3s_lrgb obj_light_emission ;
2006-03-20 17:12:09 +00:00
2011-04-12 01:02:51 +00:00
obj_light_emission = compute_light_emission ( objnum ) ;
2006-03-20 17:12:09 +00:00
2011-04-12 01:02:51 +00:00
if ( ( ( obj_light_emission . r + obj_light_emission . g + obj_light_emission . b ) / 3 ) > 0 )
apply_light ( obj_light_emission , obj - > segnum , objpos , n_render_vertices , render_vertices , objnum ) ;
2006-03-20 17:12:09 +00:00
}
}
// ---------------------------------------------------------
void toggle_headlight_active ( )
{
if ( Players [ Player_num ] . flags & PLAYER_FLAGS_HEADLIGHT ) {
2011-04-07 20:32:51 +00:00
Players [ Player_num ] . flags ^ = PLAYER_FLAGS_HEADLIGHT_ON ;
2006-03-20 17:12:09 +00:00
# ifdef NETWORK
if ( Game_mode & GM_MULTI )
2011-04-07 20:32:51 +00:00
multi_send_flags ( Player_num ) ;
2006-03-20 17:12:09 +00:00
# endif
}
}
# define HEADLIGHT_BOOST_SCALE 8 //how much to scale light when have headlight boost
fix Beam_brightness = ( F1_0 / 2 ) ; //global saying how bright the light beam is
# define MAX_DIST_LOG 6 //log(MAX_DIST-expressed-as-integer)
# define MAX_DIST (f1_0<<MAX_DIST_LOG) //no light beyond this dist
fix compute_headlight_light_on_object ( object * objp )
{
int i ;
fix light ;
// Let's just illuminate players and robots for speed reasons, ok?
if ( ( objp - > type ! = OBJ_ROBOT ) & & ( objp - > type ! = OBJ_PLAYER ) )
return 0 ;
light = 0 ;
for ( i = 0 ; i < Num_headlights ; i + + ) {
fix dot , dist ;
vms_vector vec_to_obj ;
object * light_objp ;
light_objp = Headlights [ i ] ;
vm_vec_sub ( & vec_to_obj , & objp - > pos , & light_objp - > pos ) ;
dist = vm_vec_normalize_quick ( & vec_to_obj ) ;
if ( dist > 0 ) {
dot = vm_vec_dot ( & light_objp - > orient . fvec , & vec_to_obj ) ;
if ( dot < F1_0 / 2 )
light + = fixdiv ( HEADLIGHT_SCALE , fixmul ( HEADLIGHT_SCALE , dist ) ) ; // Do the normal thing, but darken around headlight.
else
light + = fixmul ( fixmul ( dot , dot ) , HEADLIGHT_SCALE ) / 8 ;
}
}
return light ;
}
//compute the average dynamic light in a segment. Takes the segment number
2011-04-07 20:32:51 +00:00
g3s_lrgb compute_seg_dynamic_light ( int segnum )
2006-03-20 17:12:09 +00:00
{
2011-04-07 20:32:51 +00:00
g3s_lrgb sum , seg_lrgb ;
2006-03-20 17:12:09 +00:00
segment * seg ;
short * verts ;
seg = & Segments [ segnum ] ;
verts = seg - > verts ;
2011-04-07 20:32:51 +00:00
sum . r = sum . g = sum . b = 0 ;
sum . r + = Dynamic_light [ * verts ] . r ;
sum . g + = Dynamic_light [ * verts ] . g ;
sum . b + = Dynamic_light [ * verts + + ] . b ;
sum . r + = Dynamic_light [ * verts ] . r ;
sum . g + = Dynamic_light [ * verts ] . g ;
sum . b + = Dynamic_light [ * verts + + ] . b ;
sum . r + = Dynamic_light [ * verts ] . r ;
sum . g + = Dynamic_light [ * verts ] . g ;
sum . b + = Dynamic_light [ * verts + + ] . b ;
sum . r + = Dynamic_light [ * verts ] . r ;
sum . g + = Dynamic_light [ * verts ] . g ;
sum . b + = Dynamic_light [ * verts + + ] . b ;
sum . r + = Dynamic_light [ * verts ] . r ;
sum . g + = Dynamic_light [ * verts ] . g ;
sum . b + = Dynamic_light [ * verts + + ] . b ;
sum . r + = Dynamic_light [ * verts ] . r ;
sum . g + = Dynamic_light [ * verts ] . g ;
sum . b + = Dynamic_light [ * verts + + ] . b ;
sum . r + = Dynamic_light [ * verts ] . r ;
sum . g + = Dynamic_light [ * verts ] . g ;
sum . b + = Dynamic_light [ * verts + + ] . b ;
sum . r + = Dynamic_light [ * verts ] . r ;
sum . g + = Dynamic_light [ * verts ] . g ;
sum . b + = Dynamic_light [ * verts ] . b ;
seg_lrgb . r = sum . r > > 3 ;
seg_lrgb . g = sum . g > > 3 ;
seg_lrgb . b = sum . b > > 3 ;
2006-03-20 17:12:09 +00:00
2011-04-07 20:32:51 +00:00
return seg_lrgb ;
2006-03-20 17:12:09 +00:00
}
2011-04-07 20:32:51 +00:00
g3s_lrgb object_light [ MAX_OBJECTS ] ;
2006-03-20 17:12:09 +00:00
int object_sig [ MAX_OBJECTS ] ;
object * old_viewer ;
int reset_lighting_hack ;
2011-04-07 20:32:51 +00:00
# define LIGHT_RATE i2f(4) //how fast the light ramps up
2006-03-20 17:12:09 +00:00
void start_lighting_frame ( object * viewer )
{
reset_lighting_hack = ( viewer ! = old_viewer ) ;
old_viewer = viewer ;
}
//compute the lighting for an object. Takes a pointer to the object,
//and possibly a rotated 3d point. If the point isn't specified, the
//object's center point is rotated.
2011-04-07 20:32:51 +00:00
g3s_lrgb compute_object_light ( object * obj , vms_vector * rotated_pnt )
2006-03-20 17:12:09 +00:00
{
2011-04-07 20:32:51 +00:00
g3s_lrgb light , seg_dl ;
fix mlight ;
2006-03-20 17:12:09 +00:00
g3s_point objpnt ;
int objnum = obj - Objects ;
2011-04-07 20:32:51 +00:00
if ( ! rotated_pnt )
{
2006-03-20 17:12:09 +00:00
g3_rotate_point ( & objpnt , & obj - > pos ) ;
rotated_pnt = & objpnt . p3_vec ;
}
2011-04-07 20:32:51 +00:00
//First, get static (mono) light for this segment
light . r = light . g = light . b = Segment2s [ obj - > segnum ] . static_light ;
2006-03-20 17:12:09 +00:00
//Now, maybe return different value to smooth transitions
2011-04-07 20:32:51 +00:00
if ( ! reset_lighting_hack & & object_sig [ objnum ] = = obj - > signature )
{
fix frame_delta ;
g3s_lrgb delta_light ;
2006-03-20 17:12:09 +00:00
2011-04-07 20:32:51 +00:00
delta_light . r = light . r - object_light [ objnum ] . r ;
delta_light . g = light . g - object_light [ objnum ] . g ;
delta_light . b = light . b - object_light [ objnum ] . b ;
2006-03-20 17:12:09 +00:00
frame_delta = fixmul ( LIGHT_RATE , FrameTime ) ;
2011-04-07 20:32:51 +00:00
if ( abs ( ( ( delta_light . r + delta_light . g + delta_light . b ) / 3 ) ) < = frame_delta )
{
2006-03-20 17:12:09 +00:00
object_light [ objnum ] = light ; //we've hit the goal
2011-04-07 20:32:51 +00:00
}
2006-03-20 17:12:09 +00:00
else
2011-04-07 20:32:51 +00:00
{
if ( ( ( delta_light . r + delta_light . g + delta_light . b ) / 3 ) < 0 )
{
light . r = object_light [ objnum ] . r - = frame_delta ;
light . g = object_light [ objnum ] . g - = frame_delta ;
light . b = object_light [ objnum ] . b - = frame_delta ;
}
2006-03-20 17:12:09 +00:00
else
2011-04-07 20:32:51 +00:00
{
light . r = object_light [ objnum ] . r + = frame_delta ;
light . g = object_light [ objnum ] . g + = frame_delta ;
light . b = object_light [ objnum ] . b + = frame_delta ;
}
}
2006-03-20 17:12:09 +00:00
}
2011-04-07 20:32:51 +00:00
else //new object, initialize
{
2006-03-20 17:12:09 +00:00
object_sig [ objnum ] = obj - > signature ;
2011-04-07 20:32:51 +00:00
object_light [ objnum ] . r = light . r ;
object_light [ objnum ] . g = light . g ;
object_light [ objnum ] . b = light . b ;
2006-03-20 17:12:09 +00:00
}
2011-04-07 20:32:51 +00:00
//Next, add in (NOTE: WHITE) headlight on this object
mlight = compute_headlight_light_on_object ( obj ) ;
light . r + = mlight ;
light . g + = mlight ;
light . b + = mlight ;
2006-03-20 17:12:09 +00:00
//Finally, add in dynamic light for this segment
2011-04-07 20:32:51 +00:00
seg_dl = compute_seg_dynamic_light ( obj - > segnum ) ;
light . r + = seg_dl . r ;
light . g + = seg_dl . g ;
light . b + = seg_dl . b ;
2006-03-20 17:12:09 +00:00
return light ;
}