From f41fc229e59e17b525e427cc321390f7bbc5f46c Mon Sep 17 00:00:00 2001 From: Goober5000 Date: Mon, 9 Sep 2024 00:48:46 -0400 Subject: [PATCH] electrical arc upgrade, stage 2: make arrays dynamic --- code/debris/debris.cpp | 33 ++++++++++++++------------------ code/debris/debris.h | 4 ++-- code/model/model.h | 8 +------- code/model/modelinterp.cpp | 9 ++------- code/model/modelread.cpp | 26 ++++++++++++------------- code/model/modelrender.cpp | 31 ++++++++++++------------------ code/scripting/api/objs/ship.cpp | 10 +++++----- code/ship/ship.cpp | 14 ++++++++------ code/ship/ship.h | 6 +++--- code/ship/shipfx.cpp | 27 +++++++++++--------------- 10 files changed, 70 insertions(+), 98 deletions(-) diff --git a/code/debris/debris.cpp b/code/debris/debris.cpp index d0ffbba7da1..38aa6c55793 100644 --- a/code/debris/debris.cpp +++ b/code/debris/debris.cpp @@ -56,8 +56,8 @@ int Debris_num_submodels = 0; #define DEBRIS_INDEX(dp) (int)(dp-Debris.data()) -// Find the first available arc slot. -debris_electrical_arc *debris_find_electrical_arc_slot(debris *db); +// Find the first available arc slot. If none is available, and no_create is false, add one. +debris_electrical_arc *debris_find_or_create_electrical_arc_slot(debris *db, bool no_create); /** * Start the sequence of a piece of debris writhing in unholy agony!!! @@ -251,22 +251,19 @@ void debris_process_post(object * obj, float frame_time) if (db->is_hull) { - int n, n_arcs = Random::next(1, 3); // Create 1-3 sparks + int n_arcs = Random::next(1, 3); // Create 1-3 sparks vec3d v1 = submodel_get_random_point(db->model_num, db->submodel_num); vec3d v2 = submodel_get_random_point(db->model_num, db->submodel_num); vec3d v3 = submodel_get_random_point(db->model_num, db->submodel_num); vec3d v4 = submodel_get_random_point(db->model_num, db->submodel_num); - n = 0; - int lifetime = Random::next(100, 1000); // Create the spark effects - for (int i=0; ielectrical_arcs[i]; - if ( !arc->timestamp.isValid() ) { - + for (int n = 0; n < n_arcs; n++) { + auto arc = debris_find_or_create_electrical_arc_slot(db, db->electrical_arcs.size() >= MAX_DEBRIS_ARCS); + if (arc) { arc->timestamp = _timestamp(lifetime); // live up to a second switch( n ) { @@ -286,10 +283,6 @@ void debris_process_post(object * obj, float frame_time) default: UNREACHABLE("Unhandled case %d for electrical arc creation in debris_process_post()!", n); } - - n++; - if ( n == n_arcs ) - break; // Don't need to create anymore } } @@ -582,9 +575,7 @@ object *debris_create_only(int parent_objnum, int parent_ship_class, int alt_typ db->parent_alt_name = alt_type_index; db->damage_mult = 1.0f; - for (int i=0; ielectrical_arcs[i].timestamp = TIMESTAMP::invalid(); - } + db->electrical_arcs.clear(); if ( db->is_hull ) { // Percent of debris pieces with arcs controlled via table (default 50%) @@ -1238,7 +1229,7 @@ void create_generic_debris(object* ship_objp, vec3d* pos, float min_num_debris, } } -debris_electrical_arc *debris_find_electrical_arc_slot(debris *db) +debris_electrical_arc *debris_find_or_create_electrical_arc_slot(debris *db, bool no_create) { size_t i = 0; for (auto& ii : db->electrical_arcs) @@ -1248,8 +1239,12 @@ debris_electrical_arc *debris_find_electrical_arc_slot(debris *db) i++; } - if (i == MAX_DEBRIS_ARCS) - return nullptr; + if (i == db->electrical_arcs.size()) + { + if (no_create) + return nullptr; + db->electrical_arcs.emplace_back(); + } return &db->electrical_arcs[i]; } diff --git a/code/debris/debris.h b/code/debris/debris.h index 7d4fcd31113..359dbe2aebc 100644 --- a/code/debris/debris.h +++ b/code/debris/debris.h @@ -20,7 +20,7 @@ class object; struct CFILE; class model_draw_list; -#define MAX_DEBRIS_ARCS 8 // Must be less than MAX_ARC_EFFECTS in model.h +#define MAX_DEBRIS_ARCS 8 FLAG_LIST(Debris_Flags) { Used, @@ -56,7 +56,7 @@ typedef struct debris { TIMESTAMP sound_delay; // timestamp to signal when sound should start fix time_started; // time when debris was created - debris_electrical_arc electrical_arcs[MAX_DEBRIS_ARCS]; + SCP_vector electrical_arcs; int arc_frequency; // Starts at 1000, gets bigger int parent_alt_name; diff --git a/code/model/model.h b/code/model/model.h index d0cbe10ac22..8d72ab83e61 100644 --- a/code/model/model.h +++ b/code/model/model.h @@ -131,17 +131,11 @@ struct submodel_instance vec3d canonical_offset = vmd_zero_vector; vec3d canonical_prev_offset = vmd_zero_vector; - int num_arcs = 0; // See model_add_arc for more info - model_electrical_arc electrical_arcs[MAX_ARC_EFFECTS]; + SCP_vector electrical_arcs; //SMI-Specific movement axis. Only valid in MOVEMENT_TYPE_TRIGGERED. vec3d rotation_axis = vmd_zero_vector; vec3d translation_axis = vmd_zero_vector; - - submodel_instance() - { - memset(electrical_arcs, 0, MAX_ARC_EFFECTS * sizeof(model_electrical_arc)); - } }; #define TM_BASE_TYPE 0 // the standard base map diff --git a/code/model/modelinterp.cpp b/code/model/modelinterp.cpp index a57dd743314..7a40fbfeff7 100644 --- a/code/model/modelinterp.cpp +++ b/code/model/modelinterp.cpp @@ -785,9 +785,7 @@ void model_draw_bay_paths_htl(int model_num) gr_set_cull(cull); } -static const int MAX_ARC_SEGMENT_POINTS = 50; -int Num_arc_segment_points = 0; -vec3d Arc_segment_points[MAX_ARC_SEGMENT_POINTS]; +SCP_vector Arc_segment_points; void interp_render_arc_segment(const vec3d *v1, const vec3d *v2, int depth ) { @@ -795,10 +793,7 @@ void interp_render_arc_segment(const vec3d *v1, const vec3d *v2, int depth ) const float scaler = 0.30f; if ( (d < scaler) || (depth > 4) ) { - // the real limit appears to be 33, so we should never hit this unless the code changes - Assert( Num_arc_segment_points < MAX_ARC_SEGMENT_POINTS ); - - memcpy( &Arc_segment_points[Num_arc_segment_points++], v2, sizeof(vec3d) ); + Arc_segment_points.push_back(*v2); } else { // divide in half vec3d tmp; diff --git a/code/model/modelread.cpp b/code/model/modelread.cpp index 21cb51bbc22..3bb1fe61bd3 100644 --- a/code/model/modelread.cpp +++ b/code/model/modelread.cpp @@ -5159,7 +5159,7 @@ void model_instance_clear_arcs(polymodel *pm, polymodel_instance *pmi) Assert(pm->id == pmi->model_num); for (int i = 0; i < pm->n_models; ++i) { - pmi->submodel[i].num_arcs = 0; // Turn off any electric arcing effects + pmi->submodel[i].electrical_arcs.clear(); // Turn off any electric arcing effects } } @@ -5179,20 +5179,18 @@ void model_instance_add_arc(polymodel *pm, polymodel_instance *pmi, int sub_mode if ( sub_model_num >= pm->n_models ) return; auto smi = &pmi->submodel[sub_model_num]; - if ( smi->num_arcs < MAX_ARC_EFFECTS ) { - auto &new_arc = smi->electrical_arcs[smi->num_arcs]; - new_arc.type = static_cast(arc_type); - new_arc.endpoint_1 = *v1; - new_arc.endpoint_2 = *v2; - - if (arc_type == MARC_TYPE_SHIP || arc_type == MARC_TYPE_SCRIPTED) { - new_arc.primary_color_1 = *primary_color_1; - new_arc.primary_color_2 = *primary_color_2; - new_arc.secondary_color = *secondary_color; - new_arc.width = width; - } + smi->electrical_arcs.emplace_back(); + auto &new_arc = smi->electrical_arcs.back(); + + new_arc.type = static_cast(arc_type); + new_arc.endpoint_1 = *v1; + new_arc.endpoint_2 = *v2; - smi->num_arcs++; + if (arc_type == MARC_TYPE_SHIP || arc_type == MARC_TYPE_SCRIPTED) { + new_arc.primary_color_1 = *primary_color_1; + new_arc.primary_color_2 = *primary_color_2; + new_arc.secondary_color = *secondary_color; + new_arc.width = width; } } diff --git a/code/model/modelrender.cpp b/code/model/modelrender.cpp index dbcdf024622..601eb1cb0ac 100644 --- a/code/model/modelrender.cpp +++ b/code/model/modelrender.cpp @@ -40,9 +40,7 @@ extern int Model_polys; extern int tiling; extern float model_radius; -extern const int MAX_ARC_SEGMENT_POINTS; -extern int Num_arc_segment_points; -extern vec3d Arc_segment_points[]; +extern SCP_vector Arc_segment_points; extern bool Scene_framebuffer_in_frame; color Wireframe_color; @@ -810,12 +808,9 @@ model_draw_list::~model_draw_list() { void model_render_add_lightning(model_draw_list *scene, const model_render_params* interp, const polymodel *pm, const submodel_instance *smi ) { - int i; float width = 0.9f; color primary, secondary; - Assert( smi->num_arcs > 0 ); - if ( interp->get_model_flags() & MR_SHOW_OUTLINE_PRESET ) { return; } @@ -825,9 +820,7 @@ void model_render_add_lightning(model_draw_list *scene, const model_render_param return; } - for ( i = 0; i < smi->num_arcs; i++ ) { - auto &arc = smi->electrical_arcs[i]; - + for (auto &arc: smi->electrical_arcs) { // pick a color based upon arc type switch ( arc.type ) { // "normal", FreeSpace 1 style arcs @@ -1306,7 +1299,7 @@ void model_render_children_buffers(model_draw_list* scene, model_material *rende } } - if ( smi != nullptr && smi->num_arcs > 0 ) { + if ( smi != nullptr && !smi->electrical_arcs.empty() ) { model_render_add_lightning( scene, interp, pm, smi ); } @@ -1626,7 +1619,7 @@ void submodel_render_queue(const model_render_params *render_info, model_draw_li } } - if ( pmi && pmi->submodel[submodel_num].num_arcs > 0 ) { + if ( pmi && !pmi->submodel[submodel_num].electrical_arcs.empty() ) { model_render_add_lightning( scene, render_info, pm, &pmi->submodel[submodel_num] ); } @@ -2080,8 +2073,8 @@ void model_render_glow_points(const polymodel *pm, const polymodel_instance *pmi Assert( bank->points != nullptr ); int flick; - if (pmi != nullptr && pmi->submodel[pm->detail[0]].num_arcs > 0) { - flick = static_rand( timestamp() % 20 ) % (pmi->submodel[pm->detail[0]].num_arcs + j); //the more damage, the more arcs, the more likely the lights will fail + if (pmi != nullptr && !pmi->submodel[pm->detail[0]].electrical_arcs.empty()) { + flick = static_rand( timestamp() % 20 ) % (pmi->submodel[pm->detail[0]].electrical_arcs.size() + j); //the more damage, the more arcs, the more likely the lights will fail } else { flick = 1; } @@ -2516,10 +2509,10 @@ void model_render_insignias(const insignia_draw_data *insignia_data) void model_render_arc(const vec3d *v1, const vec3d *v2, const color *primary, const color *secondary, float arc_width) { - Num_arc_segment_points = 0; + Arc_segment_points.clear(); - // need need to add the first point - memcpy( &Arc_segment_points[Num_arc_segment_points++], v1, sizeof(vec3d) ); + // need to add the first point + Arc_segment_points.push_back(*v1); // this should fill in all of the middle, and the last, points interp_render_arc_segment(v1, v2, 0); @@ -2527,10 +2520,10 @@ void model_render_arc(const vec3d *v1, const vec3d *v2, const color *primary, co // use primary color for fist pass Assert( primary ); - g3_render_rod(primary, Num_arc_segment_points, Arc_segment_points, arc_width); + g3_render_rod(primary, static_cast(Arc_segment_points.size()), Arc_segment_points.data(), arc_width); if (secondary) { - g3_render_rod(secondary, Num_arc_segment_points, Arc_segment_points, arc_width * 0.33f); + g3_render_rod(secondary, static_cast(Arc_segment_points.size()), Arc_segment_points.data(), arc_width * 0.33f); } } @@ -2940,7 +2933,7 @@ void model_render_queue(const model_render_params* interp, model_draw_list* scen } else { model_render_buffers(scene, &rendering_material, interp, &pm->submodel[detail_model_num].buffer, pm, detail_model_num, detail_level, tmap_flags); - if ( pmi != nullptr && pmi->submodel[detail_model_num].num_arcs > 0 ) { + if ( pmi != nullptr && !pmi->submodel[detail_model_num].electrical_arcs.empty() ) { model_render_add_lightning( scene, interp, pm, &pmi->submodel[detail_model_num] ); } } diff --git a/code/scripting/api/objs/ship.cpp b/code/scripting/api/objs/ship.cpp index 2e4f56d53c3..218ef99eb78 100644 --- a/code/scripting/api/objs/ship.cpp +++ b/code/scripting/api/objs/ship.cpp @@ -2694,8 +2694,8 @@ ADE_FUNC(AddElectricArc, l_Ship, "vector firstPoint, vector secondPoint, number auto shipp = &Ships[objh->objp()->instance]; - // spawn the arc in the first unused slot - auto arc = ship_find_electrical_arc_slot(shipp); + // spawn the arc in the first unused slot, or in a new slot if there are no unused ones + auto arc = ship_find_or_create_electrical_arc_slot(shipp, false); if (arc) { arc->timestamp = _timestamp(fl2i(duration * MILLISECONDS_PER_SECOND)); @@ -2712,7 +2712,7 @@ ADE_FUNC(AddElectricArc, l_Ship, "vector firstPoint, vector secondPoint, number arc->width = width; - return ade_set_args(L, "i", static_cast(arc - shipp->electrical_arcs) + 1); // FS2 -> Lua + return ade_set_args(L, "i", static_cast(arc - shipp->electrical_arcs.data()) + 1); // FS2 -> Lua } return ade_set_args(L, "i", 0); @@ -2735,7 +2735,7 @@ ADE_FUNC(DeleteElectricArc, l_Ship, "number index", auto shipp = &Ships[objh->objp()->instance]; index--; // Lua -> FS2 - if (index >= 0 && index < MAX_ARC_EFFECTS) + if (SCP_vector_inbounds(shipp->electrical_arcs, index)) { shipp->electrical_arcs[index].timestamp = TIMESTAMP::invalid(); } @@ -2764,7 +2764,7 @@ ADE_FUNC(ModifyElectricArc, l_Ship, "number index, vector firstPoint, vector sec auto shipp = &Ships[objh->objp()->instance]; index--; // Lua -> FS2 - if (index >= 0 && index < MAX_ARC_EFFECTS) + if (SCP_vector_inbounds(shipp->electrical_arcs, index)) { auto &arc = shipp->electrical_arcs[index]; arc.endpoint_1 = *v1; diff --git a/code/ship/ship.cpp b/code/ship/ship.cpp index b5dc47a463d..698e8e81587 100644 --- a/code/ship/ship.cpp +++ b/code/ship/ship.cpp @@ -6866,9 +6866,7 @@ void ship::clear() for (int i = 0; i < NUM_SUB_EXPL_HANDLES; i++) sub_expl_sound_handle[i] = sound_handle::invalid(); - memset(&electrical_arcs, 0, MAX_ARC_EFFECTS * sizeof(ship_electrical_arc)); - for (int i = 0; i < MAX_ARC_EFFECTS; i++) - electrical_arcs[i].timestamp = TIMESTAMP::invalid(); + electrical_arcs.clear(); arc_next_time = TIMESTAMP::invalid(); emp_intensity = -1.0f; @@ -21399,7 +21397,7 @@ int ship_check_visibility(const ship* viewed, ship* viewer) return ship_is_visible; } -ship_electrical_arc *ship_find_electrical_arc_slot(ship *shipp) +ship_electrical_arc *ship_find_or_create_electrical_arc_slot(ship *shipp, bool no_create) { size_t i = 0; for (auto &ii : shipp->electrical_arcs) @@ -21409,8 +21407,12 @@ ship_electrical_arc *ship_find_electrical_arc_slot(ship *shipp) i++; } - if (i == MAX_ARC_EFFECTS) - return nullptr; + if (i == shipp->electrical_arcs.size()) + { + if (no_create) + return nullptr; + shipp->electrical_arcs.emplace_back(); + } return &shipp->electrical_arcs[i]; } diff --git a/code/ship/ship.h b/code/ship/ship.h index cb16a4c1d64..5ce7a343df0 100644 --- a/code/ship/ship.h +++ b/code/ship/ship.h @@ -728,7 +728,7 @@ class ship std::array sub_expl_sound_handle; // Stuff for showing electrical arcs on damaged ships - ship_electrical_arc electrical_arcs[MAX_ARC_EFFECTS]; + SCP_vector electrical_arcs; TIMESTAMP arc_next_time; // When the next damage/emp arc will be created. SCP_vector passive_arc_next_times; // When the next passive ship arc will be created. @@ -2126,7 +2126,7 @@ bool ship_secondary_has_ammo(ship_weapon* swp, int bank_index); // Used to check if one ship can see the other on radar int ship_check_visibility(const ship* viewed, ship* viewer); -// Find the first available arc slot. -ship_electrical_arc *ship_find_electrical_arc_slot(ship *shipp); +// Find the first available arc slot. If none is available, and no_create is false, add one. +ship_electrical_arc *ship_find_or_create_electrical_arc_slot(ship *shipp, bool no_create); #endif diff --git a/code/ship/shipfx.cpp b/code/ship/shipfx.cpp index e0190d2d043..ec7e020466f 100644 --- a/code/ship/shipfx.cpp +++ b/code/ship/shipfx.cpp @@ -2166,8 +2166,8 @@ void shipfx_do_lightning_arcs_frame( ship *shipp ) if (skip) continue; if (submodel_1 >= 0 && submodel_2 >= 0) { - // spawn the arc in the first unused slot - auto arc = ship_find_electrical_arc_slot(shipp); + // spawn the arc in the first unused slot, or in a new slot if there are no unused ones + auto arc = ship_find_or_create_electrical_arc_slot(shipp, shipp->electrical_arcs.size() >= MAX_ARC_EFFECTS); if (arc) { arc->timestamp = _timestamp(fl2i(arc_info->duration * MILLISECONDS_PER_SECOND)); @@ -2277,7 +2277,7 @@ void shipfx_do_lightning_arcs_frame( ship *shipp ) shipp->arc_next_time = TIMESTAMP::invalid(); // invalid, so it gets restarted next frame - int n, n_arcs = Random::next(1, 3); + int n_arcs = Random::next(1, 3); vec3d v1 = submodel_get_random_point(model_num, -1); vec3d v2 = submodel_get_random_point(model_num, -1); @@ -2315,18 +2315,18 @@ void shipfx_do_lightning_arcs_frame( ship *shipp ) } - n = 0; - float factor = 1.0f + 0.0025f*obj->radius; int a = (int) (factor*100.0f); int b = (int) (factor*1000.0f); int lifetime = Random::next(a, b); // Create the arc effects - int num_damage_arcs = 0; - for (int i=0; ielectrical_arcs[i]; - if ( !arc->timestamp.isValid() ) { + auto num_damage_arcs = std::count_if(shipp->electrical_arcs.begin(), shipp->electrical_arcs.end(), [](const ship_electrical_arc &arc) { + return arc.timestamp.isValid() && (arc.type == MARC_TYPE_DAMAGED || arc.type == MARC_TYPE_EMP); + }); + for (int n = 0; n < n_arcs && num_damage_arcs < MAX_SHIP_DAMAGE_ARCS; n++) { + auto arc = ship_find_or_create_electrical_arc_slot(shipp, false); + if (arc) { arc->timestamp = _timestamp(lifetime); // live up to a second switch( n ) { @@ -2353,16 +2353,11 @@ void shipfx_do_lightning_arcs_frame( ship *shipp ) } else { arc->type = MARC_TYPE_DAMAGED; } - - n++; + num_damage_arcs++; - if ( n == n_arcs || num_damage_arcs >= MAX_SHIP_DAMAGE_ARCS) - break; // Don't need to create anymore - } else if (arc->type == MARC_TYPE_DAMAGED || arc->type == MARC_TYPE_EMP) { - num_damage_arcs ++; } } - + // rotate v2 out of local coordinates into world. // Use v2 since it is used in every bolt. See above switch(). vec3d snd_pos;