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..842c86d135e 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() const +{ + for (const auto& ins : Insignias) { + render_insignia(ins); + } +} + 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); @@ -2863,29 +2977,8 @@ 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) ) { - - for (const auto& ins : pm->ins) { - // skip insignias not on our detail level - if (ins.detail_level != detail_level) { - continue; - } - - decals::Decal decal; - decal.object = &Objects[objnum]; - decal.position = ins.position; - decal.submodel = -1; - decal.scale = vec3d{{{ins.diameter, ins.diameter, ins.diameter}}}; - decal.orig_obj_type = OBJ_SHIP; - decal.creation_time = f2fl(Missiontime); - decal.lifetime = 1.0f; - decal.orientation = ins.orientation; - decal.definition_handle = std::make_tuple(bitmap_num, -1, -1); - decals::addSingleFrameDecal(std::move(decal)); - } - } + if ( !( model_flags & MR_NO_TEXTURING ) && !( model_flags & MR_NO_INSIGNIA) ) { + scene->add_insignia(interp, pm, detail_level, interp->get_insignia_bitmap()); } if ( (model_flags & MR_AUTOCENTER) && (set_autocen) ) { diff --git a/code/model/modelrender.h b/code/model/modelrender.h index c516eb7ba0a..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); @@ -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() const; + 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);