Execute set_dynamic_light 60 times per second max since more would just be a waste of CPU time; When executing set_dynamic_light, process ALL lights; Instead of storing light color in objects, do it on-thy-fly but store bitmap-based color in grs_bitmap - vastly speeds up colored dynamic lights; Improved saturation for vertex lighting to make light color a bit more subtile

This commit is contained in:
zicodxx 2011-04-12 03:02:51 +02:00
parent a74fcba858
commit 7ae49da7cf
12 changed files with 143 additions and 221 deletions

View file

@ -4,6 +4,7 @@ D2X-Rebirth Changelog
--------
main/game.c, main/gauges.c, main/multi.h, main/net_ipx.c, main/net_ipx.h, main/net_udp.c, main/net_udp.h: Little fix for typing-indicator in multiplayer - was showing comma even if no player name was displayed; Removed team_vector from UDP lite_info structure - it's not needed; Removed ShowAllNames from Netgame structure as I see no reason why names display should be host-controlled; Increased UDP_NETGAMES_PAGES to actually show 3000 possible games
main/laser.c: Stupid me forgot to let Omega use it's charge again after debugging it - fixed...
include/gr.h, main/bm.c, main/bm.h, main/gamesave.c, main/lighting.c, main/multi.c, main/object.c, main/object.h, main/piggy.c, main/render.c, main/state.c: Execute set_dynamic_light 60 times per second max since more would just be a waste of CPU time; When executing set_dynamic_light, process ALL lights; Instead of storing light color in objects, do it on-thy-fly but store bitmap-based color in grs_bitmap - vastly speeds up colored dynamic lights; Improved saturation for vertex lighting to make light color a bit more subtile
20110411
--------

View file

@ -93,6 +93,7 @@ typedef struct _grs_bitmap {
// SVGA = *parent+(rowsize*y+x)
unsigned short bm_handle; //for application. initialized to 0
ubyte avg_color; // Average color of all pixels in texture map.
fix avg_color_rgb[3]; // same as above but real rgb value to be used to textured objects that should emit light
sbyte unused; // to 4-byte align.
#ifdef OGL
struct _ogl_texture *gltexture;

View file

@ -584,3 +584,62 @@ int load_exit_models()
return 1;
}
void compute_average_rgb(grs_bitmap *bm, fix *rgb)
{
ubyte buf[bm->bm_w*bm->bm_h];
int i, x, y, color, count;
fix t_rgb[3] = { 0, 0, 0 };
rgb[0] = rgb[1] = rgb[2] = 0;
if (!bm->bm_data)
return;
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_rgb[0] = gr_palette[color*3];
t_rgb[1] = gr_palette[color*3+1];
t_rgb[2] = gr_palette[color*3+2];
if (!(color == TRANSPARENCY_COLOR || (t_rgb[0] == t_rgb[1] && t_rgb[0] == t_rgb[2])))
{
rgb[0] += t_rgb[0];
rgb[1] += t_rgb[1];
rgb[2] += t_rgb[2];
count++;
}
}
}
}

View file

@ -85,6 +85,7 @@ extern int Num_object_subtypes; // Number of possible IDs for the current t
extern bitmap_index ObjBitmaps[MAX_OBJ_BITMAPS];
extern ushort ObjBitmapPtrs[MAX_OBJ_BITMAPS];
extern int First_multi_bitmap_num;
void compute_average_rgb(grs_bitmap *bm, fix *rgb);
// Initializes all bitmaps from BITMAPS.TBL file.
int gamedata_read_tbl(int pc_shareware);

View file

@ -519,7 +519,6 @@ 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;
}
@ -532,7 +531,6 @@ void read_object(object *obj,CFILE *f,int version)
obj->rtype.vclip_info.vclip_num = 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;

View file

@ -297,127 +297,10 @@ fix Obj_light_xlate[16] = { 0x1234, 0x3321, 0x2468, 0x1735,
0x0123, 0x19af, 0x3f03, 0x232a,
0x2123, 0x39af, 0x0f03, 0x132a,
0x3123, 0x29af, 0x1f03, 0x032a };
// Flag array of objects lit last frame. Guaranteed to process this frame if lit last frame.
sbyte Lighting_objects[MAX_OBJECTS];
#define MAX_HEADLIGHTS 8
object *Headlights[MAX_HEADLIGHTS];
int Num_headlights;
g3s_lrgb compute_lrgb_on(object *obj)
{
int i, x, y, color, count = 0, t_idx_s = -1, t_idx_e = -1;
g3s_lrgb t_color = {0,0,0}, obj_color = {255,255,255};
switch (obj->render_type)
{
case RT_POLYOBJ:
{
polymodel *po = &Polygon_models[obj->rtype.pobj_info.model_num];
if (po->n_textures <= 0)
{
int color = g3_poly_get_color(po->model_data);
if (color)
{
obj_color.r = gr_current_pal[color*3];
obj_color.g = gr_current_pal[color*3+1];
obj_color.b = gr_current_pal[color*3+2];
}
}
else
{
t_idx_s = ObjBitmaps[ObjBitmapPtrs[po->first_texture]].index;
t_idx_e = t_idx_s + po->n_textures - 1;
}
break;
}
case RT_WEAPON_VCLIP:
{
t_idx_s = Vclip[Weapon_info[obj->id].weapon_vclip].frames[0].index;
t_idx_e = Vclip[Weapon_info[obj->id].weapon_vclip].frames[Vclip[Weapon_info[obj->id].weapon_vclip].num_frames-1].index;
break;
}
default:
{
t_idx_s = Vclip[obj->id].frames[0].index;
t_idx_e = Vclip[obj->id].frames[Vclip[obj->id].num_frames-1].index;
break;
}
}
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;
}
// ---------------------------------------------------------
g3s_lrgb compute_light_emission(int objnum)
{
@ -547,13 +430,60 @@ g3s_lrgb compute_light_emission(int objnum)
if (compute_color)
{
int i, t_idx_s = -1, t_idx_e = -1;
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;
obj_color.r = obj_color.g = obj_color.b = 255;
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);
switch (obj->render_type)
{
case RT_POLYOBJ:
{
polymodel *po = &Polygon_models[obj->rtype.pobj_info.model_num];
if (po->n_textures <= 0)
{
int color = g3_poly_get_color(po->model_data);
if (color)
{
obj_color.r = gr_current_pal[color*3];
obj_color.g = gr_current_pal[color*3+1];
obj_color.b = gr_current_pal[color*3+2];
}
}
else
{
t_idx_s = ObjBitmaps[ObjBitmapPtrs[po->first_texture]].index;
t_idx_e = t_idx_s + po->n_textures - 1;
}
break;
}
case RT_WEAPON_VCLIP:
{
t_idx_s = Vclip[Weapon_info[obj->id].weapon_vclip].frames[0].index;
t_idx_e = Vclip[Weapon_info[obj->id].weapon_vclip].frames[Vclip[Weapon_info[obj->id].weapon_vclip].num_frames-1].index;
break;
}
default:
{
t_idx_s = Vclip[obj->id].frames[0].index;
t_idx_e = Vclip[obj->id].frames[Vclip[obj->id].num_frames-1].index;
break;
}
}
if (t_idx_s != -1 && t_idx_e != -1)
{
obj_color.r = obj_color.g = obj_color.b = 0;
for (i = t_idx_s; i <= t_idx_e; i++)
{
grs_bitmap *bm = &GameBitmaps[i];
obj_color.r += bm->avg_color_rgb[0];
obj_color.g += bm->avg_color_rgb[1];
obj_color.b += bm->avg_color_rgb[2];
}
}
// scale color to light intensity
cscale = ((float)(light_intensity*3)/(obj_color.r+obj_color.g+obj_color.b));
@ -574,7 +504,6 @@ void set_dynamic_light(void)
short render_vertices[MAX_VERTICES];
sbyte render_vertex_flags[MAX_VERTICES];
int render_seg,segnum, v;
sbyte new_lighting_objects[MAX_OBJECTS];
Num_headlights = 0;
@ -599,16 +528,10 @@ void set_dynamic_light(void)
render_vertex_flags[vnum] = 1;
render_vertices[n_render_vertices++] = vnum;
}
//--old way-- for (s=0; s<n_render_vertices; s++)
//--old way-- if (render_vertices[s] == vnum)
//--old way-- break;
//--old way-- if (s == n_render_vertices)
//--old way-- render_vertices[n_render_vertices++] = vnum;
}
}
}
// -- for (vertnum=FrameCount&1; vertnum<n_render_vertices; vertnum+=2) {
for (vv=0; vv<n_render_vertices; vv++) {
int vertnum;
@ -621,56 +544,15 @@ void set_dynamic_light(void)
cast_muzzle_flash_light(n_render_vertices, render_vertices);
for (objnum=0; objnum<=Highest_object_index; objnum++)
new_lighting_objects[objnum] = 0;
{
object *obj = &Objects[objnum];
vms_vector *objpos = &obj->pos;
g3s_lrgb obj_light_emission;
// July 5, 1995: New faster dynamic lighting code. About 5% faster on the PC (un-optimized).
// Only objects which are in rendered segments cast dynamic light. We might wad6 to extend this
// one or two segments if we notice light changing as objects go offscreen. I couldn't see any
// serious visual degradation. In fact, I could see no humorous degradation, either. --MK
for (render_seg=0; render_seg<N_render_segs; render_seg++) {
int segnum = Render_list[render_seg];
obj_light_emission = compute_light_emission(objnum);
objnum = Segments[segnum].objects;
while (objnum != -1) {
object *obj = &Objects[objnum];
vms_vector *objpos = &obj->pos;
g3s_lrgb obj_light_emission;
obj_light_emission = compute_light_emission(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, obj-Objects);
new_lighting_objects[objnum] = 1;
}
objnum = obj->next;
}
}
// Now, process all lights from last frame which haven't been processed this frame.
for (objnum=0; objnum<=Highest_object_index; objnum++) {
// In multiplayer games, process even unprocessed objects every 4th frame, else don't know about player sneaking up.
if ((Lighting_objects[objnum]) || ((Game_mode & GM_MULTI) && (((objnum ^ FrameCount) & 3) == 0))) {
if (!new_lighting_objects[objnum]) {
// Lighted last frame, but not this frame. Get intensity...
object *obj = &Objects[objnum];
vms_vector *objpos = &obj->pos;
g3s_lrgb obj_light_emission;
obj_light_emission = compute_light_emission(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;
}
} else {
// Not lighted last frame, so we don't need to light it. (Already lit if casting light this frame.)
// But copy value from new_lighting_objects to update Lighting_objects array.
Lighting_objects[objnum] = new_lighting_objects[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);
}
}

View file

@ -5835,7 +5835,6 @@ 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;
}
@ -5846,7 +5845,6 @@ 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:

View file

@ -1368,12 +1368,6 @@ 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;
}

View file

@ -219,15 +219,8 @@ 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 {
@ -236,17 +229,8 @@ 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
@ -343,8 +327,8 @@ typedef struct object_rw {
// render info, determined by RENDER_TYPE
union {
polyobj_info_rw pobj_info; // polygon model
vclip_info_rw vclip_info; // vclip
polyobj_info pobj_info; // polygon model
vclip_info vclip_info; // vclip
} __pack__ rtype ;
#ifdef WORDS_NEED_ALIGNMENT

View file

@ -1173,6 +1173,8 @@ void piggy_bitmap_page_in( bitmap_index bitmap )
//@@#endif
//@@}
compute_average_rgb(bmp, bmp->avg_color_rgb);
start_time();
}

View file

@ -279,7 +279,7 @@ void render_face(int segnum, int sidenum, int nv, short *vp, int tmap1, int tmap
for (i=0;i<nv;i++)
{
fix highval = 0;
float highval = 1.0;
//the uvl struct has static light already in it
//scale static light for destruction effect
@ -294,7 +294,9 @@ void render_face(int segnum, int sidenum, int nv, short *vp, int tmap1, int tmap
// 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 (Seismic_tremor_magnitude) //make lights flash
dyn_light[i].r = dyn_light[i].g = dyn_light[i].b = fixmul(flash_scale,uvl_copy[i].l);
else if (Control_center_destroyed) //make lights flash
{
if (PlayerCfg.DynLightColor) // let the mine glow red a little
{
@ -304,26 +306,24 @@ void render_face(int segnum, int sidenum, int nv, short *vp, int tmap1, int tmap
else
dyn_light[i].r = dyn_light[i].g = dyn_light[i].b = fixmul(flash_scale,uvl_copy[i].l);
}
if (Seismic_tremor_magnitude) //make lights flash
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)
if (dyn_light[i].r/MAX_LIGHT > highval)
highval = dyn_light[i].r/MAX_LIGHT;
if (dyn_light[i].g/MAX_LIGHT > highval)
highval = dyn_light[i].g/MAX_LIGHT;
if (dyn_light[i].b/MAX_LIGHT > highval)
highval = dyn_light[i].b/MAX_LIGHT;
if (highval > 1.0)
{
dyn_light[i].r -= highval - MAX_LIGHT;
dyn_light[i].g -= highval - MAX_LIGHT;
dyn_light[i].b -= highval - MAX_LIGHT;
dyn_light[i].r /= highval;
dyn_light[i].g /= highval;
dyn_light[i].b /= highval;
}
}
}
@ -1956,6 +1956,7 @@ void render_mine(int start_seg_num,fix eye_offset, int window_num)
int i;
#endif
int nn;
fix64 dynlight_time = 0;
// Initialize number of objects (actually, robots!) rendered this frame.
Window_rendered_data[window_num].num_objects = 0;
@ -2022,8 +2023,11 @@ void render_mine(int start_seg_num,fix eye_offset, int window_num)
if (!(_search_mode))
build_object_lists(N_render_segs);
if (eye_offset<=0) // Do for left eye or zero.
if (eye_offset<=0 && dynlight_time < timer_query()) // Do for left eye or zero.
{
dynlight_time = timer_query() + (F1_0/60); // It's enough to update dynamic light 60 times per second max. More is just waste of CPU time
set_dynamic_light();
}
if (!_search_mode && Clear_window == 2) {
if (first_terminal_seg < N_render_segs) {

View file

@ -411,7 +411,6 @@ 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;
}
@ -422,7 +421,6 @@ 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: