From 357e1b01443b028ac11f3f88cedfba1f46f97d1b Mon Sep 17 00:00:00 2001 From: zicodxx Date: Thu, 7 Apr 2011 22:32:47 +0200 Subject: [PATCH] Made lighting code work with actual RGB values and added feature to let certain objects emit colored dynamic light as well as let mine flash red when control center destroyed (OpenGL-only at the moment) --- 3d/draw.c | 8 +- 3d/interp.c | 128 ++++++++--- 3d/rod.c | 17 +- CHANGELOG.txt | 4 + arch/ogl/ogl.c | 24 +- include/3d.h | 18 +- include/ogl_init.h | 2 +- main/endlevel.c | 8 +- main/gamesave.c | 2 + main/lighting.c | 531 ++++++++++++++++++++++++++++++--------------- main/lighting.h | 6 +- main/menu.c | 7 +- main/morph.c | 4 +- main/multi.c | 2 + main/object.c | 38 +++- main/object.h | 20 +- main/playsave.c | 4 + main/playsave.h | 1 + main/polyobj.c | 5 +- main/polyobj.h | 2 +- main/render.c | 58 +++-- main/state.c | 2 + main/terrain.c | 18 +- 23 files changed, 633 insertions(+), 276 deletions(-) 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;