From 3fbe83a32029769509d827ae5068d7cbde5c9b57 Mon Sep 17 00:00:00 2001 From: Birk Magnussen <6238428+BMagnu@users.noreply.github.com> Date: Thu, 22 Jan 2026 22:04:17 +0900 Subject: [PATCH 1/6] Revert "Move insignia post-processing to model load" This reverts commit 665d7145b65f05c88a7321f4d79ba61b7c28b03a. --- code/model/model.h | 16 ++++--- code/model/modelread.cpp | 89 +++++++++++++++----------------------- code/model/modelrender.cpp | 47 +++++++++++++++++--- 3 files changed, 87 insertions(+), 65 deletions(-) diff --git a/code/model/model.h b/code/model/model.h index e88a1c67948..127586dfbd3 100644 --- a/code/model/model.h +++ b/code/model/model.h @@ -729,9 +729,13 @@ typedef struct cross_section { #define MAX_INS_FACES 128 typedef struct insignia { int detail_level; - vec3d position; - matrix orientation; - float diameter; + int num_faces; + int faces[MAX_INS_FACES][MAX_INS_FACE_VECS]; // indices into the vecs array + float u[MAX_INS_FACES][MAX_INS_FACE_VECS]; // u tex coords on a per-face-per-vertex basis + float v[MAX_INS_FACES][MAX_INS_FACE_VECS]; // v tex coords on a per-face-per-vertex bases + vec3d vecs[MAX_INS_VECS]; // vertex list + vec3d offset; // global position offset for this insignia + vec3d norm[MAX_INS_VECS] ; //normal of the insignia-Bobboau } insignia; #define PM_FLAG_ALLOW_TILING (1<<0) // Allow texture tiling @@ -807,7 +811,7 @@ class polymodel n_view_positions(0), rad(0.0f), core_radius(0.0f), n_textures(0), submodel(NULL), n_guns(0), n_missiles(0), n_docks(0), n_thrusters(0), gun_banks(NULL), missile_banks(NULL), docking_bays(NULL), thrusters(NULL), ship_bay(NULL), shield(), shield_collision_tree(NULL), sldc_size(0), n_paths(0), paths(NULL), mass(0), num_xc(0), xc(NULL), num_split_plane(0), - used_this_mission(0), n_glow_point_banks(0), glow_point_banks(nullptr), + num_ins(0), used_this_mission(0), n_glow_point_banks(0), glow_point_banks(nullptr), vert_source() { filename[0] = 0; @@ -820,6 +824,7 @@ class polymodel memset(&bounding_box, 0, 8 * sizeof(vec3d)); memset(&view_positions, 0, MAX_EYES * sizeof(eye)); memset(&split_plane, 0, MAX_SPLIT_PLANE * sizeof(float)); + memset(&ins, 0, MAX_MODEL_INSIGNIAS * sizeof(insignia)); #ifndef NDEBUG ram_used = 0; @@ -894,7 +899,8 @@ class polymodel int num_split_plane; // number of split planes float split_plane[MAX_SPLIT_PLANE]; // actual split plane z coords (for big ship explosions) - SCP_vector ins; + insignia ins[MAX_MODEL_INSIGNIAS]; + int num_ins; #ifndef NDEBUG int ram_used; // How much RAM this model uses diff --git a/code/model/modelread.cpp b/code/model/modelread.cpp index 67fa2ccdbf4..33fddbfaeb8 100644 --- a/code/model/modelread.cpp +++ b/code/model/modelread.cpp @@ -1657,8 +1657,8 @@ modelread_status read_model_file_no_subsys(polymodel * pm, const char* filename, memset( &pm->view_positions, 0, sizeof(pm->view_positions) ); - // reset insignia - pm->ins.clear(); + // reset insignia counts + pm->num_ins = 0; // reset glow points!! - Goober5000 pm->n_glow_point_banks = 0; @@ -2806,80 +2806,61 @@ modelread_status read_model_file_no_subsys(polymodel * pm, const char* filename, } break; - case ID_INSG: { + case ID_INSG: + int num_ins, num_verts, num_faces, idx, idx2, idx3; + // get the # of insignias - int num_ins = cfread_int(fp); - pm->ins = SCP_vector(num_ins); + num_ins = cfread_int(fp); + pm->num_ins = num_ins; // read in the insignias - for (int idx = 0; idx < num_ins; idx++){ - insignia& ins = pm->ins[idx]; - + for(idx=0; idxfilename, ins.detail_level); + pm->ins[idx].detail_level = cfread_int(fp); + if (pm->ins[idx].detail_level < 0) { + Warning(LOCATION, "Model '%s': insignia uses an invalid LOD (%i)\n", pm->filename, pm->ins[idx].detail_level); } // # of faces - int num_faces = cfread_int(fp); + num_faces = cfread_int(fp); + pm->ins[idx].num_faces = num_faces; + Assert(num_faces <= MAX_INS_FACES); // # of vertices - int num_verts = cfread_int(fp); - SCP_vector vertices(num_verts); + num_verts = cfread_int(fp); + Assert(num_verts <= MAX_INS_VECS); // read in all the vertices - for(int idx2 = 0; idx2 < num_verts; idx2++){ - cfread_vector(&vertices[idx2], fp); + for(idx2=0; idx2ins[idx].vecs[idx2], fp); } - vec3d offset; // read in world offset - cfread_vector(&offset, fp); - - vec3d min {{{FLT_MAX, FLT_MAX, FLT_MAX}}}; - vec3d max {{{-FLT_MAX, -FLT_MAX, -FLT_MAX}}}; - vec3d avg_total = ZERO_VECTOR; - vec3d avg_normal = ZERO_VECTOR; + cfread_vector(&pm->ins[idx].offset, fp); // read in all the faces - for(int idx2 = 0; idx2 < num_faces; idx2++){ - std::array faces; + for(idx2=0; idx2ins[idx].num_faces; idx2++){ // read in 3 vertices - for(int idx3 = 0; idx3 < 3; idx3++){ - faces[idx3] = cfread_int(fp); - - //UV coords are no longer needed - cfread_float(fp); - cfread_float(fp); + for(idx3=0; idx3<3; idx3++){ + pm->ins[idx].faces[idx2][idx3] = cfread_int(fp); + pm->ins[idx].u[idx2][idx3] = cfread_float(fp); + pm->ins[idx].v[idx2][idx3] = cfread_float(fp); } + vec3d tempv; - const vec3d& v1 = vertices[faces[0]]; - const vec3d& v2 = vertices[faces[1]]; - const vec3d& v3 = vertices[faces[2]]; - - vec3d normal; //get three points (rotated) and compute normal - vm_vec_perp(&normal, &v1, &v2, &v3); - - vm_vec_min(&min, &min, &v1); - vm_vec_min(&min, &min, &v2); - vm_vec_min(&min, &min, &v3); - vm_vec_max(&max, &max, &v1); - vm_vec_max(&max, &max, &v2); - vm_vec_max(&max, &max, &v3); - - vec3d avg = (v1 + v2 + v3) * (1.0f / 3.0f); - avg_total += avg; - avg_normal += normal; + + vm_vec_perp(&tempv, + &pm->ins[idx].vecs[pm->ins[idx].faces[idx2][0]], + &pm->ins[idx].vecs[pm->ins[idx].faces[idx2][1]], + &pm->ins[idx].vecs[pm->ins[idx].faces[idx2][2]]); + + vm_vec_normalize_safe(&tempv); + + pm->ins[idx].norm[idx2] = tempv; // mprintf(("insignorm %.2f %.2f %.2f\n",pm->ins[idx].norm[idx2].xyz.x, pm->ins[idx].norm[idx2].xyz.y, pm->ins[idx].norm[idx2].xyz.z)); - } - ins.position = avg_total / static_cast(num_faces) + offset; - vec3d bb = max - min; - ins.diameter = std::max({bb.xyz.x, bb.xyz.y, bb.xyz.z}); - vm_vector_2_matrix(&ins.orientation, &avg_normal, &vmd_z_vector); - } + } } break; diff --git a/code/model/modelrender.cpp b/code/model/modelrender.cpp index 8a11c310379..5bdbe2e5d01 100644 --- a/code/model/modelrender.cpp +++ b/code/model/modelrender.cpp @@ -2865,23 +2865,58 @@ void model_render_queue(const model_render_params* interp, model_draw_list* scen // MARKED! if ( !( model_flags & MR_NO_TEXTURING ) && !( model_flags & MR_NO_INSIGNIA) && objnum >= 0 ) { int bitmap_num = interp->get_insignia_bitmap(); - if ( (!pm->ins.empty()) && (bitmap_num >= 0) ) { + if ( (pm->num_ins > 0) && (bitmap_num >= 0) ) { - for (const auto& ins : pm->ins) { + for (int idx=0; idxnum_ins; idx++) { // skip insignias not on our detail level - if (ins.detail_level != detail_level) { + if (pm->ins[idx].detail_level != detail_level) { continue; } + vec3d min {{{FLT_MAX, FLT_MAX, FLT_MAX}}}; + vec3d max {{{-FLT_MAX, -FLT_MAX, -FLT_MAX}}}; + vec3d avg_total = ZERO_VECTOR; + vec3d avg_normal = ZERO_VECTOR; + for(int s_idx=0; s_idxins[idx].num_faces; s_idx++) { + // get vertex indices + int i1 = pm->ins[idx].faces[s_idx][0]; + int i2 = pm->ins[idx].faces[s_idx][1]; + int i3 = pm->ins[idx].faces[s_idx][2]; + + const vec3d& v1 = pm->ins[idx].vecs[i1]; + const vec3d& v2 = pm->ins[idx].vecs[i2]; + const vec3d& v3 = pm->ins[idx].vecs[i3]; + + vm_vec_min(&min, &min, &v1); + vm_vec_min(&min, &min, &v2); + vm_vec_min(&min, &min, &v3); + vm_vec_max(&max, &max, &v1); + vm_vec_max(&max, &max, &v2); + vm_vec_max(&max, &max, &v3); + + // transform vecs and setup vertices + vec3d avg = (v1 + v2 + v3) * (1.0f / 3.0f); + avg_total += avg; + + const vec3d& u = v2 - v1; + const vec3d& v = v3 - v1; + avg_normal.xyz.x += u.xyz.y * v.xyz.z - u.xyz.z * v.xyz.y; + avg_normal.xyz.y += u.xyz.z * v.xyz.x - u.xyz.x * v.xyz.z; + avg_normal.xyz.z += u.xyz.x * v.xyz.y - u.xyz.y * v.xyz.x; + } + avg_total /= pm->ins[idx].num_faces; + vec3d bb = max - min; + float diameter = std::max({bb.xyz.x, bb.xyz.y, bb.xyz.z}); + decals::Decal decal; decal.object = &Objects[objnum]; - decal.position = ins.position; + decal.position = avg_total + pm->ins[idx].offset; decal.submodel = -1; - decal.scale = vec3d{{{ins.diameter, ins.diameter, ins.diameter}}}; + decal.scale = vec3d{{{diameter, diameter, diameter}}}; decal.orig_obj_type = OBJ_SHIP; decal.creation_time = f2fl(Missiontime); decal.lifetime = 1.0f; - decal.orientation = ins.orientation; + vm_vector_2_matrix(&decal.orientation, &avg_normal, &vmd_z_vector); decal.definition_handle = std::make_tuple(bitmap_num, -1, -1); decals::addSingleFrameDecal(std::move(decal)); } From e14144fc9754d737b48e34cce52665460fafb972 Mon Sep 17 00:00:00 2001 From: Birk Magnussen <6238428+BMagnu@users.noreply.github.com> Date: Thu, 22 Jan 2026 22:04:30 +0900 Subject: [PATCH 2/6] Revert "Cleanup of old insignia stuff" This reverts commit fdf98a1f3a39d772756cc4c13638e69e694a04fd. --- code/def_files/data/effects/decal-v.sdr | 2 +- code/model/modelrender.cpp | 114 ++++++++++++++++++++++++ code/model/modelrender.h | 5 ++ code/object/objectsort.cpp | 1 + 4 files changed, 121 insertions(+), 1 deletion(-) diff --git a/code/def_files/data/effects/decal-v.sdr b/code/def_files/data/effects/decal-v.sdr index bd3511e0c7e..d90bddb7aa3 100644 --- a/code/def_files/data/effects/decal-v.sdr +++ b/code/def_files/data/effects/decal-v.sdr @@ -37,6 +37,6 @@ void main() { modelMatrix[2][3] = 0.0; invModelMatrix = inverse(modelMatrix); - decalDirection = mat3(viewMatrix) * modelMatrix[2].xyz; + decalDirection = mat3(viewMatrix) * vec3(modelMatrix[2][0], modelMatrix[2][1], modelMatrix[2][2]); gl_Position = projMatrix * viewMatrix * modelMatrix * vertPosition; } diff --git a/code/model/modelrender.cpp b/code/model/modelrender.cpp index 5bdbe2e5d01..730be2853b7 100644 --- a/code/model/modelrender.cpp +++ b/code/model/modelrender.cpp @@ -641,6 +641,51 @@ void model_draw_list::render_arcs() gr_zbuffer_set(mode); } +void model_draw_list::add_insignia(const model_render_params *params, const polymodel *pm, int detail_level, int bitmap_num) +{ + insignia_draw_data new_insignia; + + new_insignia.transform = Transformations.get_transform(); + new_insignia.pm = pm; + new_insignia.detail_level = detail_level; + new_insignia.bitmap_num = bitmap_num; + + new_insignia.clip = params->is_clip_plane_set(); + new_insignia.clip_normal = params->get_clip_plane_normal(); + new_insignia.clip_position = params->get_clip_plane_pos(); + + Insignias.push_back(new_insignia); +} + +void model_draw_list::render_insignia(const insignia_draw_data &insignia_info) +{ + if ( insignia_info.clip ) { + vec3d tmp; + vec3d pos; + + vm_matrix4_get_offset(&pos, &insignia_info.transform); + vm_vec_sub(&tmp, &pos, &insignia_info.clip_position); + vm_vec_normalize(&tmp); + + if ( vm_vec_dot(&tmp, &insignia_info.clip_normal) < 0.0f) { + return; + } + } + + g3_start_instance_matrix(&insignia_info.transform); + + model_render_insignias(&insignia_info); + + g3_done_instance(true); +} + +void model_draw_list::render_insignias() +{ + for ( size_t i = 0; i < Insignias.size(); ++i ) { + render_insignia(Insignias[i]); + } +} + void model_draw_list::add_outline(const vertex* vert_array, int n_verts, const color *clr) { outline_draw draw_info; @@ -2382,6 +2427,74 @@ void model_queue_render_thrusters(const model_render_params *interp, const polym } } +void model_render_insignias(const insignia_draw_data *insignia_data) +{ + auto pm = insignia_data->pm; + int detail_level = insignia_data->detail_level; + int bitmap_num = insignia_data->bitmap_num; + + // if the model has no insignias, or we don't have a texture, then bail + if ( (pm->num_ins <= 0) || (bitmap_num < 0) ) + return; + + int idx, s_idx; + vertex vecs[3]; + vec3d t1, t2, t3; + int i1, i2, i3; + + material insignia_material; + insignia_material.set_depth_bias(1); + + // set the proper texture + material_set_unlit(&insignia_material, bitmap_num, 0.65f, true, true); + + if ( insignia_data->clip ) { + insignia_material.set_clip_plane(insignia_data->clip_normal, insignia_data->clip_position); + } + + // otherwise render them + for(idx=0; idxnum_ins; idx++){ + // skip insignias not on our detail level + if(pm->ins[idx].detail_level != detail_level){ + continue; + } + + for(s_idx=0; s_idxins[idx].num_faces; s_idx++){ + // get vertex indices + i1 = pm->ins[idx].faces[s_idx][0]; + i2 = pm->ins[idx].faces[s_idx][1]; + i3 = pm->ins[idx].faces[s_idx][2]; + + // transform vecs and setup vertices + vm_vec_add(&t1, &pm->ins[idx].vecs[i1], &pm->ins[idx].offset); + vm_vec_add(&t2, &pm->ins[idx].vecs[i2], &pm->ins[idx].offset); + vm_vec_add(&t3, &pm->ins[idx].vecs[i3], &pm->ins[idx].offset); + + g3_transfer_vertex(&vecs[0], &t1); + g3_transfer_vertex(&vecs[1], &t2); + g3_transfer_vertex(&vecs[2], &t3); + + // setup texture coords + vecs[0].texture_position.u = pm->ins[idx].u[s_idx][0]; + vecs[0].texture_position.v = pm->ins[idx].v[s_idx][0]; + + vecs[1].texture_position.u = pm->ins[idx].u[s_idx][1]; + vecs[1].texture_position.v = pm->ins[idx].v[s_idx][1]; + + vecs[2].texture_position.u = pm->ins[idx].u[s_idx][2]; + vecs[2].texture_position.v = pm->ins[idx].v[s_idx][2]; + + light_apply_rgb( &vecs[0].r, &vecs[0].g, &vecs[0].b, &pm->ins[idx].vecs[i1], &pm->ins[idx].norm[i1], 1.5f ); + light_apply_rgb( &vecs[1].r, &vecs[1].g, &vecs[1].b, &pm->ins[idx].vecs[i2], &pm->ins[idx].norm[i2], 1.5f ); + light_apply_rgb( &vecs[2].r, &vecs[2].g, &vecs[2].b, &pm->ins[idx].vecs[i3], &pm->ins[idx].norm[i3], 1.5f ); + vecs[0].a = vecs[1].a = vecs[2].a = 255; + + // draw the polygon + g3_render_primitives_colored_textured(&insignia_material, vecs, 3, PRIM_TYPE_TRIFAN, false); + } + } +} + SCP_vector Arc_segment_points; void model_render_arc(const vec3d *v1, const vec3d *v2, const SCP_vector *persistent_arc_points, const color *primary, const color *secondary, float arc_width, ubyte depth_limit) @@ -2541,6 +2654,7 @@ void model_render_immediate(const model_render_params* render_info, int model_nu } model_list.render_outlines(); + model_list.render_insignias(); model_list.render_arcs(); gr_zbias(0); diff --git a/code/model/modelrender.h b/code/model/modelrender.h index c516eb7ba0a..3758da24189 100644 --- a/code/model/modelrender.h +++ b/code/model/modelrender.h @@ -256,6 +256,7 @@ class model_draw_list SCP_vector Render_keys; SCP_vector Arcs; + SCP_vector Insignias; SCP_vector Outlines; graphics::util::UniformBuffer _dataBuffer; @@ -288,6 +289,9 @@ class model_draw_list void add_arc(const vec3d *v1, const vec3d *v2, const SCP_vector *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); + void render_insignias(); + void add_outline(const vertex* vert_array, int n_verts, const color *clr); void render_outlines(); @@ -310,6 +314,7 @@ void submodel_render_queue(const model_render_params* render_info, model_draw_li 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 SCP_vector *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, const SCP_string& tcolor = ""); diff --git a/code/object/objectsort.cpp b/code/object/objectsort.cpp index f438936d6b6..0107c0de30e 100644 --- a/code/object/objectsort.cpp +++ b/code/object/objectsort.cpp @@ -388,6 +388,7 @@ void obj_render_queue_all() // render electricity effects and insignias scene.render_outlines(); + scene.render_insignias(); scene.render_arcs(); gr_zbuffer_set(ZBUFFER_TYPE_READ); From 84eb043678ed6ee2adde8d1a6d656f903d0be899 Mon Sep 17 00:00:00 2001 From: Birk Magnussen <6238428+BMagnu@users.noreply.github.com> Date: Thu, 22 Jan 2026 22:07:55 +0900 Subject: [PATCH 3/6] Revert "render insignias as decals" This reverts commit 24cdeb3c954f100dc8ef42b0361a44281dcbf75e. --- code/decals/decals.cpp | 177 ++++++++++++++++++------------------- code/decals/decals.h | 21 ----- code/math/vecmat.cpp | 13 --- code/math/vecmat.h | 4 - code/model/modelrender.cpp | 62 ++----------- 5 files changed, 91 insertions(+), 186 deletions(-) diff --git a/code/decals/decals.cpp b/code/decals/decals.cpp index 424c3807932..20d5a5c2da1 100644 --- a/code/decals/decals.cpp +++ b/code/decals/decals.cpp @@ -181,52 +181,66 @@ void parse_decals_table(const char* filename) { } } -Decal::Decal() { - vm_vec_make(&scale, 1.f, 1.f, 1.f); -} +struct Decal { + int definition_handle = -1; + object_h object; + int orig_obj_type = OBJ_NONE; + int submodel = -1; -bool Decal::isValid() const { - if (!object.isValid()) { - return false; - } - if (object.objp()->flags[Object::Object_Flags::Should_be_dead]) { - return false; - } + float creation_time = -1.0f; //!< The mission time at which this decal was created + float lifetime = -1.0f; //!< The time this decal is active. When negative it never expires - if (orig_obj_type != object.objp()->type) { - mprintf(("Decal object type for object %d has changed from %s to %s. Please let m!m know about this\n", - object.objnum, Object_type_names[orig_obj_type], Object_type_names[object.objp()->type])); - return false; + vec3d position = vmd_zero_vector; + vec3d scale; + matrix orientation = vmd_identity_matrix; + + Decal() { + vm_vec_make(&scale, 1.f, 1.f, 1.f); } - if (lifetime > 0.0f) { - if (f2fl(Missiontime) >= creation_time + lifetime) { - // Decal has expired + bool isValid() const { + if (!object.isValid()) { + return false; + } + if (object.objp()->flags[Object::Object_Flags::Should_be_dead]) { return false; } - } - auto objp = object.objp(); - if (objp->type == OBJ_SHIP) { - auto shipp = &Ships[objp->instance]; - auto model_instance = model_get_instance(shipp->model_instance_num); + if (orig_obj_type != object.objp()->type) { + mprintf(("Decal object type for object %d has changed from %s to %s. Please let m!m know about this\n", + object.objnum, Object_type_names[orig_obj_type], Object_type_names[object.objp()->type])); + return false; + } - Assertion(submodel >= 0 && submodel < object_get_model(objp)->n_models, - "Invalid submodel number detected!"); - auto smi = &model_instance->submodel[submodel]; + if (lifetime > 0.0f) { + if (f2fl(Missiontime) >= creation_time + lifetime) { + // Decal has expired + return false; + } + } + + auto objp = object.objp(); + if (objp->type == OBJ_SHIP) { + auto shipp = &Ships[objp->instance]; + auto model_instance = model_get_instance(shipp->model_instance_num); + + Assertion(submodel >= 0 && submodel < object_get_model(objp)->n_models, + "Invalid submodel number detected!"); + auto smi = &model_instance->submodel[submodel]; - if (smi->blown_off) { + if (smi->blown_off) { + return false; + } + } else { + Assertion(false, "Only ships are currently supported for decals!"); return false; } - } else { - Assertion(false, "Only ships are currently supported for decals!"); - return false; - } - return true; -} + return true; + } +}; -SCP_vector active_decals, active_single_frame_decals; +SCP_vector active_decals; bool required_string_if_new(const char* token, bool new_entry) { if (!new_entry) { @@ -360,7 +374,7 @@ void initializeMission() { const float DECAL_ANGLE_CUTOFF = fl_radians(45.f); const float DECAL_ANGLE_FADE_START = fl_radians(30.f); -static matrix4 getDecalTransform(const Decal& decal, float alpha) { +static matrix4 getDecalTransform(Decal& decal, float alpha) { Assertion(decal.object.objp()->type == OBJ_SHIP, "Only ships are currently supported for decals!"); auto objp = decal.object.objp(); @@ -404,51 +418,6 @@ static matrix4 getDecalTransform(const Decal& decal, float alpha) { return mat4; } -inline static void renderDecal(graphics::decal_draw_list& draw_list, const Decal& decal) { - auto mission_time = f2fl(Missiontime); - - int diffuse_bm = -1; - int glow_bm = -1; - int normal_bm = -1; - - auto decal_time = mission_time - decal.creation_time; - auto progress = decal_time / decal.lifetime; - - float alpha = 1.0f; - if (progress > 0.8) { - // Fade the decal out for the last 20% of its lifetime - alpha = 1.0f - smoothstep(0.8f, 1.0f, progress); - } - - if (std::holds_alternative(decal.definition_handle)) { - int definition_handle = std::get(decal.definition_handle); - Assertion(definition_handle >= 0 && definition_handle < (int) DecalDefinitions.size(), - "Invalid decal handle detected!"); - auto &decalDef = DecalDefinitions[definition_handle]; - - if (decalDef.getDiffuseBitmap() >= 0) { - diffuse_bm = decalDef.getDiffuseBitmap() - + - bm_get_anim_frame(decalDef.getDiffuseBitmap(), decal_time, 0.0f, decalDef.isDiffuseLooping()); - } - - if (decalDef.getGlowBitmap() >= 0) { - glow_bm = decalDef.getGlowBitmap() - + bm_get_anim_frame(decalDef.getGlowBitmap(), decal_time, 0.0f, decalDef.isGlowLooping()); - } - - if (decalDef.getNormalBitmap() >= 0) { - normal_bm = decalDef.getNormalBitmap() - + bm_get_anim_frame(decalDef.getNormalBitmap(), decal_time, 0.0f, decalDef.isNormalLooping()); - } - } - else { - std::tie(diffuse_bm, glow_bm, normal_bm) = std::get>(decal.definition_handle); - } - - draw_list.add_decal(diffuse_bm, glow_bm, normal_bm, decal_time, getDecalTransform(decal, alpha)); -} - void renderAll() { if (!Decal_system_active || !Decal_option_active || !gr_is_capable(gr_capability::CAPABILITY_INSTANCED_RENDERING)) { return; @@ -473,21 +442,51 @@ void renderAll() { ++iter; } - if (active_decals.empty() && active_single_frame_decals.empty()) { + if (active_decals.empty()) { return; } - + auto mission_time = f2fl(Missiontime); graphics::decal_draw_list draw_list; - for (auto& decal : active_decals) - renderDecal(draw_list, decal); - for (auto& decal : active_single_frame_decals) - renderDecal(draw_list, decal); + for (auto& decal : active_decals) { - draw_list.render(); + Assertion(decal.definition_handle >= 0 && decal.definition_handle < (int)DecalDefinitions.size(), + "Invalid decal handle detected!"); + auto& decalDef = DecalDefinitions[decal.definition_handle]; + + int diffuse_bm = -1; + int glow_bm = -1; + int normal_bm = -1; - active_single_frame_decals.clear(); + auto decal_time = mission_time - decal.creation_time; + auto progress = decal_time / decal.lifetime; + + float alpha = 1.0f; + if (progress > 0.8) { + // Fade the decal out for the last 20% of its lifetime + alpha = 1.0f - smoothstep(0.8f, 1.0f, progress); + } + + if (decalDef.getDiffuseBitmap() >= 0) { + diffuse_bm = decalDef.getDiffuseBitmap() + + bm_get_anim_frame(decalDef.getDiffuseBitmap(), decal_time, 0.0f, decalDef.isDiffuseLooping()); + } + + if (decalDef.getGlowBitmap() >= 0) { + glow_bm = decalDef.getGlowBitmap() + + bm_get_anim_frame(decalDef.getGlowBitmap(), decal_time, 0.0f, decalDef.isGlowLooping()); + } + + if (decalDef.getNormalBitmap() >= 0) { + normal_bm = decalDef.getNormalBitmap() + + bm_get_anim_frame(decalDef.getNormalBitmap(), decal_time, 0.0f, decalDef.isNormalLooping()); + } + + draw_list.add_decal(diffuse_bm, glow_bm, normal_bm, decal_time, getDecalTransform(decal, alpha)); + } + + draw_list.render(); } void addDecal(creation_info& info, const object* host, int submodel, const vec3d& local_pos, const matrix& local_orient) { @@ -532,8 +531,4 @@ void addDecal(creation_info& info, const object* host, int submodel, const vec3d active_decals.push_back(newDecal); } -void addSingleFrameDecal(Decal&& info) { - active_single_frame_decals.push_back(info); -} - } diff --git a/code/decals/decals.h b/code/decals/decals.h index 338a4fa14e4..a205b67c255 100644 --- a/code/decals/decals.h +++ b/code/decals/decals.h @@ -50,25 +50,6 @@ class DecalDefinition { bool isNormalLooping() const; }; -struct Decal { - //DecalDefinition idx vs immediate diffuse/glow/normal - std::variant> definition_handle = -1; - object_h object; - int orig_obj_type = OBJ_NONE; - int submodel = -1; - - float creation_time = -1.0f; //!< The mission time at which this decal was created - float lifetime = -1.0f; //!< The time this decal is active. When negative it never expires - - vec3d position = vmd_zero_vector; - vec3d scale; - matrix orientation = vmd_identity_matrix; - - Decal(); - - bool isValid() const; -}; - extern SCP_vector DecalDefinitions; extern bool Decal_system_active; extern bool Decal_option_active; @@ -158,6 +139,4 @@ void addDecal(creation_info& info, const vec3d& local_pos, const matrix& local_orient); -void addSingleFrameDecal(Decal&& info); - } diff --git a/code/math/vecmat.cpp b/code/math/vecmat.cpp index dc878e33f9a..3d0665b8c98 100644 --- a/code/math/vecmat.cpp +++ b/code/math/vecmat.cpp @@ -276,19 +276,6 @@ vec3d *vm_vec_avg_n(vec3d *dest, int n, const vec3d src[]) return dest; } -//Calculates the componentwise minimum of the two vectors -void vm_vec_min(vec3d* dest, const vec3d* src0, const vec3d* src1) { - dest->xyz.x = std::min(src0->xyz.x, src1->xyz.x); - dest->xyz.y = std::min(src0->xyz.y, src1->xyz.y); - dest->xyz.z = std::min(src0->xyz.z, src1->xyz.z); -} - -//Calculates the componentwise maximum of the two vectors -void vm_vec_max(vec3d* dest, const vec3d* src0, const vec3d* src1) { - dest->xyz.x = std::max(src0->xyz.x, src1->xyz.x); - dest->xyz.y = std::max(src0->xyz.y, src1->xyz.y); - dest->xyz.z = std::max(src0->xyz.z, src1->xyz.z); -} //averages two vectors. returns ptr to dest //dest can equal either source diff --git a/code/math/vecmat.h b/code/math/vecmat.h index f3fe9c2958b..a09533f92ba 100755 --- a/code/math/vecmat.h +++ b/code/math/vecmat.h @@ -145,11 +145,7 @@ void vm_vec_sub2(vec3d *dest, const vec3d *src); //averages n vectors vec3d *vm_vec_avg_n(vec3d *dest, int n, const vec3d src[]); -//Calculates the componentwise minimum of the two vectors -void vm_vec_min(vec3d* dest, const vec3d* src0, const vec3d* src1); -//Calculates the componentwise maximum of the two vectors -void vm_vec_max(vec3d* dest, const vec3d* src0, const vec3d* src1); //averages two vectors. returns ptr to dest //dest can equal either source vec3d *vm_vec_avg(vec3d *dest, const vec3d *src0, const vec3d *src1); diff --git a/code/model/modelrender.cpp b/code/model/modelrender.cpp index 730be2853b7..d120d238619 100644 --- a/code/model/modelrender.cpp +++ b/code/model/modelrender.cpp @@ -2977,64 +2977,12 @@ void model_render_queue(const model_render_params* interp, model_draw_list* scen } // MARKED! - if ( !( model_flags & MR_NO_TEXTURING ) && !( model_flags & MR_NO_INSIGNIA) && objnum >= 0 ) { - int bitmap_num = interp->get_insignia_bitmap(); - if ( (pm->num_ins > 0) && (bitmap_num >= 0) ) { + if ( !( model_flags & MR_NO_TEXTURING ) && !( model_flags & MR_NO_INSIGNIA) ) { + decals::creation_info decal { - for (int idx=0; idxnum_ins; idx++) { - // skip insignias not on our detail level - if (pm->ins[idx].detail_level != detail_level) { - continue; - } - - vec3d min {{{FLT_MAX, FLT_MAX, FLT_MAX}}}; - vec3d max {{{-FLT_MAX, -FLT_MAX, -FLT_MAX}}}; - vec3d avg_total = ZERO_VECTOR; - vec3d avg_normal = ZERO_VECTOR; - for(int s_idx=0; s_idxins[idx].num_faces; s_idx++) { - // get vertex indices - int i1 = pm->ins[idx].faces[s_idx][0]; - int i2 = pm->ins[idx].faces[s_idx][1]; - int i3 = pm->ins[idx].faces[s_idx][2]; - - const vec3d& v1 = pm->ins[idx].vecs[i1]; - const vec3d& v2 = pm->ins[idx].vecs[i2]; - const vec3d& v3 = pm->ins[idx].vecs[i3]; - - vm_vec_min(&min, &min, &v1); - vm_vec_min(&min, &min, &v2); - vm_vec_min(&min, &min, &v3); - vm_vec_max(&max, &max, &v1); - vm_vec_max(&max, &max, &v2); - vm_vec_max(&max, &max, &v3); - - // transform vecs and setup vertices - vec3d avg = (v1 + v2 + v3) * (1.0f / 3.0f); - avg_total += avg; - - const vec3d& u = v2 - v1; - const vec3d& v = v3 - v1; - avg_normal.xyz.x += u.xyz.y * v.xyz.z - u.xyz.z * v.xyz.y; - avg_normal.xyz.y += u.xyz.z * v.xyz.x - u.xyz.x * v.xyz.z; - avg_normal.xyz.z += u.xyz.x * v.xyz.y - u.xyz.y * v.xyz.x; - } - avg_total /= pm->ins[idx].num_faces; - vec3d bb = max - min; - float diameter = std::max({bb.xyz.x, bb.xyz.y, bb.xyz.z}); - - decals::Decal decal; - decal.object = &Objects[objnum]; - decal.position = avg_total + pm->ins[idx].offset; - decal.submodel = -1; - decal.scale = vec3d{{{diameter, diameter, diameter}}}; - decal.orig_obj_type = OBJ_SHIP; - decal.creation_time = f2fl(Missiontime); - decal.lifetime = 1.0f; - vm_vector_2_matrix(&decal.orientation, &avg_normal, &vmd_z_vector); - decal.definition_handle = std::make_tuple(bitmap_num, -1, -1); - decals::addSingleFrameDecal(std::move(decal)); - } - } + }; + decals::addDecal() + scene->add_insignia(interp, pm, detail_level, interp->get_insignia_bitmap()); } if ( (model_flags & MR_AUTOCENTER) && (set_autocen) ) { From 5b400acd85fdc12bdbbe6d947d7e1deef47937e4 Mon Sep 17 00:00:00 2001 From: Birk Magnussen <6238428+BMagnu@users.noreply.github.com> Date: Thu, 22 Jan 2026 22:10:34 +0900 Subject: [PATCH 4/6] Isolate reverts to insignias --- code/decals/decals.cpp | 177 ++++++++++++------------ code/decals/decals.h | 21 +++ code/def_files/data/effects/decal-v.sdr | 2 +- code/math/vecmat.cpp | 13 ++ code/math/vecmat.h | 4 + 5 files changed, 130 insertions(+), 87 deletions(-) diff --git a/code/decals/decals.cpp b/code/decals/decals.cpp index 20d5a5c2da1..424c3807932 100644 --- a/code/decals/decals.cpp +++ b/code/decals/decals.cpp @@ -181,66 +181,52 @@ void parse_decals_table(const char* filename) { } } -struct Decal { - int definition_handle = -1; - object_h object; - int orig_obj_type = OBJ_NONE; - int submodel = -1; - - float creation_time = -1.0f; //!< The mission time at which this decal was created - float lifetime = -1.0f; //!< The time this decal is active. When negative it never expires - - vec3d position = vmd_zero_vector; - vec3d scale; - matrix orientation = vmd_identity_matrix; +Decal::Decal() { + vm_vec_make(&scale, 1.f, 1.f, 1.f); +} - Decal() { - vm_vec_make(&scale, 1.f, 1.f, 1.f); +bool Decal::isValid() const { + if (!object.isValid()) { + return false; + } + if (object.objp()->flags[Object::Object_Flags::Should_be_dead]) { + return false; } - bool isValid() const { - if (!object.isValid()) { - return false; - } - if (object.objp()->flags[Object::Object_Flags::Should_be_dead]) { - return false; - } + if (orig_obj_type != object.objp()->type) { + mprintf(("Decal object type for object %d has changed from %s to %s. Please let m!m know about this\n", + object.objnum, Object_type_names[orig_obj_type], Object_type_names[object.objp()->type])); + return false; + } - if (orig_obj_type != object.objp()->type) { - mprintf(("Decal object type for object %d has changed from %s to %s. Please let m!m know about this\n", - object.objnum, Object_type_names[orig_obj_type], Object_type_names[object.objp()->type])); + if (lifetime > 0.0f) { + if (f2fl(Missiontime) >= creation_time + lifetime) { + // Decal has expired return false; } + } - if (lifetime > 0.0f) { - if (f2fl(Missiontime) >= creation_time + lifetime) { - // Decal has expired - return false; - } - } - - auto objp = object.objp(); - if (objp->type == OBJ_SHIP) { - auto shipp = &Ships[objp->instance]; - auto model_instance = model_get_instance(shipp->model_instance_num); + auto objp = object.objp(); + if (objp->type == OBJ_SHIP) { + auto shipp = &Ships[objp->instance]; + auto model_instance = model_get_instance(shipp->model_instance_num); - Assertion(submodel >= 0 && submodel < object_get_model(objp)->n_models, - "Invalid submodel number detected!"); - auto smi = &model_instance->submodel[submodel]; + Assertion(submodel >= 0 && submodel < object_get_model(objp)->n_models, + "Invalid submodel number detected!"); + auto smi = &model_instance->submodel[submodel]; - if (smi->blown_off) { - return false; - } - } else { - Assertion(false, "Only ships are currently supported for decals!"); + if (smi->blown_off) { return false; } - - return true; + } else { + Assertion(false, "Only ships are currently supported for decals!"); + return false; } -}; -SCP_vector active_decals; + return true; +} + +SCP_vector active_decals, active_single_frame_decals; bool required_string_if_new(const char* token, bool new_entry) { if (!new_entry) { @@ -374,7 +360,7 @@ void initializeMission() { const float DECAL_ANGLE_CUTOFF = fl_radians(45.f); const float DECAL_ANGLE_FADE_START = fl_radians(30.f); -static matrix4 getDecalTransform(Decal& decal, float alpha) { +static matrix4 getDecalTransform(const Decal& decal, float alpha) { Assertion(decal.object.objp()->type == OBJ_SHIP, "Only ships are currently supported for decals!"); auto objp = decal.object.objp(); @@ -418,6 +404,51 @@ static matrix4 getDecalTransform(Decal& decal, float alpha) { return mat4; } +inline static void renderDecal(graphics::decal_draw_list& draw_list, const Decal& decal) { + auto mission_time = f2fl(Missiontime); + + int diffuse_bm = -1; + int glow_bm = -1; + int normal_bm = -1; + + auto decal_time = mission_time - decal.creation_time; + auto progress = decal_time / decal.lifetime; + + float alpha = 1.0f; + if (progress > 0.8) { + // Fade the decal out for the last 20% of its lifetime + alpha = 1.0f - smoothstep(0.8f, 1.0f, progress); + } + + if (std::holds_alternative(decal.definition_handle)) { + int definition_handle = std::get(decal.definition_handle); + Assertion(definition_handle >= 0 && definition_handle < (int) DecalDefinitions.size(), + "Invalid decal handle detected!"); + auto &decalDef = DecalDefinitions[definition_handle]; + + if (decalDef.getDiffuseBitmap() >= 0) { + diffuse_bm = decalDef.getDiffuseBitmap() + + + bm_get_anim_frame(decalDef.getDiffuseBitmap(), decal_time, 0.0f, decalDef.isDiffuseLooping()); + } + + if (decalDef.getGlowBitmap() >= 0) { + glow_bm = decalDef.getGlowBitmap() + + bm_get_anim_frame(decalDef.getGlowBitmap(), decal_time, 0.0f, decalDef.isGlowLooping()); + } + + if (decalDef.getNormalBitmap() >= 0) { + normal_bm = decalDef.getNormalBitmap() + + bm_get_anim_frame(decalDef.getNormalBitmap(), decal_time, 0.0f, decalDef.isNormalLooping()); + } + } + else { + std::tie(diffuse_bm, glow_bm, normal_bm) = std::get>(decal.definition_handle); + } + + draw_list.add_decal(diffuse_bm, glow_bm, normal_bm, decal_time, getDecalTransform(decal, alpha)); +} + void renderAll() { if (!Decal_system_active || !Decal_option_active || !gr_is_capable(gr_capability::CAPABILITY_INSTANCED_RENDERING)) { return; @@ -442,51 +473,21 @@ void renderAll() { ++iter; } - if (active_decals.empty()) { + if (active_decals.empty() && active_single_frame_decals.empty()) { return; } - auto mission_time = f2fl(Missiontime); - - graphics::decal_draw_list draw_list; - for (auto& decal : active_decals) { - - Assertion(decal.definition_handle >= 0 && decal.definition_handle < (int)DecalDefinitions.size(), - "Invalid decal handle detected!"); - auto& decalDef = DecalDefinitions[decal.definition_handle]; - int diffuse_bm = -1; - int glow_bm = -1; - int normal_bm = -1; - auto decal_time = mission_time - decal.creation_time; - auto progress = decal_time / decal.lifetime; - - float alpha = 1.0f; - if (progress > 0.8) { - // Fade the decal out for the last 20% of its lifetime - alpha = 1.0f - smoothstep(0.8f, 1.0f, progress); - } - - if (decalDef.getDiffuseBitmap() >= 0) { - diffuse_bm = decalDef.getDiffuseBitmap() - + bm_get_anim_frame(decalDef.getDiffuseBitmap(), decal_time, 0.0f, decalDef.isDiffuseLooping()); - } - - if (decalDef.getGlowBitmap() >= 0) { - glow_bm = decalDef.getGlowBitmap() - + bm_get_anim_frame(decalDef.getGlowBitmap(), decal_time, 0.0f, decalDef.isGlowLooping()); - } - - if (decalDef.getNormalBitmap() >= 0) { - normal_bm = decalDef.getNormalBitmap() - + bm_get_anim_frame(decalDef.getNormalBitmap(), decal_time, 0.0f, decalDef.isNormalLooping()); - } - - draw_list.add_decal(diffuse_bm, glow_bm, normal_bm, decal_time, getDecalTransform(decal, alpha)); - } + graphics::decal_draw_list draw_list; + for (auto& decal : active_decals) + renderDecal(draw_list, decal); + for (auto& decal : active_single_frame_decals) + renderDecal(draw_list, decal); draw_list.render(); + + active_single_frame_decals.clear(); } void addDecal(creation_info& info, const object* host, int submodel, const vec3d& local_pos, const matrix& local_orient) { @@ -531,4 +532,8 @@ void addDecal(creation_info& info, const object* host, int submodel, const vec3d active_decals.push_back(newDecal); } +void addSingleFrameDecal(Decal&& info) { + active_single_frame_decals.push_back(info); +} + } diff --git a/code/decals/decals.h b/code/decals/decals.h index a205b67c255..338a4fa14e4 100644 --- a/code/decals/decals.h +++ b/code/decals/decals.h @@ -50,6 +50,25 @@ class DecalDefinition { bool isNormalLooping() const; }; +struct Decal { + //DecalDefinition idx vs immediate diffuse/glow/normal + std::variant> definition_handle = -1; + object_h object; + int orig_obj_type = OBJ_NONE; + int submodel = -1; + + float creation_time = -1.0f; //!< The mission time at which this decal was created + float lifetime = -1.0f; //!< The time this decal is active. When negative it never expires + + vec3d position = vmd_zero_vector; + vec3d scale; + matrix orientation = vmd_identity_matrix; + + Decal(); + + bool isValid() const; +}; + extern SCP_vector DecalDefinitions; extern bool Decal_system_active; extern bool Decal_option_active; @@ -139,4 +158,6 @@ void addDecal(creation_info& info, const vec3d& local_pos, const matrix& local_orient); +void addSingleFrameDecal(Decal&& info); + } diff --git a/code/def_files/data/effects/decal-v.sdr b/code/def_files/data/effects/decal-v.sdr index d90bddb7aa3..bd3511e0c7e 100644 --- a/code/def_files/data/effects/decal-v.sdr +++ b/code/def_files/data/effects/decal-v.sdr @@ -37,6 +37,6 @@ void main() { modelMatrix[2][3] = 0.0; invModelMatrix = inverse(modelMatrix); - decalDirection = mat3(viewMatrix) * vec3(modelMatrix[2][0], modelMatrix[2][1], modelMatrix[2][2]); + decalDirection = mat3(viewMatrix) * modelMatrix[2].xyz; gl_Position = projMatrix * viewMatrix * modelMatrix * vertPosition; } diff --git a/code/math/vecmat.cpp b/code/math/vecmat.cpp index 3d0665b8c98..dc878e33f9a 100644 --- a/code/math/vecmat.cpp +++ b/code/math/vecmat.cpp @@ -276,6 +276,19 @@ vec3d *vm_vec_avg_n(vec3d *dest, int n, const vec3d src[]) return dest; } +//Calculates the componentwise minimum of the two vectors +void vm_vec_min(vec3d* dest, const vec3d* src0, const vec3d* src1) { + dest->xyz.x = std::min(src0->xyz.x, src1->xyz.x); + dest->xyz.y = std::min(src0->xyz.y, src1->xyz.y); + dest->xyz.z = std::min(src0->xyz.z, src1->xyz.z); +} + +//Calculates the componentwise maximum of the two vectors +void vm_vec_max(vec3d* dest, const vec3d* src0, const vec3d* src1) { + dest->xyz.x = std::max(src0->xyz.x, src1->xyz.x); + dest->xyz.y = std::max(src0->xyz.y, src1->xyz.y); + dest->xyz.z = std::max(src0->xyz.z, src1->xyz.z); +} //averages two vectors. returns ptr to dest //dest can equal either source diff --git a/code/math/vecmat.h b/code/math/vecmat.h index a09533f92ba..f3fe9c2958b 100755 --- a/code/math/vecmat.h +++ b/code/math/vecmat.h @@ -145,7 +145,11 @@ void vm_vec_sub2(vec3d *dest, const vec3d *src); //averages n vectors vec3d *vm_vec_avg_n(vec3d *dest, int n, const vec3d src[]); +//Calculates the componentwise minimum of the two vectors +void vm_vec_min(vec3d* dest, const vec3d* src0, const vec3d* src1); +//Calculates the componentwise maximum of the two vectors +void vm_vec_max(vec3d* dest, const vec3d* src0, const vec3d* src1); //averages two vectors. returns ptr to dest //dest can equal either source vec3d *vm_vec_avg(vec3d *dest, const vec3d *src0, const vec3d *src1); From 4052a2df0db8a4b5687bbea8658124841a4d3305 Mon Sep 17 00:00:00 2001 From: Birk Magnussen <6238428+BMagnu@users.noreply.github.com> Date: Thu, 22 Jan 2026 22:22:51 +0900 Subject: [PATCH 5/6] Fix oversight --- code/model/modelrender.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/code/model/modelrender.cpp b/code/model/modelrender.cpp index d120d238619..303bec0c266 100644 --- a/code/model/modelrender.cpp +++ b/code/model/modelrender.cpp @@ -2978,10 +2978,6 @@ void model_render_queue(const model_render_params* interp, model_draw_list* scen // MARKED! if ( !( model_flags & MR_NO_TEXTURING ) && !( model_flags & MR_NO_INSIGNIA) ) { - decals::creation_info decal { - - }; - decals::addDecal() scene->add_insignia(interp, pm, detail_level, interp->get_insignia_bitmap()); } From 78afbd4fb68af5ddd1cd70fa95a091f302fccb46 Mon Sep 17 00:00:00 2001 From: Birk Magnussen <6238428+BMagnu@users.noreply.github.com> Date: Thu, 22 Jan 2026 23:18:36 +0900 Subject: [PATCH 6/6] clang tidy --- code/model/modelrender.cpp | 6 +++--- code/model/modelrender.h | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/code/model/modelrender.cpp b/code/model/modelrender.cpp index 303bec0c266..842c86d135e 100644 --- a/code/model/modelrender.cpp +++ b/code/model/modelrender.cpp @@ -679,10 +679,10 @@ void model_draw_list::render_insignia(const insignia_draw_data &insignia_info) g3_done_instance(true); } -void model_draw_list::render_insignias() +void model_draw_list::render_insignias() const { - for ( size_t i = 0; i < Insignias.size(); ++i ) { - render_insignia(Insignias[i]); + for (const auto& ins : Insignias) { + render_insignia(ins); } } diff --git a/code/model/modelrender.h b/code/model/modelrender.h index 3758da24189..6914074bfe4 100644 --- a/code/model/modelrender.h +++ b/code/model/modelrender.h @@ -248,7 +248,7 @@ class model_draw_list light_indexing_info Current_lights_set; void render_arc(const arc_effect &arc); - void render_insignia(const insignia_draw_data &insignia_info); + static void render_insignia(const insignia_draw_data &insignia_info); void render_outline(const outline_draw &outline_info); void render_buffer(const queued_buffer_draw &render_elements); @@ -290,7 +290,7 @@ class model_draw_list void render_arcs(); void add_insignia(const model_render_params *params, const polymodel *pm, int detail_level, int bitmap_num); - void render_insignias(); + void render_insignias() const; void add_outline(const vertex* vert_array, int n_verts, const color *clr); void render_outlines();