diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 4cf303193..ef175299d 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -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 -------- diff --git a/include/gr.h b/include/gr.h index efa7ed97f..6fa33ce50 100644 --- a/include/gr.h +++ b/include/gr.h @@ -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; diff --git a/main/bm.c b/main/bm.c index 5f0c5528e..6293302d3 100644 --- a/main/bm.c +++ b/main/bm.c @@ -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++; + } + } + } +} diff --git a/main/bm.h b/main/bm.h index d1c0784a4..8dd14a636 100644 --- a/main/bm.h +++ b/main/bm.h @@ -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); diff --git a/main/gamesave.c b/main/gamesave.c index 953ed93af..8dd7ee160 100644 --- a/main/gamesave.c +++ b/main/gamesave.c @@ -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; diff --git a/main/lighting.c b/main/lighting.c index 0e22f37cb..bf19968a1 100644 --- a/main/lighting.c +++ b/main/lighting.c @@ -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; spos; + 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_segpos; - 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); } } diff --git a/main/multi.c b/main/multi.c index 4eeac88dc..06420bbad 100644 --- a/main/multi.c +++ b/main/multi.c @@ -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: diff --git a/main/object.c b/main/object.c index 48c05f36c..f021dcc6a 100644 --- a/main/object.c +++ b/main/object.c @@ -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; } diff --git a/main/object.h b/main/object.h index 15ed6fbae..daaf03714 100644 --- a/main/object.h +++ b/main/object.h @@ -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 diff --git a/main/piggy.c b/main/piggy.c index cc8489534..7210cb3de 100644 --- a/main/piggy.c +++ b/main/piggy.c @@ -1173,6 +1173,8 @@ void piggy_bitmap_page_in( bitmap_index bitmap ) //@@#endif //@@} + compute_average_rgb(bmp, bmp->avg_color_rgb); + start_time(); } diff --git a/main/render.c b/main/render.c index 1fa8c7b04..e20d30fc7 100644 --- a/main/render.c +++ b/main/render.c @@ -279,7 +279,7 @@ void render_face(int segnum, int sidenum, int nv, short *vp, int tmap1, int tmap for (i=0;i 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) { diff --git a/main/state.c b/main/state.c index b36c10c76..ceb89906d 100644 --- a/main/state.c +++ b/main/state.c @@ -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: