2006-03-20 17:12:09 +00:00
/*
2014-06-01 17:55:23 +00:00
* Portions of this file are copyright Rebirth contributors and licensed as
* described in COPYING . txt .
* Portions of this file are copyright Parallax Software and licensed
* according to the Parallax license below .
* See COPYING . txt for license details .
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 .
*
*/
2012-11-11 22:12:51 +00:00
# include <algorithm>
2014-08-12 03:02:50 +00:00
# include <numeric>
2006-03-20 17:12:09 +00:00
# include <stdio.h>
# include <string.h> // for memset()
2012-07-01 02:54:33 +00:00
# include "maths.h"
2006-03-20 17:12:09 +00:00
# include "vecmat.h"
# include "gr.h"
# include "inferno.h"
# include "segment.h"
2012-07-07 18:35:06 +00:00
# include "dxxerror.h"
2006-03-20 17:12:09 +00:00
# include "render.h"
2014-08-12 02:28:03 +00:00
# include "render_state.h"
2006-03-20 17:12:09 +00:00
# include "game.h"
# include "vclip.h"
# include "lighting.h"
# include "3d.h"
2011-04-07 20:32:51 +00:00
# include "interp.h"
2013-12-26 04:18:28 +00:00
# include "gameseg.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"
2011-07-09 19:39:22 +00:00
# include "wall.h"
2006-03-20 17:12:09 +00:00
2012-11-11 22:12:51 +00:00
using std : : min ;
using std : : max ;
2006-03-20 17:12:09 +00:00
int Do_dynamic_light = 1 ;
2011-07-09 19:39:22 +00:00
int use_fcd_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 HEADLIGHT_CONE_DOT (F1_0*9 / 10)
# define HEADLIGHT_SCALE (F1_0*10)
2014-08-16 18:15:16 +00:00
static void add_light_div ( g3s_lrgb & d , const g3s_lrgb & light , const fix & scale )
{
d . r + = fixdiv ( light . r , scale ) ;
d . g + = fixdiv ( light . g , scale ) ;
d . b + = fixdiv ( light . b , scale ) ;
}
static void add_light_dot_square ( g3s_lrgb & d , const g3s_lrgb & light , const fix & dot )
{
auto square = fixmul ( dot , dot ) ;
d . r + = fixmul ( square , light . r ) / 8 ;
d . g + = fixmul ( square , light . g ) / 8 ;
d . b + = fixmul ( square , light . b ) / 8 ;
}
2006-03-20 17:12:09 +00:00
// ----------------------------------------------------------------------------------------------
2013-12-29 04:28:07 +00:00
static void apply_light ( g3s_lrgb obj_light_emission , segnum_t obj_seg , vms_vector * obj_pos , int n_render_vertices , int * render_vertices , segnum_t * vert_segnum_list , objnum_t 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 ;
2011-09-26 17:03:20 +00:00
sbyte is_marker = 0 ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2013-12-26 22:21:16 +00:00
if ( objnum ! = object_none )
2011-09-26 17:03:20 +00:00
if ( Objects [ objnum ] . type = = OBJ_MARKER )
is_marker = 1 ;
2013-03-03 01:03:33 +00:00
# endif
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.
2011-09-26 17:03:20 +00:00
if ( ( abs ( obji_64 ) < = F1_0 * 8 ) | | is_marker ) {
2014-08-16 18:14:00 +00:00
auto & vp = Segments [ obj_seg ] . verts ;
2006-03-20 17:12:09 +00:00
for ( vv = 0 ; vv < MAX_VERTICES_PER_SEGMENT ; vv + + ) {
int vertnum ;
vms_vector * vertpos ;
fix dist ;
vertnum = vp [ vv ] ;
2013-04-18 09:56:32 +00:00
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 ;
2014-08-16 18:15:16 +00:00
add_light_div ( Dynamic_light [ vertnum ] , obj_light_emission , dist ) ;
2006-03-20 17:12:09 +00:00
}
}
} else {
int headlight_shift = 0 ;
fix max_headlight_dist = F1_0 * 200 ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2013-12-26 22:21:16 +00:00
if ( objnum ! = object_none )
2011-09-26 17:03:20 +00:00
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 ;
}
2006-03-20 17:12:09 +00:00
}
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
for ( vv = 0 ; vv < n_render_vertices ; vv + + ) {
2013-12-29 04:28:07 +00:00
int vertnum ;
2006-03-20 17:12:09 +00:00
vms_vector * vertpos ;
fix dist ;
2011-07-09 19:39:22 +00:00
int apply_light = 0 ;
2006-03-20 17:12:09 +00:00
vertnum = render_vertices [ vv ] ;
2013-12-29 04:28:07 +00:00
segnum_t vsegnum = vert_segnum_list [ vv ] ;
2013-04-18 09:56:32 +00:00
vertpos = & Vertices [ vertnum ] ;
2006-03-20 17:12:09 +00:00
2013-04-18 09:56:32 +00:00
if ( use_fcd_lighting & & abs ( obji_64 ) > F1_0 * 32 )
{
2014-09-06 22:26:11 +00:00
dist = find_connected_distance ( obj_pos , obj_seg , vertpos , vsegnum , n_render_vertices , WID_RENDPAST_FLAG | WID_FLY_FLAG ) ;
2013-04-18 09:56:32 +00:00
if ( dist > = 0 )
2011-07-09 19:39:22 +00:00
apply_light = 1 ;
2013-04-18 09:56:32 +00:00
}
else
{
dist = vm_vec_dist_quick ( obj_pos , vertpos ) ;
apply_light = 1 ;
}
2011-07-09 19:39:22 +00:00
2013-04-18 09:56:32 +00:00
if ( apply_light & & ( ( dist > > headlight_shift ) < abs ( obji_64 ) ) ) {
2006-03-20 17:12:09 +00:00
2013-04-18 09:56:32 +00:00
if ( dist < MIN_LIGHT_DIST )
dist = MIN_LIGHT_DIST ;
2006-03-20 17:12:09 +00:00
2013-12-26 22:21:16 +00:00
if ( headlight_shift & & objnum ! = object_none )
2013-04-18 09:56:32 +00:00
{
fix dot ;
vms_vector vec_to_point ;
2006-03-20 17:12:09 +00:00
2013-04-18 09:56:32 +00:00
vm_vec_sub ( & vec_to_point , vertpos , obj_pos ) ;
vm_vec_normalize_quick ( & vec_to_point ) ; // MK, Optimization note: You compute distance about 15 lines up, this is partially redundant
dot = vm_vec_dot ( & vec_to_point , & Objects [ objnum ] . orient . fvec ) ;
if ( dot < F1_0 / 2 )
{
// Do the normal thing, but darken around headlight.
2014-08-16 18:15:16 +00:00
add_light_div ( Dynamic_light [ vertnum ] , obj_light_emission , fixmul ( HEADLIGHT_SCALE , dist ) ) ;
2013-04-18 09:56:32 +00:00
}
else
{
if ( Game_mode & GM_MULTI )
2011-07-09 19:39:22 +00:00
{
2013-04-18 09:56:32 +00:00
if ( dist < max_headlight_dist )
2011-07-09 19:39:22 +00:00
{
2014-08-16 18:15:16 +00:00
add_light_dot_square ( Dynamic_light [ vertnum ] , obj_light_emission , dot ) ;
2011-07-09 19:39:22 +00:00
}
2011-04-07 20:32:51 +00:00
}
2013-04-18 09:56:32 +00:00
else
{
2014-08-16 18:15:16 +00:00
add_light_dot_square ( Dynamic_light [ vertnum ] , obj_light_emission , dot ) ;
2013-04-18 09:56:32 +00:00
}
2006-03-20 17:12:09 +00:00
}
2013-04-18 09:56:32 +00:00
}
else
{
2014-08-16 18:15:16 +00:00
add_light_div ( Dynamic_light [ vertnum ] , obj_light_emission , 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
// ----------------------------------------------------------------------------------------------
2013-12-29 04:28:07 +00:00
static void cast_muzzle_flash_light ( int n_render_vertices , int * render_vertices , segnum_t * vert_segnum_list )
2006-03-20 17:12:09 +00:00
{
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 ) ;
2013-12-26 22:21:16 +00:00
apply_light ( ml , Muzzle_data [ i ] . segnum , & Muzzle_data [ i ] . pos , n_render_vertices , render_vertices , vert_segnum_list , object_none ) ;
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
{
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
2013-11-28 00:23:35 +00:00
static const fix Obj_light_xlate [ 16 ] = { 0x1234 , 0x3321 , 0x2468 , 0x1735 ,
2011-04-07 20:32:51 +00:00
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
// ---------------------------------------------------------
2013-10-27 22:00:14 +00:00
static 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 ;
2013-03-03 01:03:33 +00:00
fix light_intensity = 0 ;
2011-04-07 20:32:51 +00:00
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 :
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
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 ;
}
2013-08-11 16:03:47 +00:00
else if ( game_mode_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.
2011-04-07 20:32:51 +00:00
{
2013-03-03 01:03:33 +00:00
fix s , hoardlight ;
2011-04-07 20:32:51 +00:00
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
2013-03-03 01:03:33 +00:00
# endif
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 :
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_I)
light_intensity = F1_0 / 2 ; // F1_0*Robot_info[obj->id].lightcast;
# elif defined(DXX_BUILD_DESCENT_II)
2013-10-07 23:52:33 +00:00
light_intensity = F1_0 * Robot_info [ get_robot_id ( obj ) ] . lightcast ;
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
break ;
2011-04-07 20:32:51 +00:00
case OBJ_WEAPON :
{
2013-10-07 23:52:33 +00:00
fix tval = Weapon_info [ get_weapon_id ( obj ) ] . light ;
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2006-03-20 17:12:09 +00:00
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!
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
2013-10-07 23:52:33 +00:00
if ( get_weapon_id ( obj ) = = 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
}
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
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
}
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
case OBJ_POWERUP :
2013-10-07 23:52:33 +00:00
light_intensity = Powerup_info [ get_powerup_id ( obj ) ] . 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 :
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2011-04-07 20:32:51 +00:00
case OBJ_MARKER :
2013-03-03 01:03:33 +00:00
# endif
2011-04-07 20:32:51 +00:00
compute_color = 1 ;
break ;
case OBJ_POWERUP :
{
2013-10-07 23:52:33 +00:00
switch ( get_powerup_id ( obj ) )
2011-04-07 20:32:51 +00:00
{
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 :
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
2011-04-07 20:32:51 +00:00
case POW_HOARD_ORB :
2013-03-03 01:03:33 +00:00
# endif
2011-04-07 20:32:51 +00:00
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 )
{
2011-06-20 09:30:12 +00:00
case RT_NONE :
break ; // no object - no light
2011-04-12 01:02:51 +00:00
case RT_POLYOBJ :
{
polymodel * po = & Polygon_models [ obj - > rtype . pobj_info . model_num ] ;
if ( po - > n_textures < = 0 )
{
2014-07-24 03:12:57 +00:00
int color = g3_poly_get_color ( po - > model_data . get ( ) ) ;
2011-04-12 01:02:51 +00:00
if ( color )
{
2013-01-06 21:11:53 +00:00
obj_color . r = gr_current_pal [ color ] . r ;
obj_color . g = gr_current_pal [ color ] . g ;
obj_color . b = gr_current_pal [ color ] . b ;
2011-04-12 01:02:51 +00:00
}
}
else
{
t_idx_s = ObjBitmaps [ ObjBitmapPtrs [ po - > first_texture ] ] . index ;
t_idx_e = t_idx_s + po - > n_textures - 1 ;
}
break ;
}
2011-05-05 18:45:24 +00:00
case RT_LASER :
{
2013-10-07 23:52:33 +00:00
t_idx_s = t_idx_e = Weapon_info [ get_weapon_id ( obj ) ] . bitmap . index ;
2011-05-05 18:45:24 +00:00
break ;
}
2011-06-01 13:49:06 +00:00
case RT_POWERUP :
{
t_idx_s = Vclip [ obj - > rtype . vclip_info . vclip_num ] . frames [ 0 ] . index ;
t_idx_e = Vclip [ obj - > rtype . vclip_info . vclip_num ] . frames [ Vclip [ obj - > rtype . vclip_info . vclip_num ] . num_frames - 1 ] . index ;
break ;
}
2011-04-12 01:02:51 +00:00
case RT_WEAPON_VCLIP :
{
2013-10-07 23:52:33 +00:00
t_idx_s = Vclip [ Weapon_info [ get_weapon_id ( obj ) ] . weapon_vclip ] . frames [ 0 ] . index ;
t_idx_e = Vclip [ Weapon_info [ get_weapon_id ( obj ) ] . weapon_vclip ] . frames [ Vclip [ Weapon_info [ get_weapon_id ( obj ) ] . weapon_vclip ] . num_frames - 1 ] . index ;
2011-04-12 01:02:51 +00:00
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 ] ;
2011-06-04 08:04:39 +00:00
bitmap_index bi ;
bi . index = i ;
PIGGY_PAGE_IN ( bi ) ;
2011-04-12 01:02:51 +00:00
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
}
// ----------------------------------------------------------------------------------------------
2014-08-12 02:28:03 +00:00
void set_dynamic_light ( render_state_t & rstate )
2006-03-20 17:12:09 +00:00
{
int vv ;
int n_render_vertices ;
2011-06-30 10:23:38 +00:00
int render_vertices [ MAX_VERTICES ] ;
2013-12-29 04:28:07 +00:00
segnum_t vert_segnum_list [ MAX_VERTICES ] ;
2006-03-20 17:12:09 +00:00
sbyte render_vertex_flags [ MAX_VERTICES ] ;
2014-08-12 02:28:03 +00:00
int render_seg , v ;
2013-04-18 09:56:32 +00:00
static fix light_time ;
2006-03-20 17:12:09 +00:00
Num_headlights = 0 ;
if ( ! Do_dynamic_light )
return ;
2013-04-18 09:56:32 +00:00
light_time + = FrameTime ;
if ( light_time < ( F1_0 / 60 ) ) // it's enough to stress the CPU 60 times per second
return ;
light_time = light_time - ( F1_0 / 60 ) ;
2011-06-04 08:04:39 +00:00
2006-03-20 17:12:09 +00:00
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 ;
2014-09-07 23:39:38 +00:00
for ( render_seg = 0 ; render_seg < rstate . N_render_segs ; render_seg + + ) {
2013-12-29 04:28:07 +00:00
segnum_t segnum = rstate . Render_list [ render_seg ] ;
2013-12-26 22:21:16 +00:00
if ( segnum ! = segment_none ) {
2014-08-16 18:14:00 +00:00
auto & vp = Segments [ segnum ] . verts ;
2006-03-20 17:12:09 +00:00
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 ;
2011-07-09 19:39:22 +00:00
render_vertices [ n_render_vertices ] = vnum ;
vert_segnum_list [ n_render_vertices ] = segnum ;
n_render_vertices + + ;
2006-03-20 17:12:09 +00:00
}
}
}
}
for ( vv = 0 ; vv < n_render_vertices ; vv + + ) {
int vertnum ;
vertnum = render_vertices [ vv ] ;
Assert ( vertnum > = 0 & & vertnum < = Highest_vertex_index ) ;
2014-07-17 02:43:03 +00:00
Dynamic_light [ vertnum ] = { } ;
2006-03-20 17:12:09 +00:00
}
2011-07-09 19:39:22 +00:00
cast_muzzle_flash_light ( n_render_vertices , render_vertices , vert_segnum_list ) ;
2006-03-20 17:12:09 +00:00
2013-12-29 04:28:07 +00:00
for ( objnum_t 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 )
2011-07-09 19:39:22 +00:00
apply_light ( obj_light_emission , obj - > segnum , objpos , n_render_vertices , render_vertices , vert_segnum_list , objnum ) ;
2006-03-20 17:12:09 +00:00
}
}
// ---------------------------------------------------------
2013-03-03 01:03:33 +00:00
# if defined(DXX_BUILD_DESCENT_II)
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
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
}
}
2013-03-03 01:03:33 +00:00
# endif
2006-03-20 17:12:09 +00:00
# define HEADLIGHT_BOOST_SCALE 8 //how much to scale light when have headlight boost
# define MAX_DIST_LOG 6 //log(MAX_DIST-expressed-as-integer)
# define MAX_DIST (f1_0<<MAX_DIST_LOG) //no light beyond this dist
2013-10-27 22:00:14 +00:00
static fix compute_headlight_light_on_object ( object * objp )
2006-03-20 17:12:09 +00:00
{
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
2013-12-29 04:28:07 +00:00
g3s_lrgb compute_seg_dynamic_light ( segnum_t segnum )
2006-03-20 17:12:09 +00:00
{
segment * seg ;
seg = & Segments [ segnum ] ;
2014-08-12 03:02:50 +00:00
auto op = [ ] ( g3s_lrgb r , unsigned v ) {
r . r + = Dynamic_light [ v ] . r ;
r . g + = Dynamic_light [ v ] . g ;
r . b + = Dynamic_light [ v ] . b ;
return r ;
} ;
g3s_lrgb sum = std : : accumulate ( begin ( seg - > verts ) , end ( seg - > verts ) , g3s_lrgb { 0 , 0 , 0 } , op ) ;
g3s_lrgb seg_lrgb ;
2011-04-07 20:32:51 +00:00
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.
2014-08-16 23:18:17 +00:00
g3s_lrgb compute_object_light ( vobjptridx_t 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 ;
2014-01-11 22:58:58 +00:00
int objnum = obj ;
2006-03-20 17:12:09 +00:00
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
2013-03-03 01:03:33 +00:00
light . r = light . g = light . b = Segments [ 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 ;
}