diff --git a/3d/draw.c b/3d/draw.c index c8a2b70fa..a69d07fb2 100644 --- a/3d/draw.c +++ b/3d/draw.c @@ -143,10 +143,10 @@ bool g3_check_and_draw_poly(int nv,g3s_point **pointlist,vms_vector *norm,vms_ve return 255; } -bool g3_check_and_draw_tmap(int nv,g3s_point **pointlist,g3s_uvl *uvl_list,grs_bitmap *bm,vms_vector *norm,vms_vector *pnt) +bool g3_check_and_draw_tmap(int nv,g3s_point **pointlist,g3s_uvl *uvl_list,g3s_lrgb *light_rgb,grs_bitmap *bm,vms_vector *norm,vms_vector *pnt) { if (do_facing_check(norm,pointlist,pnt)) - return g3_draw_tmap(nv,pointlist,uvl_list,bm); + return g3_draw_tmap(nv,pointlist,uvl_list,light_rgb,bm); else return 255; } @@ -246,7 +246,7 @@ bool must_clip_tmap_face(int nv,g3s_codes cc,grs_bitmap *bm); //draw a texture-mapped face. //returns 1 if off screen, 0 if drew -bool g3_draw_tmap(int nv,g3s_point **pointlist,g3s_uvl *uvl_list,grs_bitmap *bm) +bool g3_draw_tmap(int nv,g3s_point **pointlist,g3s_uvl *uvl_list,g3s_lrgb *light_rgb,grs_bitmap *bm) { int i; g3s_point **bufptr; @@ -266,7 +266,7 @@ bool g3_draw_tmap(int nv,g3s_point **pointlist,g3s_uvl *uvl_list,grs_bitmap *bm) p->p3_u = uvl_list[i].u; p->p3_v = uvl_list[i].v; - p->p3_l = uvl_list[i].l; + p->p3_l = (light_rgb[i].r+light_rgb[i].g+light_rgb[i].b)/3; p->p3_flags |= PF_UVS + PF_LS; diff --git a/3d/interp.c b/3d/interp.c index 3fcfb8cab..e83562ba9 100644 --- a/3d/interp.c +++ b/3d/interp.c @@ -105,9 +105,59 @@ g3s_point *point_list[MAX_POINTS_PER_POLY]; int glow_num = -1; +// check a polymodel for it's color and return it +int g3_poly_get_color(void *model_ptr) +{ + ubyte *p = model_ptr; + int color = 0; + + while (w(p) != OP_EOF) + switch (w(p)) { + case OP_DEFPOINTS: + p += w(p+2)*sizeof(struct vms_vector) + 4; + break; + case OP_DEFP_START: + p += w(p+2)*sizeof(struct vms_vector) + 8; + break; + case OP_FLATPOLY: { + int nv = w(p+2); + if (g3_check_normal_facing(vp(p+4),vp(p+16)) > 0) + color = (w(p+28)); + p += 30 + ((nv&~1)+1)*2; + break; + } + case OP_TMAPPOLY: { + int nv = w(p+2); + p += 30 + ((nv&~1)+1)*2 + nv*12; + break; + } + case OP_SORTNORM: + if (g3_check_normal_facing(vp(p+16),vp(p+4)) > 0) //facing + color = g3_poly_get_color(p+w(p+28)); + else //not facing + color = g3_poly_get_color(p+w(p+30)); + p += 32; + break; + case OP_RODBM: + p+=36; + break; + case OP_SUBCALL: + color = g3_poly_get_color(p+w(p+16)); + p += 20; + break; + case OP_GLOW: + p += 4; + break; + + default: + ; + } + return color; +} + //calls the object interpreter to render an object. The object renderer //is really a seperate pipeline. returns true if drew -bool g3_draw_polygon_model(void *model_ptr,grs_bitmap **model_bitmaps,vms_angvec *anim_angles,fix model_light,fix *glow_values) +bool g3_draw_polygon_model(void *model_ptr,grs_bitmap **model_bitmaps,vms_angvec *anim_angles,g3s_lrgb model_light,fix *glow_values) { ubyte *p = model_ptr; @@ -163,32 +213,40 @@ bool g3_draw_polygon_model(void *model_ptr,grs_bitmap **model_bitmaps,vms_angvec Assert( nv < MAX_POINTS_PER_POLY ); if (g3_check_normal_facing(vp(p+4),vp(p+16)) > 0) { int i; - fix light; + g3s_lrgb light, lrgb_list[nv]; //calculate light from surface normal - - if (glow_num < 0) { //no glow - - light = -vm_vec_dot(&View_matrix.fvec,vp(p+16)); - light = f1_0/4 + (light*3)/4; - light = fixmul(light,model_light); + if (glow_num < 0) //no glow + { + light.r = light.g = light.b = -vm_vec_dot(&View_matrix.fvec,vp(p+16)); + light.r = f1_0/4 + (light.r*3)/4; + light.r = fixmul(light.r,model_light.r); + light.g = f1_0/4 + (light.g*3)/4; + light.g = fixmul(light.g,model_light.g); + light.b = f1_0/4 + (light.b*3)/4; + light.b = fixmul(light.b,model_light.b); } - else { //yes glow - light = glow_values[glow_num]; + else //yes glow + { + light.r = light.g = light.b = glow_values[glow_num]; glow_num = -1; } //now poke light into l values - uvl_list = (g3s_uvl *) (p+30+((nv&~1)+1)*2); for (i=0;ip3_vec.z); if (tmap_drawer_ptr == draw_tmap_flat) { color_array[index4] = 0; + color_array[index4+1] = color_array[index4]; + color_array[index4+2] = color_array[index4]; + color_array[index4+3] = color_alpha; + } else { - color_array[index4] = bm->bm_flags & BM_FLAG_NO_LIGHTING ? 1.0 : f2glf(uvl_list[c].l); + color_array[index4] = bm->bm_flags & BM_FLAG_NO_LIGHTING ? 1.0 : f2glf(light_rgb[c].r); + color_array[index4+1] = bm->bm_flags & BM_FLAG_NO_LIGHTING ? 1.0 : f2glf(light_rgb[c].g); + color_array[index4+2] = bm->bm_flags & BM_FLAG_NO_LIGHTING ? 1.0 : f2glf(light_rgb[c].b); + color_array[index4+3] = color_alpha; } - color_array[index4+1] = color_array[index4]; - color_array[index4+2] = color_array[index4]; - color_array[index4+3] = color_alpha; texcoord_array[index2] = f2glf(uvl_list[c].u); texcoord_array[index2+1] = f2glf(uvl_list[c].v); } @@ -934,12 +938,12 @@ bool g3_draw_tmap(int nv,g3s_point **pointlist,g3s_uvl *uvl_list,grs_bitmap *bm) /* * Everything texturemapped with secondary texture (walls with secondary texture) */ -bool g3_draw_tmap_2(int nv, g3s_point **pointlist, g3s_uvl *uvl_list, grs_bitmap *bmbot, grs_bitmap *bm, int orient) +bool g3_draw_tmap_2(int nv, g3s_point **pointlist, g3s_uvl *uvl_list, g3s_lrgb *light_rgb, grs_bitmap *bmbot, grs_bitmap *bm, int orient) { int c, index2, index3, index4;; GLfloat vertex_array[nv*3], color_array[nv*4], texcoord_array[nv*2]; - g3_draw_tmap(nv,pointlist,uvl_list,bmbot);//draw the bottom texture first.. could be optimized with multitexturing.. + g3_draw_tmap(nv,pointlist,uvl_list,light_rgb,bmbot);//draw the bottom texture first.. could be optimized with multitexturing.. glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); @@ -974,9 +978,9 @@ bool g3_draw_tmap_2(int nv, g3s_point **pointlist, g3s_uvl *uvl_list, grs_bitmap break; } - color_array[index4] = bm->bm_flags & BM_FLAG_NO_LIGHTING ? 1.0 : f2glf(uvl_list[c].l); - color_array[index4+1] = color_array[c*4]; - color_array[index4+2] = color_array[c*4]; + color_array[index4] = bm->bm_flags & BM_FLAG_NO_LIGHTING ? 1.0 : f2glf(light_rgb[c].r); + color_array[index4+1] = bm->bm_flags & BM_FLAG_NO_LIGHTING ? 1.0 : f2glf(light_rgb[c].g); + color_array[index4+2] = bm->bm_flags & BM_FLAG_NO_LIGHTING ? 1.0 : f2glf(light_rgb[c].b); color_array[index4+3] = (grd_curcanv->cv_fade_level >= GR_FADE_OFF)?1.0:(1.0 - (float)grd_curcanv->cv_fade_level / ((float)GR_FADE_LEVELS - 1.0)); vertex_array[index3] = f2glf(pointlist[c]->p3_vec.x); diff --git a/include/3d.h b/include/3d.h index 4369b9b38..68bc161d6 100644 --- a/include/3d.h +++ b/include/3d.h @@ -54,6 +54,11 @@ typedef struct g3s_uvl { fix u,v,l; } g3s_uvl; +//Structure for storing light color. Also uses l of g3s-uvl to add/compute mono (white) light +typedef struct g3s_lrgb { + fix r,g,b; +} g3s_lrgb; + //Stucture to store clipping codes in a word typedef struct g3s_codes { ubyte or,and; //or is low byte, and is high byte @@ -192,7 +197,7 @@ bool g3_draw_poly(int nv,g3s_point **pointlist); //draw a texture-mapped face. //returns 1 if off screen, 0 if drew -bool g3_draw_tmap(int nv,g3s_point **pointlist,g3s_uvl *uvl_list,grs_bitmap *bm); +bool g3_draw_tmap(int nv,g3s_point **pointlist,g3s_uvl *uvl_list,g3s_lrgb *light_rgb,grs_bitmap *bm); //draw a sortof sphere - i.e., the 2d radius is proportional to the 3d //radius, but not to the distance from the eye @@ -209,7 +214,7 @@ int g3_draw_sphere(g3s_point *pnt,fix rad); //g3_draw_poly(). //returns -1 if not facing, 1 if off screen, 0 if drew bool g3_check_and_draw_poly(int nv,g3s_point **pointlist,vms_vector *norm,vms_vector *pnt); -bool g3_check_and_draw_tmap(int nv,g3s_point **pointlist,g3s_uvl *uvl_list,grs_bitmap *bm,vms_vector *norm,vms_vector *pnt); +bool g3_check_and_draw_tmap(int nv,g3s_point **pointlist,g3s_uvl *uvl_list,g3s_lrgb *light_rgb, grs_bitmap *bm,vms_vector *norm,vms_vector *pnt); //draws a line. takes two points. bool g3_draw_line(g3s_point *p0,g3s_point *p1); @@ -220,7 +225,7 @@ bool g3_draw_rod_flat(g3s_point *bot_point,fix bot_width,g3s_point *top_point,fi //draw a bitmap object that is always facing you //returns 1 if off screen, 0 if drew -bool g3_draw_rod_tmap(grs_bitmap *bitmap,g3s_point *bot_point,fix bot_width,g3s_point *top_point,fix top_width,fix light); +bool g3_draw_rod_tmap(grs_bitmap *bitmap,g3s_point *bot_point,fix bot_width,g3s_point *top_point,fix top_width,g3s_lrgb light); //draws a bitmap with the specified 3d width & height //returns 1 if off screen, 0 if drew @@ -237,13 +242,16 @@ void g3_set_interp_points(g3s_point *pointlist); //calls the object interpreter to render an object. The object renderer //is really a seperate pipeline. returns true if drew -bool g3_draw_polygon_model(void *model_ptr,grs_bitmap **model_bitmaps,vms_angvec *anim_angles,fix light,fix *glow_values); +bool g3_draw_polygon_model(void *model_ptr,grs_bitmap **model_bitmaps,vms_angvec *anim_angles,g3s_lrgb light,fix *glow_values); //init code for bitmap models void g3_init_polygon_model(void *model_ptr); //alternate interpreter for morphing object -bool g3_draw_morphing_model(void *model_ptr,grs_bitmap **model_bitmaps,vms_angvec *anim_angles,fix light,vms_vector *new_points); +bool g3_draw_morphing_model(void *model_ptr,grs_bitmap **model_bitmaps,vms_angvec *anim_angles,g3s_lrgb light,vms_vector *new_points); + +// check a polymodel for it's color and return it +int g3_poly_get_color(void *model_ptr); // routine to convert little to big endian in polygon model data void swap_polygon_model_data(ubyte *data); diff --git a/include/ogl_init.h b/include/ogl_init.h index 19aa7c8ef..66ff53d77 100644 --- a/include/ogl_init.h +++ b/include/ogl_init.h @@ -101,7 +101,7 @@ void ogl_upixelc(int x, int y, int c); void ogl_ulinec(int left, int top, int right, int bot, int c); #include "3d.h" -bool g3_draw_tmap_2(int nv,g3s_point **pointlist,g3s_uvl *uvl_list,grs_bitmap *bmbot,grs_bitmap *bm, int orient); +bool g3_draw_tmap_2(int nv,g3s_point **pointlist,g3s_uvl *uvl_list,g3s_lrgb *light_rgb, grs_bitmap *bmbot,grs_bitmap *bm, int orient); void ogl_draw_vertex_reticle(int cross,int primary,int secondary,int color,int alpha,int size_offs); void ogl_toggle_depth_test(int enable); diff --git a/main/endlevel.c b/main/endlevel.c index a2a94dd6d..9f13021ca 100644 --- a/main/endlevel.c +++ b/main/endlevel.c @@ -821,11 +821,12 @@ void draw_exit_model() { vms_vector model_pos; int f=15,u=0; //21; + g3s_lrgb lrgb = { f1_0, f1_0, f1_0 }; vm_vec_scale_add(&model_pos,&mine_exit_point,&mine_exit_orient.fvec,i2f(f)); vm_vec_scale_add2(&model_pos,&mine_exit_orient.uvec,i2f(u)); - draw_polygon_model(&model_pos,&mine_exit_orient,NULL,(mine_destroyed)?destroyed_exit_modelnum:exit_modelnum,0,f1_0,NULL,NULL); + draw_polygon_model(&model_pos,&mine_exit_orient,NULL,(mine_destroyed)?destroyed_exit_modelnum:exit_modelnum,0,lrgb,NULL,NULL); } @@ -841,6 +842,7 @@ void render_external_scene(fix eye_offset) { int orig_Render_depth = Render_depth; Viewer_eye = Viewer->pos; + g3s_lrgb lrgb = { f1_0, f1_0, f1_0 }; if (eye_offset) vm_vec_scale_add2(&Viewer_eye,&Viewer->orient.rvec,eye_offset); @@ -871,14 +873,14 @@ void render_external_scene(fix eye_offset) if (! (p.p3_flags & PF_OVERFLOW)) { Interpolation_method = 0; //gr_bitmapm(f2i(p.p3_sx)-32,f2i(p.p3_sy)-32,satellite_bitmap); - g3_draw_rod_tmap(satellite_bitmap,&p,SATELLITE_WIDTH,&top_pnt,SATELLITE_WIDTH,f1_0); + g3_draw_rod_tmap(satellite_bitmap,&p,SATELLITE_WIDTH,&top_pnt,SATELLITE_WIDTH,lrgb); Interpolation_method = save_im; } } } #ifdef STATION_ENABLED - draw_polygon_model(&station_pos,&vmd_identity_matrix,NULL,station_modelnum,0,f1_0,NULL,NULL); + draw_polygon_model(&station_pos,&vmd_identity_matrix,NULL,station_modelnum,0,lrgb,NULL,NULL); #endif #ifdef OGL diff --git a/main/gamesave.c b/main/gamesave.c index c12d56ae9..6788fda25 100644 --- a/main/gamesave.c +++ b/main/gamesave.c @@ -525,6 +525,7 @@ void read_object(object *obj,CFILE *f,int version) #endif obj->rtype.pobj_info.alt_textures = 0; + obj->rtype.pobj_info.lrgb.r = obj->rtype.pobj_info.lrgb.g = obj->rtype.pobj_info.lrgb.b = -1; break; } @@ -537,6 +538,7 @@ void read_object(object *obj,CFILE *f,int version) obj->rtype.vclip_info.vclip_num = convert_vclip(cfile_read_int(f)); obj->rtype.vclip_info.frametime = cfile_read_fix(f); obj->rtype.vclip_info.framenum = cfile_read_byte(f); + obj->rtype.vclip_info.lrgb.r = obj->rtype.vclip_info.lrgb.g = obj->rtype.vclip_info.lrgb.b = -1; break; diff --git a/main/lighting.c b/main/lighting.c index 839cf3a74..7140c98bd 100644 --- a/main/lighting.c +++ b/main/lighting.c @@ -34,16 +34,19 @@ COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. #include "laser.h" #include "timer.h" #include "player.h" +#include "playsave.h" #include "weapon.h" #include "powerup.h" #include "fvi.h" #include "robot.h" #include "multi.h" +#include "palette.h" +#include "bm.h" +#include "rle.h" int Do_dynamic_light=1; //int Use_fvi_lighting = 0; - -fix Dynamic_light[MAX_VERTICES]; +g3s_lrgb Dynamic_light[MAX_VERTICES]; #define LIGHTING_CACHE_SIZE 4096 // Must be power of 2! #define LIGHTING_FRAME_DELTA 256 // Recompute cache value every 8 frames. @@ -121,12 +124,13 @@ Cache_hits++; #define HEADLIGHT_SCALE (F1_0*10) // ---------------------------------------------------------------------------------------------- -void apply_light(fix obj_intensity, int obj_seg, vms_vector *obj_pos, int n_render_vertices, short *render_vertices, int objnum) +void apply_light(g3s_lrgb obj_light_emission, int obj_seg, vms_vector *obj_pos, int n_render_vertices, short *render_vertices, int objnum) { int vv; - if (obj_intensity) { - fix obji_64 = obj_intensity*64; + 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; // for pretty dim sources, only process vertices in object's own segment. // 12/04/95, MK, markers only cast light in own segment. @@ -147,7 +151,9 @@ void apply_light(fix obj_intensity, int obj_seg, vms_vector *obj_pos, int n_rend if (dist < MIN_LIGHT_DIST) dist = MIN_LIGHT_DIST; - Dynamic_light[vertnum] += fixdiv(obj_intensity, dist); + 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); } } } @@ -180,25 +186,48 @@ void apply_light(fix obj_intensity, int obj_seg, vms_vector *obj_pos, int n_rend //} else apply_light = 1; - if (apply_light) { - if (headlight_shift) { - fix dot; - vms_vector vec_to_point; + if (apply_light) + { + if (headlight_shift) + { + fix dot; + vms_vector vec_to_point; 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 + 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) - Dynamic_light[vertnum] += fixdiv(obj_intensity, fixmul(HEADLIGHT_SCALE, dist)); // Do the normal thing, but darken around headlight. - else { - if (Game_mode & GM_MULTI) { - if (dist < max_headlight_dist) - Dynamic_light[vertnum] += fixmul(fixmul(dot, dot), obj_intensity)/8; - } else - Dynamic_light[vertnum] += fixmul(fixmul(dot, dot), obj_intensity)/8; + { + // 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 - Dynamic_light[vertnum] += fixdiv(obj_intensity, dist); + else + { + if (Game_mode & GM_MULTI) + { + if (dist < max_headlight_dist) + { + 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; + } + } + } + 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); + } } } } @@ -207,93 +236,272 @@ void apply_light(fix obj_intensity, int obj_seg, vms_vector *obj_pos, int n_rend } } -#define FLASH_LEN_FIXED_SECONDS (F1_0/3) -#define FLASH_SCALE (3*F1_0/FLASH_LEN_FIXED_SECONDS) +#define FLASH_LEN_FIXED_SECONDS (F1_0/3) +#define FLASH_SCALE (3*F1_0/FLASH_LEN_FIXED_SECONDS) // ---------------------------------------------------------------------------------------------- void cast_muzzle_flash_light(int n_render_vertices, short *render_vertices) { fix64 current_time; - int i; - short time_since_flash; + int i; + short time_since_flash; current_time = timer_query(); - for (i=0; irender_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; + } + } + + if (t_idx_s != -1 && t_idx_e != -1) + { + for (i = t_idx_s; i <= t_idx_e; i++) + { + grs_bitmap *bm = &GameBitmaps[i]; + ubyte buf[bm->bm_w*bm->bm_h]; + + if (!bm->bm_data) + return obj_color; + + memset(&buf,0,bm->bm_w*bm->bm_h); + + if (bm->bm_flags & BM_FLAG_RLE){ + unsigned char * dbits; + unsigned char * sbits; + int data_offset; + + data_offset = 1; + if (bm->bm_flags & BM_FLAG_RLE_BIG) + data_offset = 2; + + sbits = &bm->bm_data[4 + (bm->bm_h * data_offset)]; + dbits = buf; + + for (i=0; i < bm->bm_h; i++ ) { + gr_rle_decode(sbits,dbits); + if ( bm->bm_flags & BM_FLAG_RLE_BIG ) + sbits += (int)INTEL_SHORT(*((short *)&(bm->bm_data[4+(i*data_offset)]))); + else + sbits += (int)bm->bm_data[4+i]; + dbits += bm->bm_w; + } + } + else + { + memcpy(&buf, bm->bm_data, sizeof(unsigned char)*(bm->bm_w*bm->bm_h)); + } + + i = 0; + for (x = 0; x < bm->bm_h; x++) + { + for (y = 0; y < bm->bm_w; y++) + { + color = buf[i++]; + t_color.r = gr_palette[color*3]; + t_color.g = gr_palette[color*3+1]; + t_color.b = gr_palette[color*3+2]; + if (!(color == TRANSPARENCY_COLOR || (t_color.r == t_color.g && t_color.r == t_color.b))) + { + obj_color.r += t_color.r; + obj_color.g += t_color.g; + obj_color.b += t_color.b; + count++; + } + } + } + } + + if (count) + { + obj_color.r /= count; + obj_color.g /= count; + obj_color.b /= count; + } + } + + if (obj->render_type == RT_POLYOBJ) + obj->rtype.pobj_info.lrgb = obj_color; + else + obj->rtype.vclip_info.lrgb = obj_color; + + return obj_color; +} // --------------------------------------------------------- -fix compute_light_intensity(int objnum) +g3s_lrgb compute_light_emission(int objnum) { - object *obj = &Objects[objnum]; - int objtype = obj->type; + object *obj = &Objects[objnum]; + int compute_color = 0; + float cscale = 255.0; + fix light_intensity = 0; + g3s_lrgb lemission, obj_color = { 255, 255, 255 }; - switch (objtype) { + switch (obj->type) + { case OBJ_PLAYER: { - 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); - return max(vm_vec_mag_quick(&sthrust)/4, F1_0*2) + F1_0/2; + 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); + light_intensity = max(vm_vec_mag_quick(&sthrust)/4, F1_0*2) + F1_0/2; break; } case OBJ_FIREBALL: - if (obj->id != 0xff) { + if (obj->id != 0xff) + { if (obj->lifeleft < F1_0*4) - return fixmul(fixdiv(obj->lifeleft, Vclip[obj->id].play_time), Vclip[obj->id].light_value); + light_intensity = fixmul(fixdiv(obj->lifeleft, Vclip[obj->id].play_time), Vclip[obj->id].light_value); else - return Vclip[obj->id].light_value; - } else - return 0; + light_intensity = Vclip[obj->id].light_value; + } + else + light_intensity = 0; break; case OBJ_ROBOT: - return F1_0/2; // F1_0*Robot_info[obj->id].lightcast; + light_intensity = F1_0/2; // F1_0*Robot_info[obj->id].lightcast; break; - case OBJ_WEAPON: { + case OBJ_WEAPON: + { fix tval = Weapon_info[obj->id].light; if (obj->id == FLARE_ID ) - return 2* (min(tval, obj->lifeleft) + ((((fix)GameTime64) ^ Obj_light_xlate[objnum&0x0f]) & 0x3fff)); + light_intensity = 2* (min(tval, obj->lifeleft) + ((((fix)GameTime64) ^ Obj_light_xlate[objnum&0x0f]) & 0x3fff)); else - return tval; + light_intensity = tval; + break; } - case OBJ_POWERUP: - return Powerup_info[obj->id].light; + light_intensity = Powerup_info[obj->id].light; break; case OBJ_DEBRIS: - return F1_0/4; + light_intensity = F1_0/4; break; case OBJ_LIGHT: - return obj->ctype.light_info.intensity; + light_intensity = obj->ctype.light_info.intensity; break; default: - return 0; + 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: + 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: + compute_color = 1; + break; + default: + break; + } + break; + } + } + + if (compute_color) + { + if (light_intensity < F1_0) // for every effect we want color, increase light_intensity so the effect becomes barely visible + light_intensity = F1_0; + + obj_color = (obj->render_type == RT_POLYOBJ)?obj->rtype.pobj_info.lrgb:obj->rtype.vclip_info.lrgb; + + if (obj_color.r == -1 || obj_color.g == -1 || obj_color.b == -1) // object does not have any color value, yet. compute! + obj_color = compute_lrgb_on(obj); + + // 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; + } + + return lemission; } // ---------------------------------------------------------------------------------------------- @@ -346,7 +554,7 @@ void set_dynamic_light(void) vertnum = render_vertices[vv]; Assert(vertnum >= 0 && vertnum <= Highest_vertex_index); if ((vertnum ^ FrameCount) & 1) - Dynamic_light[vertnum] = 0; + Dynamic_light[vertnum].r = Dynamic_light[vertnum].g = Dynamic_light[vertnum].b = 0; } cast_muzzle_flash_light(n_render_vertices, render_vertices); @@ -366,12 +574,12 @@ void set_dynamic_light(void) while (objnum != -1) { object *obj = &Objects[objnum]; vms_vector *objpos = &obj->pos; - fix obj_intensity; + g3s_lrgb obj_light_emission; - obj_intensity = compute_light_intensity(objnum); + obj_light_emission = compute_light_emission(objnum); - if (obj_intensity) { - apply_light(obj_intensity, obj->segnum, objpos, n_render_vertices, render_vertices, obj-Objects); + 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, obj-Objects); new_lighting_objects[objnum] = 1; } @@ -387,12 +595,12 @@ void set_dynamic_light(void) // Lighted last frame, but not this frame. Get intensity... object *obj = &Objects[objnum]; vms_vector *objpos = &obj->pos; - fix obj_intensity; + g3s_lrgb obj_light_emission; - obj_intensity = compute_light_intensity(objnum); + obj_light_emission = compute_light_emission(objnum); - if (obj_intensity) { - apply_light(obj_intensity, obj->segnum, objpos, n_render_vertices, render_vertices, objnum); + 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); Lighting_objects[objnum] = 1; } else Lighting_objects[objnum] = 0; @@ -447,159 +655,134 @@ fix compute_headlight_light_on_object(object *objp) return light; } - -// -- Unused -- //Compute the lighting from the headlight for a given vertex on a face. -// -- Unused -- //Takes: -// -- Unused -- // point - the 3d coords of the point -// -- Unused -- // face_light - a scale factor derived from the surface normal of the face -// -- Unused -- //If no surface normal effect is wanted, pass F1_0 for face_light -// -- Unused -- fix compute_headlight_light(vms_vector *point,fix face_light) -// -- Unused -- { -// -- Unused -- fix light; -// -- Unused -- int use_beam = 0; //flag for beam effect -// -- Unused -- -// -- Unused -- light = Beam_brightness; -// -- Unused -- -// -- Unused -- if ((Players[Player_num].flags & PLAYER_FLAGS_HEADLIGHT) && (Players[Player_num].flags & PLAYER_FLAGS_HEADLIGHT_ON) && Viewer==&Objects[Players[Player_num].objnum] && Players[Player_num].energy > 0) { -// -- Unused -- light *= HEADLIGHT_BOOST_SCALE; -// -- Unused -- use_beam = 1; //give us beam effect -// -- Unused -- } -// -- Unused -- -// -- Unused -- if (light) { //if no beam, don't bother with the rest of this -// -- Unused -- fix point_dist; -// -- Unused -- -// -- Unused -- point_dist = vm_vec_mag_quick(point); -// -- Unused -- -// -- Unused -- if (point_dist >= MAX_DIST) -// -- Unused -- -// -- Unused -- light = 0; -// -- Unused -- -// -- Unused -- else { -// -- Unused -- fix dist_scale,face_scale; -// -- Unused -- -// -- Unused -- dist_scale = (MAX_DIST - point_dist) >> MAX_DIST_LOG; -// -- Unused -- light = fixmul(light,dist_scale); -// -- Unused -- -// -- Unused -- if (face_light < 0) -// -- Unused -- face_light = 0; -// -- Unused -- -// -- Unused -- face_scale = f1_0/4 + face_light/2; -// -- Unused -- light = fixmul(light,face_scale); -// -- Unused -- -// -- Unused -- if (use_beam) { -// -- Unused -- fix beam_scale; -// -- Unused -- -// -- Unused -- if (face_light > f1_0*3/4 && point->z > i2f(12)) { -// -- Unused -- beam_scale = fixdiv(point->z,point_dist); -// -- Unused -- beam_scale = fixmul(beam_scale,beam_scale); //square it -// -- Unused -- light = fixmul(light,beam_scale); -// -- Unused -- } -// -- Unused -- } -// -- Unused -- } -// -- Unused -- } -// -- Unused -- -// -- Unused -- return light; -// -- Unused -- } - //compute the average dynamic light in a segment. Takes the segment number -fix compute_seg_dynamic_light(int segnum) +g3s_lrgb compute_seg_dynamic_light(int segnum) { - fix sum; + g3s_lrgb sum, seg_lrgb; segment *seg; short *verts; seg = &Segments[segnum]; verts = seg->verts; - sum = 0; + sum.r = sum.g = sum.b = 0; - sum += Dynamic_light[*verts++]; - sum += Dynamic_light[*verts++]; - sum += Dynamic_light[*verts++]; - sum += Dynamic_light[*verts++]; - sum += Dynamic_light[*verts++]; - sum += Dynamic_light[*verts++]; - sum += Dynamic_light[*verts++]; - sum += Dynamic_light[*verts]; - - return sum >> 3; + 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; + return seg_lrgb; } -fix object_light[MAX_OBJECTS]; +g3s_lrgb object_light[MAX_OBJECTS]; int object_sig[MAX_OBJECTS]; object *old_viewer; int reset_lighting_hack; -#define LIGHT_RATE i2f(4) //how fast the light ramps up +#define LIGHT_RATE i2f(4) //how fast the light ramps up 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. -fix compute_object_light(object *obj,vms_vector *rotated_pnt) +g3s_lrgb compute_object_light(object *obj,vms_vector *rotated_pnt) { - fix light; + g3s_lrgb light, seg_dl; + fix mlight; g3s_point objpnt; int objnum = obj-Objects; - if (!rotated_pnt) { + if (!rotated_pnt) + { g3_rotate_point(&objpnt,&obj->pos); rotated_pnt = &objpnt.p3_vec; } - //First, get static light for this segment - - light = Segments[obj->segnum].static_light; - - //return light; + //First, get static (mono) light for this segment + light.r = light.g = light.b = Segments[obj->segnum].static_light; //Now, maybe return different value to smooth transitions + if (!reset_lighting_hack && object_sig[objnum] == obj->signature) + { + fix frame_delta; + g3s_lrgb delta_light; - if (!reset_lighting_hack && object_sig[objnum] == obj->signature) { - fix delta_light,frame_delta; - - delta_light = light - object_light[objnum]; + 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; frame_delta = fixmul(LIGHT_RATE,FrameTime); - if (abs(delta_light) <= frame_delta) - + if (abs(((delta_light.r+delta_light.g+delta_light.b)/3)) <= frame_delta) + { object_light[objnum] = light; //we've hit the goal - + } else - - if (delta_light < 0) - light = object_light[objnum] -= frame_delta; + { + 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; + } else - light = object_light[objnum] += frame_delta; + { + light.r = object_light[objnum].r += frame_delta; + light.g = object_light[objnum].g += frame_delta; + light.b = object_light[objnum].b += frame_delta; + } + } } - else { //new object, initialize - + else //new object, initialize + { object_sig[objnum] = obj->signature; - object_light[objnum] = light; + object_light[objnum].r = light.r; + object_light[objnum].g = light.g; + object_light[objnum].b = light.b; } - - - //Next, add in headlight on this object - - // -- Matt code: light += compute_headlight_light(rotated_pnt,f1_0); - light += compute_headlight_light_on_object(obj); + //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; //Finally, add in dynamic light for this segment - - light += compute_seg_dynamic_light(obj->segnum); - + seg_dl = compute_seg_dynamic_light(obj->segnum); + light.r += seg_dl.r; + light.g += seg_dl.g; + light.b += seg_dl.b; return light; } - - diff --git a/main/lighting.h b/main/lighting.h index 40b2c5488..c92f29a52 100644 --- a/main/lighting.h +++ b/main/lighting.h @@ -27,7 +27,7 @@ COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. #define MIN_LIGHT_DIST (F1_0*4) extern fix Beam_brightness; -extern fix Dynamic_light[MAX_VERTICES]; +extern g3s_lrgb Dynamic_light[MAX_VERTICES]; extern void set_dynamic_light(void); @@ -39,12 +39,12 @@ extern void set_dynamic_light(void); fix compute_headlight_light(vms_vector *point,fix face_light); // compute the average dynamic light in a segment. Takes the segment number -fix compute_seg_dynamic_light(int segnum); +g3s_lrgb compute_seg_dynamic_light(int segnum); // 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. -fix compute_object_light(object *obj,vms_vector *rotated_pnt); +g3s_lrgb compute_object_light(object *obj,vms_vector *rotated_pnt); // turn headlight boost on & off void toggle_headlight_active(void); diff --git a/main/menu.c b/main/menu.c index e6fadee42..ddba7d648 100644 --- a/main/menu.c +++ b/main/menu.c @@ -1211,7 +1211,7 @@ void reticle_config() PlayerCfg.ReticleSize = m[opt_ret_size].value; } -int opt_gr_texfilt, opt_gr_brightness, opt_gr_reticlemenu, opt_gr_alphafx, opt_gr_vsync, opt_gr_multisample, opt_gr_fpsindi; +int opt_gr_texfilt, opt_gr_brightness, opt_gr_reticlemenu, opt_gr_alphafx, opt_gr_dynlightcolor, opt_gr_vsync, opt_gr_multisample, opt_gr_fpsindi; int graphics_config_menuset(newmenu *menu, d_event *event, void *userdata) { newmenu_item *items = newmenu_get_items(menu); @@ -1252,7 +1252,7 @@ int graphics_config_menuset(newmenu *menu, d_event *event, void *userdata) void graphics_config() { #ifdef OGL - newmenu_item m[12]; + newmenu_item m[13]; int i = 0; #else newmenu_item m[3]; @@ -1275,6 +1275,8 @@ void graphics_config() #ifdef OGL opt_gr_alphafx = nitems; m[nitems].type = NM_TYPE_CHECK; m[nitems].text = "Transparency Effects"; m[nitems].value = PlayerCfg.AlphaEffects; nitems++; + opt_gr_dynlightcolor = nitems; + m[nitems].type = NM_TYPE_CHECK; m[nitems].text = "Colored Dynamic Light"; m[nitems].value = PlayerCfg.DynLightColor; nitems++; opt_gr_vsync = nitems; m[nitems].type = NM_TYPE_CHECK; m[nitems].text="VSync"; m[nitems].value = GameCfg.VSync; nitems++; opt_gr_multisample = nitems; @@ -1296,6 +1298,7 @@ void graphics_config() if (m[i+opt_gr_texfilt].value) GameCfg.TexFilt = i; PlayerCfg.AlphaEffects = m[opt_gr_alphafx].value; + PlayerCfg.DynLightColor = m[opt_gr_dynlightcolor].value; GameCfg.VSync = m[opt_gr_vsync].value; GameCfg.Multisample = m[opt_gr_multisample].value; #endif diff --git a/main/morph.c b/main/morph.c index 2d25d79db..6e3c81811 100644 --- a/main/morph.c +++ b/main/morph.c @@ -321,7 +321,7 @@ void morph_start(object *obj) } -void draw_model(polymodel *pm,int submodel_num,vms_angvec *anim_angles,fix light,morph_data *md) +void draw_model(polymodel *pm,int submodel_num,vms_angvec *anim_angles,g3s_lrgb light,morph_data *md) { int i,mn; int facing; @@ -411,7 +411,7 @@ void draw_morph_object(object *obj) { // int save_light; polymodel *po; - fix light; + g3s_lrgb light; morph_data *md; md = find_morph_data(obj); diff --git a/main/multi.c b/main/multi.c index d8098547e..125863ba5 100644 --- a/main/multi.c +++ b/main/multi.c @@ -3860,6 +3860,7 @@ void multi_object_rw_to_object(object_rw *obj_rw, object *obj) obj->rtype.pobj_info.subobj_flags = obj_rw->rtype.pobj_info.subobj_flags; obj->rtype.pobj_info.tmap_override = obj_rw->rtype.pobj_info.tmap_override; obj->rtype.pobj_info.alt_textures = obj_rw->rtype.pobj_info.alt_textures; + obj->rtype.pobj_info.lrgb.r = obj->rtype.pobj_info.lrgb.g = obj->rtype.pobj_info.lrgb.b = -1; break; } @@ -3870,6 +3871,7 @@ void multi_object_rw_to_object(object_rw *obj_rw, object *obj) obj->rtype.vclip_info.vclip_num = obj_rw->rtype.vclip_info.vclip_num; obj->rtype.vclip_info.frametime = obj_rw->rtype.vclip_info.frametime; obj->rtype.vclip_info.framenum = obj_rw->rtype.vclip_info.framenum; + obj->rtype.vclip_info.lrgb.r = obj->rtype.vclip_info.lrgb.g = obj->rtype.vclip_info.lrgb.b = -1; break; case RT_LASER: diff --git a/main/object.c b/main/object.c index 5b539688a..8da7254b7 100644 --- a/main/object.c +++ b/main/object.c @@ -196,7 +196,7 @@ void draw_object_blob(object *obj,bitmap_index bmi) void draw_object_tmap_rod(object *obj,bitmap_index bitmapi,int lighted) { grs_bitmap * bitmap = &GameBitmaps[bitmapi.index]; - fix light; + g3s_lrgb light; vms_vector delta,top_v,bot_v; g3s_point top_p,bot_p; @@ -212,9 +212,13 @@ void draw_object_tmap_rod(object *obj,bitmap_index bitmapi,int lighted) g3_rotate_point(&bot_p,&bot_v); if (lighted) + { light = compute_object_light(obj,&top_p.p3_vec); + } else - light = f1_0; + { + light.r = light.g = light.b = f1_0; + } g3_draw_rod_tmap(bitmap,&bot_p,obj->size,&top_p,obj->size,light); @@ -244,7 +248,7 @@ fix Cloak_fadein_duration; fix Cloak_fadeout_duration; //do special cloaked render -void draw_cloaked_object(object *obj,fix light,fix *glow,fix64 cloak_start_time,fix64 cloak_end_time,bitmap_index * alt_textures) +void draw_cloaked_object(object *obj,g3s_lrgb light,fix *glow,fix64 cloak_start_time,fix64 cloak_end_time,bitmap_index * alt_textures) { fix cloak_delta_time,total_cloaked_time; fix light_scale=F1_0; @@ -309,9 +313,12 @@ void draw_cloaked_object(object *obj,fix light,fix *glow,fix64 cloak_start_time, if (fading) { - fix new_light,new_glow; + fix new_glow; + g3s_lrgb new_light; - new_light = fixmul(light,light_scale); + new_light.r = fixmul(light.r,light_scale); + new_light.g = fixmul(light.g,light_scale); + new_light.b = fixmul(light.b,light_scale); new_glow = fixmul(*glow,light_scale); draw_polygon_model(&obj->pos,&obj->orient,obj->rtype.pobj_info.anim_angles,obj->rtype.pobj_info.model_num,obj->rtype.pobj_info.subobj_flags,new_light,&new_glow, alt_textures ); } @@ -328,7 +335,7 @@ void draw_cloaked_object(object *obj,fix light,fix *glow,fix64 cloak_start_time, //draw an object which renders as a polygon model void draw_polygon_object(object *obj) { - fix light; + g3s_lrgb light; int imsave; fix engine_glow_value; @@ -338,7 +345,7 @@ void draw_polygon_object(object *obj) #ifdef NETWORK if (Game_mode & GM_MULTI) if (Netgame.BrightPlayers) - light = F1_0*2; + light.r = light.g = light.b = F1_0*2; #endif imsave = Interpolation_method; @@ -397,6 +404,15 @@ void draw_polygon_object(object *obj) draw_polygon_model(&obj->pos,&obj->orient,obj->rtype.pobj_info.anim_angles,obj->rtype.pobj_info.model_num,obj->rtype.pobj_info.subobj_flags,light,&engine_glow_value,alt_textures); +#ifndef OGL // in software rendering must draw inner model last + if (obj->type == OBJ_WEAPON && (Weapon_info[obj->id].model_num_inner > -1 )) { + fix dist_to_eye = vm_vec_dist_quick(&Viewer->pos, &obj->pos); + gr_settransblend(GR_FADE_OFF, GR_BLEND_ADDITIVE_A); + if (dist_to_eye < Simple_model_threshhold_scale * F1_0*2) + draw_polygon_model(&obj->pos,&obj->orient,obj->rtype.pobj_info.anim_angles,Weapon_info[obj->id].model_num_inner,obj->rtype.pobj_info.subobj_flags,light,&engine_glow_value,alt_textures); + } +#endif + if (obj->type == OBJ_WEAPON && (Weapon_info[obj->id].model_num_inner > -1 )) gr_settransblend(GR_FADE_OFF, GR_BLEND_NORMAL); @@ -605,7 +621,7 @@ void render_object(object *obj) break; case RT_WEAPON_VCLIP: - if ( PlayerCfg.AlphaEffects ) // set nice transparency/blending for certrain objects + if ( PlayerCfg.AlphaEffects && obj->id != PROXIMITY_ID ) // set nice transparency/blending for certrain objects gr_settransblend( 7, GR_BLEND_ADDITIVE_A ); draw_weapon_vclip(obj); @@ -1176,6 +1192,12 @@ int obj_create(ubyte type,ubyte id,int segnum,vms_vector *pos, if (obj->type == OBJ_DEBRIS) Debris_object_count++; + // set light color values to -1 to lighting code will compute them is desired + if (obj->render_type == RT_POLYOBJ) + obj->rtype.pobj_info.lrgb.r = obj->rtype.pobj_info.lrgb.g = obj->rtype.pobj_info.lrgb.b = -1; + else + obj->rtype.vclip_info.lrgb.r = obj->rtype.vclip_info.lrgb.g = obj->rtype.vclip_info.lrgb.b = -1; + return objnum; } diff --git a/main/object.h b/main/object.h index efeace10b..18826a613 100644 --- a/main/object.h +++ b/main/object.h @@ -211,8 +211,15 @@ typedef struct vclip_info { int vclip_num; fix frametime; sbyte framenum; + g3s_lrgb lrgb; // light color this vclip will emit } __pack__ vclip_info; +typedef struct vclip_info_rw { + int vclip_num; + fix frametime; + sbyte framenum; +} __pack__ vclip_info_rw; + //structures for different kinds of rendering typedef struct polyobj_info { @@ -221,8 +228,17 @@ typedef struct polyobj_info { int subobj_flags; //specify which subobjs to draw int tmap_override; //if this is not -1, map all face to this int alt_textures; //if not -1, use these textures instead + g3s_lrgb lrgb; // light color this polyobj will emit } __pack__ polyobj_info; +typedef struct polyobj_info_rw { + int model_num; //which polygon model + vms_angvec anim_angles[MAX_SUBMODELS]; //angles for each subobject + int subobj_flags; //specify which subobjs to draw + int tmap_override; //if this is not -1, map all face to this + int alt_textures; //if not -1, use these textures instead +} __pack__ polyobj_info_rw; + typedef struct object { int signature; // Every object ever has a unique signature... ubyte type; // what type of object this is... robot, weapon, hostage, powerup, fireball @@ -318,8 +334,8 @@ typedef struct object_rw { //render info, determined by RENDER_TYPE union { - polyobj_info pobj_info; //polygon model - vclip_info vclip_info; //vclip + polyobj_info_rw pobj_info; //polygon model + vclip_info_rw vclip_info; //vclip } __pack__ rtype; #ifdef WORDS_NEED_ALIGNMENT short pad2; diff --git a/main/playsave.c b/main/playsave.c index 9117bbbb8..f3243ba55 100644 --- a/main/playsave.c +++ b/main/playsave.c @@ -94,6 +94,7 @@ int new_player_config() PlayerCfg.MultiMessages = 0; PlayerCfg.BombGauge = 1; PlayerCfg.AlphaEffects = 0; + PlayerCfg.DynLightColor = 0; // Default taunt macros #ifdef NETWORK @@ -304,6 +305,8 @@ int read_player_d1x(char *filename) { if(!strcmp(word,"ALPHAEFFECTS")) PlayerCfg.AlphaEffects = atoi(line); + if(!strcmp(word,"DYNLIGHTCOLOR")) + PlayerCfg.DynLightColor = atoi(line); d_free(word); cfgets(line,50,f); word=splitword(line,'='); @@ -576,6 +579,7 @@ int write_player_d1x(char *filename) PHYSFSX_printf(fout,"[end]\n"); PHYSFSX_printf(fout,"[graphics]\n"); PHYSFSX_printf(fout,"alphaeffects=%i\n",PlayerCfg.AlphaEffects); + PHYSFSX_printf(fout,"dynlightcolor=%i\n",PlayerCfg.DynLightColor); PHYSFSX_printf(fout,"[end]\n"); PHYSFSX_printf(fout,"[plx version]\n"); PHYSFSX_printf(fout,"plx version=%s\n",VERSION); diff --git a/main/playsave.h b/main/playsave.h index e470f9e8f..01b643bc4 100644 --- a/main/playsave.h +++ b/main/playsave.h @@ -80,6 +80,7 @@ typedef struct player_config ubyte MultiMessages; ubyte BombGauge; int AlphaEffects; + int DynLightColor; } __pack__ player_config; extern struct player_config PlayerCfg; diff --git a/main/polyobj.c b/main/polyobj.c index ca2082707..a90c8ba0b 100644 --- a/main/polyobj.c +++ b/main/polyobj.c @@ -504,7 +504,7 @@ bitmap_index texture_list_index[MAX_POLYOBJ_TEXTURES]; //draw a polygon model -void draw_polygon_model(vms_vector *pos,vms_matrix *orient,vms_angvec *anim_angles,int model_num,int flags,fix light,fix *glow_values,bitmap_index alt_textures[]) +void draw_polygon_model(vms_vector *pos,vms_matrix *orient,vms_angvec *anim_angles,int model_num,int flags,g3s_lrgb light,fix *glow_values,bitmap_index alt_textures[]) { polymodel *po; int i; @@ -714,6 +714,7 @@ void draw_model_picture(int mn,vms_angvec *orient_angles) { vms_vector temp_pos=ZERO_VECTOR; vms_matrix temp_orient = IDENTITY_MATRIX; + g3s_lrgb lrgb = { f1_0, f1_0, f1_0 }; Assert(mn>=0 && mn MAX_LIGHT) uvl_copy[i].l = MAX_LIGHT; + // And now the same for the ACTUAL (rgb) light we want to use + + //scale static light for destruction effect + if (Control_center_destroyed) //make lights flash + { + if (PlayerCfg.DynLightColor) // let the mine glow red a little + { + dyn_light[i].r = fixmul(flash_scale>=f0_5*1.5?flash_scale:f0_5*1.5,uvl_copy[i].l); + dyn_light[i].g = dyn_light[i].b = fixmul(flash_scale,uvl_copy[i].l); + } + else + dyn_light[i].r = dyn_light[i].g = dyn_light[i].b = fixmul(flash_scale,uvl_copy[i].l); + } + // add light color + dyn_light[i].r += Dynamic_light[vp[i]].r; + dyn_light[i].g += Dynamic_light[vp[i]].g; + dyn_light[i].b += Dynamic_light[vp[i]].b; + // saturate at max value + if (dyn_light[i].r > highval) + highval = dyn_light[i].r; + if (dyn_light[i].g > highval) + highval = dyn_light[i].g; + if (dyn_light[i].b > highval) + highval = dyn_light[i].b; + if (highval > MAX_LIGHT) + { + dyn_light[i].r -= highval - MAX_LIGHT; + dyn_light[i].g -= highval - MAX_LIGHT; + dyn_light[i].b -= highval - MAX_LIGHT; + } } } @@ -274,7 +299,7 @@ void render_face(int segnum, int sidenum, int nv, short *vp, int tmap1, int tmap #ifdef EDITOR if ((Render_only_bottom) && (sidenum == WBOTTOM)) { - g3_draw_tmap(nv,pointlist,uvl_copy,&GameBitmaps[Textures[Bottom_bitmap_num].index]); + g3_draw_tmap(nv,pointlist,uvl_copy,dyn_light,&GameBitmaps[Textures[Bottom_bitmap_num].index]); } else #endif @@ -282,12 +307,12 @@ void render_face(int segnum, int sidenum, int nv, short *vp, int tmap1, int tmap #ifdef OGL if (bm2) { - g3_draw_tmap_2(nv,pointlist,uvl_copy,bm,bm2,((tmap2&0xC000)>>14) & 3); + g3_draw_tmap_2(nv,pointlist,uvl_copy,dyn_light,bm,bm2,((tmap2&0xC000)>>14) & 3); } else #endif { - g3_draw_tmap(nv,pointlist,uvl_copy,bm); + g3_draw_tmap(nv,pointlist,uvl_copy,dyn_light,bm); } } @@ -310,6 +335,7 @@ void check_face(int segnum, int sidenum, int facenum, int nv, short *vp, int tma int save_lighting; grs_bitmap *bm; g3s_uvl uvl_copy[8]; + g3s_lrgb dyn_light[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; g3s_point *pointlist[4]; if (tmap2 > 0 ) @@ -320,7 +346,7 @@ void check_face(int segnum, int sidenum, int facenum, int nv, short *vp, int tma for (i=0; icv_bitmap,_search_x,_search_y) == 1) { diff --git a/main/state.c b/main/state.c index d47ee8dde..14d1e96a5 100644 --- a/main/state.c +++ b/main/state.c @@ -381,6 +381,7 @@ void state_object_rw_to_object(object_rw *obj_rw, object *obj) obj->rtype.pobj_info.subobj_flags = obj_rw->rtype.pobj_info.subobj_flags; obj->rtype.pobj_info.tmap_override = obj_rw->rtype.pobj_info.tmap_override; obj->rtype.pobj_info.alt_textures = obj_rw->rtype.pobj_info.alt_textures; + obj->rtype.pobj_info.lrgb.r = obj->rtype.pobj_info.lrgb.g = obj->rtype.pobj_info.lrgb.b = -1; break; } @@ -391,6 +392,7 @@ void state_object_rw_to_object(object_rw *obj_rw, object *obj) obj->rtype.vclip_info.vclip_num = obj_rw->rtype.vclip_info.vclip_num; obj->rtype.vclip_info.frametime = obj_rw->rtype.vclip_info.frametime; obj->rtype.vclip_info.framenum = obj_rw->rtype.vclip_info.framenum; + obj->rtype.vclip_info.lrgb.r = obj->rtype.vclip_info.lrgb.g = obj->rtype.vclip_info.lrgb.b = -1; break; case RT_LASER: diff --git a/main/terrain.c b/main/terrain.c index 425e2538f..bf164e978 100644 --- a/main/terrain.c +++ b/main/terrain.c @@ -41,6 +41,8 @@ int grid_w,grid_h; g3s_uvl uvl_list1[] = { {0,0,0}, {f1_0,0,0}, {0,f1_0,0} }; g3s_uvl uvl_list2[] = { {f1_0,0,0}, {f1_0,f1_0,0}, {0,f1_0,0} }; +g3s_lrgb lrgb_list1[] = { { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 } }; +g3s_lrgb lrgb_list2[] = { { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 } }; ubyte *height_array; ubyte *light_array; @@ -76,15 +78,15 @@ void draw_cell(int i,int j,g3s_point *p0,g3s_point *p1,g3s_point *p2,g3s_point * pointlist[0] = p0; pointlist[1] = p1; pointlist[2] = p3; - uvl_list1[0].l = LIGHTVAL(i,j); - uvl_list1[1].l = LIGHTVAL(i,j+1); - uvl_list1[2].l = LIGHTVAL(i+1,j); + lrgb_list1[0].r = lrgb_list1[0].g = lrgb_list1[0].b = uvl_list1[0].l = LIGHTVAL(i,j); + lrgb_list1[1].r = lrgb_list1[1].g = lrgb_list1[1].b = uvl_list1[1].l = LIGHTVAL(i,j+1); + lrgb_list1[2].r = lrgb_list1[2].g = lrgb_list1[2].b = uvl_list1[2].l = LIGHTVAL(i+1,j); uvl_list1[0].u = (i)*f1_0/4; uvl_list1[0].v = (j)*f1_0/4; uvl_list1[1].u = (i)*f1_0/4; uvl_list1[1].v = (j+1)*f1_0/4; uvl_list1[2].u = (i+1)*f1_0/4; uvl_list1[2].v = (j)*f1_0/4; - g3_check_and_draw_tmap(3,pointlist,uvl_list1,terrain_bm,NULL,NULL); + g3_check_and_draw_tmap(3,pointlist,uvl_list1,lrgb_list1,terrain_bm,NULL,NULL); if (terrain_outline) { int lsave=Lighting_on; Lighting_on=0; @@ -96,15 +98,15 @@ void draw_cell(int i,int j,g3s_point *p0,g3s_point *p1,g3s_point *p2,g3s_point * pointlist[0] = p1; pointlist[1] = p2; - uvl_list2[0].l = LIGHTVAL(i,j+1); - uvl_list2[1].l = LIGHTVAL(i+1,j+1); - uvl_list2[2].l = LIGHTVAL(i+1,j); + lrgb_list2[0].r = lrgb_list2[0].g = lrgb_list2[0].b = uvl_list2[0].l = LIGHTVAL(i,j+1); + lrgb_list2[1].r = lrgb_list2[1].g = lrgb_list2[1].b = uvl_list2[1].l = LIGHTVAL(i+1,j+1); + lrgb_list2[2].r = lrgb_list2[2].g = lrgb_list2[2].b = uvl_list2[2].l = LIGHTVAL(i+1,j); uvl_list2[0].u = (i)*f1_0/4; uvl_list2[0].v = (j+1)*f1_0/4; uvl_list2[1].u = (i+1)*f1_0/4; uvl_list2[1].v = (j+1)*f1_0/4; uvl_list2[2].u = (i+1)*f1_0/4; uvl_list2[2].v = (j)*f1_0/4; - g3_check_and_draw_tmap(3,pointlist,uvl_list2,terrain_bm,NULL,NULL); + g3_check_and_draw_tmap(3,pointlist,uvl_list2,lrgb_list2,terrain_bm,NULL,NULL); if (terrain_outline) { int lsave=Lighting_on; Lighting_on=0;