Skip to content

Commit

Permalink
electrical arc upgrade, stage 3: add support for customizing segment …
Browse files Browse the repository at this point in the history
…depth and using persistent arc points
  • Loading branch information
Goober5000 committed Sep 21, 2024
1 parent f41fc22 commit 8548e7f
Show file tree
Hide file tree
Showing 10 changed files with 114 additions and 38 deletions.
2 changes: 1 addition & 1 deletion code/debris/debris.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1178,7 +1178,7 @@ void debris_render(object * obj, model_draw_list *scene)
if ( vm_vec_dist_quick( &obj->pos, &Eye_position ) < obj->radius*50.0f ) {
for (auto &arc: db->electrical_arcs) {
if ( arc.timestamp.isValid() ) {
model_instance_add_arc( pm, pmi, db->submodel_num, &arc.endpoint_1, &arc.endpoint_2, MARC_TYPE_DAMAGED );
model_instance_add_arc( pm, pmi, db->submodel_num, &arc.endpoint_1, &arc.endpoint_2, nullptr, MARC_TYPE_DAMAGED );
}
}
}
Expand Down
6 changes: 4 additions & 2 deletions code/model/model.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,12 @@ struct electrical_arc
vec3d endpoint_1;
vec3d endpoint_2;
ubyte type; // see MARC_TYPE_* defines
ubyte segment_depth; // number of times to divide the arc into segments
};

struct model_electrical_arc : electrical_arc
{
const SCP_vector<vec3d> *persistent_arc_points;
};

// Data specific to a particular instance of a submodel.
Expand Down Expand Up @@ -1204,8 +1206,8 @@ extern void model_set_up_techroom_instance(ship_info *sip, int model_instance_nu
void model_replicate_submodel_instance(polymodel *pm, polymodel_instance *pmi, int submodel_num, flagset<Ship::Subsystem_Flags>& flags);

// Adds an electrical arcing effect to a submodel
void model_instance_clear_arcs(polymodel *pm, polymodel_instance *pmi);
void model_instance_add_arc(polymodel *pm, polymodel_instance *pmi, int sub_model_num, vec3d *v1, vec3d *v2, int arc_type, color *primary_color_1 = nullptr, color *primary_color_2 = nullptr, color *secondary_color = nullptr, float width = 0.0f);
void model_instance_clear_arcs(const polymodel *pm, polymodel_instance *pmi);
void model_instance_add_arc(const polymodel *pm, polymodel_instance *pmi, int sub_model_num, const vec3d *v1, const vec3d *v2, const SCP_vector<vec3d> *persistent_arc_points, ubyte arc_type, const color *primary_color_1 = nullptr, const color *primary_color_2 = nullptr, const color *secondary_color = nullptr, float width = 0.0f, ubyte segment_depth = 4);

// Gets two random points on the surface of a submodel
extern vec3d submodel_get_random_point(int model_num, int submodel_num, int seed = -1);
Expand Down
14 changes: 6 additions & 8 deletions code/model/modelinterp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -785,15 +785,13 @@ void model_draw_bay_paths_htl(int model_num)
gr_set_cull(cull);
}

SCP_vector<vec3d> Arc_segment_points;

void interp_render_arc_segment(const vec3d *v1, const vec3d *v2, int depth )
void interp_generate_arc_segment(SCP_vector<vec3d> &arc_segment_points, const vec3d *v1, const vec3d *v2, ubyte depth_limit, ubyte depth)
{
float d = vm_vec_dist_quick( v1, v2 );
const float scaler = 0.30f;
constexpr float scaler = 0.30f;

if ( (d < scaler) || (depth > 4) ) {
Arc_segment_points.push_back(*v2);
if ( (d < scaler) || (depth > depth_limit) ) {
arc_segment_points.push_back(*v2);
} else {
// divide in half
vec3d tmp;
Expand All @@ -804,8 +802,8 @@ void interp_render_arc_segment(const vec3d *v1, const vec3d *v2, int depth )
tmp.xyz.z += (frand() - 0.5f) * d * scaler;

// add additional point
interp_render_arc_segment( v1, &tmp, depth+1 );
interp_render_arc_segment( &tmp, v2, depth+1 );
interp_generate_arc_segment( arc_segment_points, v1, &tmp, depth_limit, depth+1 );
interp_generate_arc_segment( arc_segment_points, &tmp, v2, depth_limit, depth+1 );
}
}

Expand Down
8 changes: 5 additions & 3 deletions code/model/modelread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5154,7 +5154,7 @@ void model_do_intrinsic_motions(object *objp)
}
}

void model_instance_clear_arcs(polymodel *pm, polymodel_instance *pmi)
void model_instance_clear_arcs(const polymodel *pm, polymodel_instance *pmi)
{
Assert(pm->id == pmi->model_num);

Expand All @@ -5164,7 +5164,7 @@ void model_instance_clear_arcs(polymodel *pm, polymodel_instance *pmi)
}

// Adds an electrical arcing effect to a submodel
void model_instance_add_arc(polymodel *pm, polymodel_instance *pmi, int sub_model_num, vec3d *v1, vec3d *v2, int arc_type, color *primary_color_1, color *primary_color_2, color *secondary_color, float width )
void model_instance_add_arc(const polymodel *pm, polymodel_instance *pmi, int sub_model_num, const vec3d *v1, const vec3d *v2, const SCP_vector<vec3d> *persistent_arc_points, ubyte arc_type, const color *primary_color_1, const color *primary_color_2, const color *secondary_color, float width, ubyte segment_depth)
{
Assert(pm->id == pmi->model_num);

Expand All @@ -5182,9 +5182,11 @@ void model_instance_add_arc(polymodel *pm, polymodel_instance *pmi, int sub_mode
smi->electrical_arcs.emplace_back();
auto &new_arc = smi->electrical_arcs.back();

new_arc.type = static_cast<ubyte>(arc_type);
new_arc.type = arc_type;
new_arc.endpoint_1 = *v1;
new_arc.endpoint_2 = *v2;
new_arc.persistent_arc_points = persistent_arc_points;
new_arc.segment_depth = segment_depth;

if (arc_type == MARC_TYPE_SHIP || arc_type == MARC_TYPE_SCRIPTED) {
new_arc.primary_color_1 = *primary_color_1;
Expand Down
41 changes: 27 additions & 14 deletions code/model/modelrender.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,10 @@ extern int Model_polys;
extern int tiling;
extern float model_radius;

extern SCP_vector<vec3d> Arc_segment_points;

extern bool Scene_framebuffer_in_frame;
color Wireframe_color;

extern void interp_render_arc_segment(const vec3d *v1, const vec3d *v2, int depth);
extern void interp_generate_arc_segment(SCP_vector<vec3d> &arc_segment_points, const vec3d *v1, const vec3d *v2, ubyte depth_limit, ubyte depth);

int model_render_determine_elapsed_time(int objnum, uint64_t flags);

Expand Down Expand Up @@ -444,7 +442,7 @@ void model_draw_list::add_submodel_to_batch(int model_num)
TransformBufferHandler.set_model_transform(transform, model_num);
}

void model_draw_list::add_arc(const vec3d *v1, const vec3d *v2, const color *primary, const color *secondary, float arc_width)
void model_draw_list::add_arc(const vec3d *v1, const vec3d *v2, const SCP_vector<vec3d> *persistent_arc_points, const color *primary, const color *secondary, float arc_width, ubyte segment_depth)
{
arc_effect new_arc;

Expand All @@ -454,6 +452,8 @@ void model_draw_list::add_arc(const vec3d *v1, const vec3d *v2, const color *pri
new_arc.primary = *primary;
new_arc.secondary = *secondary;
new_arc.width = arc_width;
new_arc.segment_depth = segment_depth;
new_arc.persistent_arc_points = persistent_arc_points;

Arcs.push_back(new_arc);
}
Expand Down Expand Up @@ -623,7 +623,7 @@ void model_draw_list::render_arc(const arc_effect &arc)
{
g3_start_instance_matrix(&arc.transform);

model_render_arc(&arc.v1, &arc.v2, &arc.primary, &arc.secondary, arc.width);
model_render_arc(&arc.v1, &arc.v2, arc.persistent_arc_points, &arc.primary, &arc.secondary, arc.width, arc.segment_depth);

g3_done_instance(true);
}
Expand Down Expand Up @@ -887,7 +887,7 @@ void model_render_add_lightning(model_draw_list *scene, const model_render_param

// render the actual arc segment
if (width > 0.0f)
scene->add_arc(&arc.endpoint_1, &arc.endpoint_2, &primary, &secondary, width);
scene->add_arc(&arc.endpoint_1, &arc.endpoint_2, arc.persistent_arc_points, &primary, &secondary, width, arc.segment_depth);
}
}

Expand Down Expand Up @@ -2507,23 +2507,36 @@ 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)
SCP_vector<vec3d> Arc_segment_points;

void model_render_arc(const vec3d *v1, const vec3d *v2, const SCP_vector<vec3d> *persistent_arc_points, const color *primary, const color *secondary, float arc_width, ubyte depth_limit)
{
Arc_segment_points.clear();
int size;
const vec3d *pvecs;

if (persistent_arc_points) {
size = static_cast<int>(persistent_arc_points->size());
pvecs = persistent_arc_points->data();
} else {
Arc_segment_points.clear();

// need to add the first point
Arc_segment_points.push_back(*v1);

// 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_generate_arc_segment(Arc_segment_points, v1, v2, depth_limit, 0);

// this should fill in all of the middle, and the last, points
interp_render_arc_segment(v1, v2, 0);
size = static_cast<int>(Arc_segment_points.size());
pvecs = Arc_segment_points.data();
}

// use primary color for fist pass
Assert( primary );

g3_render_rod(primary, static_cast<int>(Arc_segment_points.size()), Arc_segment_points.data(), arc_width);
g3_render_rod(primary, size, pvecs, arc_width);

if (secondary) {
g3_render_rod(secondary, static_cast<int>(Arc_segment_points.size()), Arc_segment_points.data(), arc_width * 0.33f);
g3_render_rod(secondary, size, pvecs, arc_width * 0.33f);
}
}

Expand Down
7 changes: 5 additions & 2 deletions code/model/modelrender.h
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,9 @@ struct arc_effect
color primary;
color secondary;
float width;
ubyte segment_depth;

const SCP_vector<vec3d> *persistent_arc_points;
};

struct insignia_draw_data
Expand Down Expand Up @@ -281,7 +284,7 @@ class model_draw_list
void pop_transform();
void set_scale(const vec3d *scale = NULL);

void add_arc(const vec3d *v1, const vec3d *v2, const color *primary, const color *secondary, float arc_width);
void add_arc(const vec3d *v1, const vec3d *v2, const SCP_vector<vec3d> *persistent_arc_points, const color *primary, const color *secondary, float arc_width, ubyte segment_depth);
void render_arcs();

void add_insignia(const model_render_params *params, const polymodel *pm, int detail_level, int bitmap_num);
Expand All @@ -308,7 +311,7 @@ void submodel_render_immediate(const model_render_params* render_info, const pol
void submodel_render_queue(const model_render_params* render_info, model_draw_list* scene, const polymodel* pm, const polymodel_instance* pmi, int submodel_num, const matrix* orient, const vec3d* pos);
void model_render_buffers(model_draw_list* scene, model_material* rendering_material, const model_render_params* interp, const vertex_buffer* buffer, const polymodel* pm, int mn, int detail_level, uint tmap_flags);
bool model_render_check_detail_box(const vec3d* view_pos, const polymodel* pm, int submodel_num, uint64_t flags);
void model_render_arc(const vec3d* v1, const vec3d* v2, const color* primary, const color* secondary, float arc_width);
void model_render_arc(const vec3d* v1, const vec3d* v2, const SCP_vector<vec3d> *persistent_arc_points, const color* primary, const color* secondary, float arc_width, ubyte depth_limit);
void model_render_insignias(const insignia_draw_data* insignia);
void model_render_set_wireframe_color(const color* clr);
bool render_tech_model(tech_render_type model_type, int x1, int y1, int x2, int y2, float zoom, bool lighting, int class_idx, const matrix* orient, const SCP_string& pof_filename = "", float closeup_zoom = 0, const vec3d* closeup_pos = &vmd_zero_vector);
Expand Down
61 changes: 54 additions & 7 deletions code/scripting/api/objs/ship.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
extern void ship_reset_disabled_physics(object *objp, int ship_class);
extern bool sexp_check_flag_arrays(const char *flag_name, Object::Object_Flags &object_flag, Ship::Ship_Flags &ship_flags, Mission::Parse_Object_Flags &parse_obj_flag, AI::AI_Flags &ai_flag);
extern void sexp_alter_ship_flag_helper(object_ship_wing_point_team &oswpt, bool future_ships, Object::Object_Flags object_flag, Ship::Ship_Flags ship_flag, Mission::Parse_Object_Flags parse_obj_flag, AI::AI_Flags ai_flag, bool set_flag);
extern void interp_generate_arc_segment(SCP_vector<vec3d> &arc_segment_points, const vec3d *v1, const vec3d *v2, ubyte depth_limit, ubyte depth);

namespace scripting {
namespace api {
Expand Down Expand Up @@ -2675,8 +2676,9 @@ ADE_FUNC(jettison, l_Ship, "number jettison_speed, [ship... dockee_ships /* All
return jettison_helper(L, docker_objh, jettison_speed, 2);
}

ADE_FUNC(AddElectricArc, l_Ship, "vector firstPoint, vector secondPoint, number duration, number width",
"Creates an electric arc on the ship between two points in the ship's reference frame, for the specified duration in seconds, and the specified width in meters.",
ADE_FUNC(AddElectricArc, l_Ship, "vector firstPoint, vector secondPoint, number duration, number width, [number segment_depth, boolean persistent_points]",
"Creates an electric arc on the ship between two points in the ship's reference frame, for the specified duration in seconds, and the specified width in meters. Optionally, "
"specify the segment depth (the number of times the spark is divided) and whether to generate a set of arc points that will persist from frame to frame.",
"number",
"The arc index if successful, 0 otherwise")
{
Expand All @@ -2685,8 +2687,10 @@ ADE_FUNC(AddElectricArc, l_Ship, "vector firstPoint, vector secondPoint, number
vec3d* v2;
float duration = 0.0f;
float width = 0.0f;
int segment_depth = 4;
bool persistent_points = false;

if (!ade_get_args(L, "oooff", l_Ship.GetPtr(&objh), l_Vector.GetPtr(&v1), l_Vector.GetPtr(&v2), &duration, &width))
if (!ade_get_args(L, "oooff|ib", l_Ship.GetPtr(&objh), l_Vector.GetPtr(&v1), l_Vector.GetPtr(&v2), &duration, &width, &segment_depth, &persistent_points))
return ade_set_error(L, "i", 0);

if (!objh->isValid())
Expand All @@ -2711,6 +2715,19 @@ ADE_FUNC(AddElectricArc, l_Ship, "vector firstPoint, vector secondPoint, number
arc->type = MARC_TYPE_SCRIPTED;

arc->width = width;
arc->segment_depth = static_cast<ubyte>(segment_depth);

// we might want to generate the arc points ahead of time, rather than every frame
if (persistent_points)
{
arc->persistent_arc_points.reset(new SCP_vector<vec3d>());

// need to add the first point
arc->persistent_arc_points->push_back(*v1);

// this should fill in all of the middle, and the last, points
interp_generate_arc_segment(*arc->persistent_arc_points, v1, v2, static_cast<ubyte>(segment_depth), 1); // start at depth 1 for the benefit of Lua
}

return ade_set_args(L, "i", static_cast<int>(arc - shipp->electrical_arcs.data()) + 1); // FS2 -> Lua
}
Expand Down Expand Up @@ -2743,8 +2760,9 @@ ADE_FUNC(DeleteElectricArc, l_Ship, "number index",
return ADE_RETURN_NIL;
}

ADE_FUNC(ModifyElectricArc, l_Ship, "number index, vector firstPoint, vector secondPoint, [number width]",
"Sets the endpoints (in the ship's reference frame) and width of the specified electric arc on the ship, .",
ADE_FUNC(ModifyElectricArc, l_Ship, "number index, vector firstPoint, vector secondPoint, [number width, number segment_depth, boolean persistent_points]",
"Sets the endpoints (in the ship's reference frame), width, and segment depth of the specified electric arc on the ship, plus whether the arc has persistent points. "
"If this arc already had a collection of persistent points and it still does after this function is called, the points will be regenerated.",
nullptr,
nullptr)
{
Expand All @@ -2753,8 +2771,10 @@ ADE_FUNC(ModifyElectricArc, l_Ship, "number index, vector firstPoint, vector sec
vec3d* v1;
vec3d* v2;
float width = 0.0f;
int segment_depth = 4;
bool persistent_points = false;

int args = ade_get_args(L, "oioo|f", l_Ship.GetPtr(&objh), &index, l_Vector.GetPtr(&v1), l_Vector.GetPtr(&v2), &width);
int args = ade_get_args(L, "oioo|fib", l_Ship.GetPtr(&objh), &index, l_Vector.GetPtr(&v1), l_Vector.GetPtr(&v2), &width, &segment_depth, &persistent_points);
if (args < 4)
return ADE_RETURN_NIL;

Expand All @@ -2770,8 +2790,35 @@ ADE_FUNC(ModifyElectricArc, l_Ship, "number index, vector firstPoint, vector sec
arc.endpoint_1 = *v1;
arc.endpoint_2 = *v2;

if (args == 5)
if (args >= 5)
arc.width = width;
if (args >= 6)
arc.segment_depth = static_cast<ubyte>(segment_depth);
if (args >= 7)
{
if (persistent_points)
{
if (!arc.persistent_arc_points)
arc.persistent_arc_points.reset(new SCP_vector<vec3d>());
}
else
{
if (arc.persistent_arc_points)
arc.persistent_arc_points.reset();
}
}

// persistent points need to be regenerated when the arc is moved; they also need to be generated if we are adding them for the first time
if (arc.persistent_arc_points)
{
arc.persistent_arc_points->clear();

// need to add the first point
arc.persistent_arc_points->push_back(*v1);

// this should fill in all of the middle, and the last, points
interp_generate_arc_segment(*arc.persistent_arc_points, v1, v2, static_cast<ubyte>(segment_depth), 1); // start at depth 1 for the benefit of Lua
}
}

return ADE_RETURN_NIL;
Expand Down
2 changes: 1 addition & 1 deletion code/ship/ship.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20958,7 +20958,7 @@ void ship_render(object* obj, model_draw_list* scene)
if ( vm_vec_dist_quick( &obj->pos, &Eye_position ) < obj->radius*50.0f && !Rendering_to_shadow_map ) {
for (auto &arc: shipp->electrical_arcs) {
if (arc.timestamp.isValid()) {
model_instance_add_arc(pm, pmi, -1, &arc.endpoint_1, &arc.endpoint_2, arc.type, &arc.primary_color_1, &arc.primary_color_2, &arc.secondary_color, arc.width);
model_instance_add_arc(pm, pmi, -1, &arc.endpoint_1, &arc.endpoint_2, arc.persistent_arc_points.get(), arc.type, &arc.primary_color_1, &arc.primary_color_2, &arc.secondary_color, arc.width, arc.segment_depth);
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions code/ship/ship.h
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,9 @@ struct reload_pct
struct ship_electrical_arc : electrical_arc
{
TIMESTAMP timestamp; // When this times out, the spark goes away. Invalid is not used

// if this vector exists, these points will be used instead of the ones generated on each frame by interp_generate_arc_segment()
std::unique_ptr<SCP_vector<vec3d>> persistent_arc_points;
};

// NOTE: Can't be treated as a struct anymore, since it has STL data structures in its object tree!
Expand Down
8 changes: 8 additions & 0 deletions code/ship/shipfx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2205,6 +2205,10 @@ void shipfx_do_lightning_arcs_frame( ship *shipp )
}
}

arc->segment_depth = 4; // previously hard-coded in interp_generate_arc_segment()

arc->persistent_arc_points.reset(); // by default, no persistent points

shipp->passive_arc_next_times[passive_arc_info_idx] = _timestamp(fl2i(arc_info->frequency * MILLISECONDS_PER_SECOND));
}
}
Expand Down Expand Up @@ -2354,6 +2358,10 @@ void shipfx_do_lightning_arcs_frame( ship *shipp )
arc->type = MARC_TYPE_DAMAGED;
}

arc->segment_depth = 4; // previously hard-coded in interp_generate_arc_segment()

arc->persistent_arc_points.reset(); // by default, no persistent points

num_damage_arcs++;
}
}
Expand Down

0 comments on commit 8548e7f

Please sign in to comment.