Fix virtual POF crashes (#7327)

* Ensure model data isn't deleted twice

* shared_ptr-ify model data

* fix virtual pof filename issue

* Fix tests

* remove redundant memsets

* Clang Tid
This commit is contained in:
BMagnu authored and GitHub committed 2026-03-31 10:02:24 -04:00
1 parent 7361417050
commit 1f5525e04f
12 files changed
+166 -277

No files matched your search

+6 -8
View File
@@ -13705,7 +13705,7 @@ int ai_acquire_emerge_path(object *pl_objp, int parent_objnum, int allowed_path_
ship_info* parent_sip = &Ship_info[parent_shipp->ship_info_index];
polymodel *pm = model_get( parent_sip->model_num );
ship_bay *bay = pm->ship_bay;
const auto& bay = pm->ship_bay;
if ( bay == nullptr ) {
Warning(LOCATION, "Ship %s was set to arrive from fighter bay on object %s, but no fighter bay exists on that ships' model (%s).\n", shipp->ship_name, parent_shipp->ship_name, pm->filename);
@@ -13920,9 +13920,8 @@ int ai_find_closest_depart_path(ai_info *aip, polymodel *pm, int allowed_path_ma
float dist, min_dist, min_free_dist;
vec3d *source;
model_path *mp;
ship_bay *bay;
bay = pm->ship_bay;
const auto& bay = pm->ship_bay;
best_free_path = best_path = -1;
min_free_dist = min_dist = 1e20f;
@@ -13999,9 +13998,9 @@ int ai_acquire_depart_path(object *pl_objp, int parent_objnum, int allowed_path_
object *parent_objp = &Objects[parent_objnum];
polymodel *pm = model_get(Ship_info[Ships[parent_objp->instance].ship_info_index].model_num );
ship_bay *bay = pm->ship_bay;
const auto& bay = pm->ship_bay;
if ( bay == NULL )
if ( bay == nullptr )
return -1;
if ( bay->num_paths <= 0 )
return -1;
@@ -14092,11 +14091,10 @@ void ai_bay_depart()
// Volition bay code
polymodel *pm;
ship_bay *bay;
pm = model_get(Ship_info[Ships[Objects[aip->goal_objnum].instance].ship_info_index].model_num);
bay = pm->ship_bay;
if ( bay != NULL ) {
const auto& bay = pm->ship_bay;
if ( bay != nullptr ) {
bay->depart_flags &= ~(1<<aip->submode_parm0);
}
+24
View File
@@ -46,6 +46,30 @@ struct is_dereferenceable_pointer<T, typename std::enable_if_t<std::is_pointer_v
template<typename T>
inline constexpr bool is_dereferenceable_pointer_v = is_dereferenceable_pointer<T>::value;
template<typename T, typename Enable = void>
struct is_smart_pointer : std::false_type {};
template<typename T>
struct is_smart_pointer<T, std::enable_if_t<std::is_same_v<std::remove_cv_t<T>, std::shared_ptr<typename T::element_type>>>> : std::true_type {};
template<typename T>
struct is_smart_pointer<T, std::enable_if_t<std::is_same_v<std::remove_cv_t<T>, std::shared_ptr<typename T::element_type[]>>>> : std::true_type {};
template<typename T>
struct is_smart_pointer<T, std::enable_if_t<std::is_same_v<std::remove_cv_t<T>, std::unique_ptr<typename T::element_type>>>> : std::true_type {};
template<typename T>
struct is_smart_pointer<T, std::enable_if_t<std::is_same_v<std::remove_cv_t<T>, std::unique_ptr<typename T::element_type[]>>>> : std::true_type {};
template<typename T>
struct is_smart_pointer<T, std::enable_if_t<std::is_same_v<std::remove_cv_t<T>, std::weak_ptr<typename T::element_type>>>> : std::true_type {};
template<typename T>
struct is_smart_pointer<T, std::enable_if_t<std::is_same_v<std::remove_cv_t<T>, std::weak_ptr<typename T::element_type[]>>>> : std::true_type {};
template<typename T>
inline constexpr bool is_smart_pointer_v = is_smart_pointer<T>::value;
template<class T, template<class...> class U>
inline constexpr bool is_instance_of_v = std::false_type{};
+2 -3
View File
@@ -615,9 +615,8 @@ public:
};
struct indexed_vertex_source {
void* Vertex_list = nullptr;
void* Index_list = nullptr;
std::shared_ptr<uint8_t[]> Vertex_list = nullptr;
std::shared_ptr<uint8_t[]> Index_list = nullptr;
gr_buffer_handle Vbuffer_handle;
size_t Vertex_offset = 0;
size_t Base_vertex_offset = 0;
+23 -23
View File
@@ -453,7 +453,7 @@ public:
matrix frame_of_reference; // used to be called 'orientation' - this is just used for setting the rotation axis and the animation angles
int bsp_data_size;
ubyte *bsp_data;
std::shared_ptr<ubyte[]> bsp_data;
int collision_tree_index;
@@ -485,7 +485,7 @@ public:
vertex_buffer buffer;
vertex_buffer trans_buffer;
vertex *outline_buffer;
std::shared_ptr<vertex[]> outline_buffer;
uint n_verts_outline;
vec3d render_box_min;
@@ -508,7 +508,7 @@ public:
typedef struct mp_vert {
vec3d pos; // xyz coordinates of vertex in object's frame of reference
int nturrets; // number of turrets guarding this vertex
int *turret_ids; // array of indices into ship_subsys linked list (can't index using [] though)
std::shared_ptr<int[]> turret_ids; // array of indices into ship_subsys linked list (can't index using [] though)
float radius; // How far the closest obstruction is from this vertex
} mp_vert;
@@ -517,7 +517,7 @@ typedef struct model_path {
char parent_name[MAX_NAME_LEN]; // parent name of submodel that path is linked to in POF
int parent_submodel;
int nverts;
mp_vert *verts;
std::shared_ptr<mp_vert[]> verts;
int goal; // Which of the verts is the one closest to the goal of this path
int type; // What this path takes you to... See MP_TYPE_??? defines above for details
int value; // This depends on the type.
@@ -567,7 +567,7 @@ struct glow_point{
typedef struct thruster_bank {
int num_points;
glow_point *points;
std::shared_ptr<glow_point[]> points;
// Engine wash info
struct engine_wash_info *wash_info_pointer; // index into Engine_wash_info
@@ -590,7 +590,7 @@ typedef struct glow_point_bank { // glow bank structure -Bobboau
int submodel_parent;
int LOD;
int num_points;
glow_point *points;
std::shared_ptr<glow_point[]> points;
int glow_bitmap;
int glow_neb_bitmap;
} glow_point_bank;
@@ -650,7 +650,7 @@ typedef struct dock_bay {
int num_slots;
int type_flags; // indicates what this docking bay can be used for (i.e. cargo/rearm, etc)
int num_spline_paths; // number of spline paths which lead to this docking bay
int *splines; // array of indices into the Spline_path array
std::shared_ptr<int[]> splines; // array of indices into the Spline_path array
int parent_submodel; // if this dockpoint should be relative to a submodel instead of the main model
char name[MAX_NAME_LEN]; // name of this docking location
vec3d pnt[MAX_DOCK_SLOTS];
@@ -692,14 +692,14 @@ typedef struct shield_vertex {
struct shield_info {
int nverts;
int ntris;
shield_vertex *verts;
shield_tri *tris;
std::shared_ptr<shield_vertex[]> verts;
std::shared_ptr<shield_tri[]> tris;
gr_buffer_handle buffer_id;
std::shared_ptr<gr_buffer_handle> buffer_id;
int buffer_n_verts;
vertex_layout layout;
shield_info() : nverts(0), ntris(0), verts(NULL), tris(NULL), buffer_id(-1), buffer_n_verts(0), layout() { }
shield_info() : nverts(0), ntris(0), verts(nullptr), tris(nullptr), buffer_id(std::make_shared<gr_buffer_handle>(gr_buffer_handle::invalid())), buffer_n_verts(0) { }
};
#define BSP_LIGHT_TYPE_WEAPON 1
@@ -852,7 +852,7 @@ public:
vec3d bounding_box[8];
int num_lights; // how many lights there are
bsp_light * lights; // array of light info
std::shared_ptr<bsp_light[]> lights; // array of light info
int n_view_positions; // number of viewing positions available on this ship
eye view_positions[MAX_EYES]; //viewing positions. Default to {0,0,0}. in location 0
@@ -866,7 +866,7 @@ public:
int n_textures;
texture_map maps[MAX_MODEL_TEXTURES];
bsp_info *submodel; // an array of size n_models of submodel info.
std::shared_ptr<bsp_info[]> submodel; // an array of size n_models of submodel info.
// linked lists for special polygon types on this model. Most ships I think will have most
// of these. (most ships however, probably won't have approach points).
@@ -874,19 +874,19 @@ public:
int n_missiles; // number of secondary weapon banks (not counting turrets)
int n_docks; // number of docking points
int n_thrusters; // number of thrusters on this ship.
w_bank *gun_banks; // array of gun banks
w_bank *missile_banks; // array of missile banks
dock_bay *docking_bays; // array of docking point pairs
thruster_bank *thrusters; // array of thruster objects -- likely to change in the future
ship_bay_t *ship_bay; // contains path indexes for ship bay approach/depart paths
std::shared_ptr<w_bank[]> gun_banks; // array of gun banks
std::shared_ptr<w_bank[]> missile_banks; // array of missile banks
std::shared_ptr<dock_bay[]> docking_bays; // array of docking point pairs
std::shared_ptr<thruster_bank[]> thrusters; // array of thruster objects -- likely to change in the future
std::shared_ptr<ship_bay_t> ship_bay; // contains path indexes for ship bay approach/depart paths
shield_info shield; // new shield information
ubyte *shield_collision_tree;
std::shared_ptr<ubyte[]> shield_collision_tree;
int sldc_size;
SCP_vector<vec3d> shield_points;
int n_paths;
model_path *paths;
std::shared_ptr<model_path[]> paths;
// physics info
float mass;
@@ -894,7 +894,7 @@ public:
matrix moment_of_inertia;
int num_xc; // number of cross sections
cross_section* xc; // pointer to array of cross sections (used in big ship explosions)
std::shared_ptr<cross_section[]> xc; // pointer to array of cross sections (used in big ship explosions)
int num_split_plane; // number of split planes
float split_plane[MAX_SPLIT_PLANE]; // actual split plane z coords (for big ship explosions)
@@ -905,13 +905,13 @@ public:
#ifndef NDEBUG
int ram_used; // How much RAM this model uses
int debug_info_size;
char *debug_info;
std::shared_ptr<char[]> debug_info;
#endif
int used_this_mission; // used for page-in system, how many times this model has been loaded per mission - taylor
int n_glow_point_banks; // number of glow points on this ship. -Bobboau
glow_point_bank *glow_point_banks; // array of glow objects -Bobboau
std::shared_ptr<glow_point_bank[]> glow_point_banks; // array of glow objects -Bobboau
indexed_vertex_source vert_source;
+9 -9
View File
@@ -859,7 +859,7 @@ bool mc_shield_check_common(shield_tri *tri)
// also finds the uv's where the ray hit.
if ( fvi_point_face(&hitpoint, 3, points, &tri->norm, NULL,NULL,NULL ) ) {
Mc->hit_dist = dist;
Mc->shield_hit_tri = (int)(tri - Mc_pm->shield.tris);
Mc->shield_hit_tri = (int)(tri - Mc_pm->shield.tris.get());
Mc->hit_point = hitpoint;
Mc->hit_normal = tri->norm;
Mc->hit_submodel = -1;
@@ -877,7 +877,7 @@ bool mc_shield_check_common(shield_tri *tri)
// same behavior whether face or edge
// normal, edge_hit, hit_point all updated thru sphereline_face
sphere_check_closest_shield_dist = Mc->hit_dist;
Mc->shield_hit_tri = (int)(tri - Mc_pm->shield.tris);
Mc->shield_hit_tri = (int)(tri - Mc_pm->shield.tris.get());
Mc->hit_submodel = -1;
Mc->num_hits++;
return true; // We hit, so we're done
@@ -893,22 +893,22 @@ bool mc_check_sldc(int offset)
if (offset > Mc_pm->sldc_size - 5) //no way is this big enough
return false;
int* type_p = (int*)(Mc_pm->shield_collision_tree + offset);
int* type_p = (int*)(Mc_pm->shield_collision_tree.get() + offset);
// not used
//int *size_p = (int *)(Mc_pm->shield_collision_tree+offset+4);
// split and polygons
auto* minbox_p = (vec3d*)(Mc_pm->shield_collision_tree + offset + 8);
auto* maxbox_p = (vec3d*)(Mc_pm->shield_collision_tree + offset + 20);
auto* minbox_p = (vec3d*)(Mc_pm->shield_collision_tree.get() + offset + 8);
auto* maxbox_p = (vec3d*)(Mc_pm->shield_collision_tree.get() + offset + 20);
// split
auto* front_offset_p = (unsigned int*)(Mc_pm->shield_collision_tree + offset + 32);
auto* back_offset_p = (unsigned int*)(Mc_pm->shield_collision_tree + offset + 36);
auto* front_offset_p = (unsigned int*)(Mc_pm->shield_collision_tree.get() + offset + 32);
auto* back_offset_p = (unsigned int*)(Mc_pm->shield_collision_tree.get() + offset + 36);
// polygons
auto* num_polygons_p = (unsigned int*)(Mc_pm->shield_collision_tree + offset + 32);
auto* num_polygons_p = (unsigned int*)(Mc_pm->shield_collision_tree.get() + offset + 32);
auto* shld_polys = (unsigned int*)(Mc_pm->shield_collision_tree + offset + 36);
auto* shld_polys = (unsigned int*)(Mc_pm->shield_collision_tree.get() + offset + 36);
+27 -31
View File
@@ -1275,7 +1275,7 @@ int submodel_get_num_polys(int model_num, int submodel_num )
pm = model_get(model_num);
return submodel_get_num_polys_sub( pm->submodel[submodel_num].bsp_data );
return submodel_get_num_polys_sub( pm->submodel[submodel_num].bsp_data.get() );
}
/**
@@ -1876,9 +1876,9 @@ void model_interp_submit_buffers(indexed_vertex_source *vert_src, size_t vertex_
return;
}
if ( vert_src->Vertex_list != NULL ) {
if ( vert_src->Vertex_list != nullptr ) {
size_t offset;
gr_heap_allocate(GpuHeap::ModelVertex, vert_src->Vertex_list_size, vert_src->Vertex_list, offset, vert_src->Vbuffer_handle);
gr_heap_allocate(GpuHeap::ModelVertex, vert_src->Vertex_list_size, vert_src->Vertex_list.get(), offset, vert_src->Vbuffer_handle);
// If this happens then someone must have allocated something from the heap with a different stride than what we
// are using.
@@ -1886,15 +1886,13 @@ void model_interp_submit_buffers(indexed_vertex_source *vert_src, size_t vertex_
vert_src->Base_vertex_offset = offset / vertex_stride;
vert_src->Vertex_offset = offset;
vm_free(vert_src->Vertex_list);
vert_src->Vertex_list = NULL;
vert_src->Vertex_list.reset();
}
if ( vert_src->Index_list != NULL ) {
gr_heap_allocate(GpuHeap::ModelIndex, vert_src->Index_list_size, vert_src->Index_list, vert_src->Index_offset, vert_src->Ibuffer_handle);
if ( vert_src->Index_list != nullptr ) {
gr_heap_allocate(GpuHeap::ModelIndex, vert_src->Index_list_size, vert_src->Index_list.get(), vert_src->Index_offset, vert_src->Ibuffer_handle);
vm_free(vert_src->Index_list);
vert_src->Index_list = NULL;
vert_src->Index_list.reset();
}
}
@@ -1908,30 +1906,26 @@ bool model_interp_pack_buffer(indexed_vertex_source *vert_src, vertex_buffer *vb
int i, n_verts = 0;
size_t j;
if ( vert_src->Vertex_list == NULL ) {
vert_src->Vertex_list = vm_malloc(vert_src->Vertex_list_size);
if ( vert_src->Vertex_list == nullptr ) {
vert_src->Vertex_list = make_shared<uint8_t[]>(vert_src->Vertex_list_size);
// return invalid if we don't have the memory
if ( vert_src->Vertex_list == NULL ) {
if ( vert_src->Vertex_list == nullptr ) {
return false;
}
memset(vert_src->Vertex_list, 0, vert_src->Vertex_list_size);
}
if ( vert_src->Index_list == NULL ) {
vert_src->Index_list = vm_malloc(vert_src->Index_list_size);
if ( vert_src->Index_list == nullptr ) {
vert_src->Index_list = make_shared<uint8_t[]>(vert_src->Index_list_size);
// return invalid if we don't have the memory
if ( vert_src->Index_list == NULL ) {
if ( vert_src->Index_list == nullptr ) {
return false;
}
memset(vert_src->Index_list, 0, vert_src->Index_list_size);
}
// bump to our index in the array
auto array = reinterpret_cast<interp_vertex*>(static_cast<uint8_t*>(vert_src->Vertex_list) + (vb->vertex_offset));
auto array = reinterpret_cast<interp_vertex*>(vert_src->Vertex_list.get() + vb->vertex_offset);
// generate the vertex array
n_verts = vb->model_list->n_verts;
@@ -1997,7 +1991,7 @@ bool model_interp_pack_buffer(indexed_vertex_source *vert_src, vertex_buffer *vb
const uint *index = tex_buf->get_index();
// bump to our spot in the buffer
auto ibuf = static_cast<uint8_t*>(vert_src->Index_list) + offset;
auto ibuf = vert_src->Index_list.get() + offset;
if ( vb->tex_buf[j].flags & VB_FLAG_LARGE_INDEX ) {
memcpy(ibuf, index, n_verts * sizeof(uint));
@@ -2109,7 +2103,7 @@ void interp_configure_vertex_buffers(polymodel *pm, int mn, const model_read_def
int milliseconds = timer_get_milliseconds();
auto bsp_polies = new bsp_polygon_data(model->bsp_data, model->bsp_data_size);
auto bsp_polies = new bsp_polygon_data(model->bsp_data.get(), model->bsp_data_size);
auto textureReplace = deferredTasks.texture_replacements.find(mn);
if (textureReplace != deferredTasks.texture_replacements.end())
@@ -2141,9 +2135,9 @@ void interp_configure_vertex_buffers(polymodel *pm, int mn, const model_read_def
if ( outline_n_lines > 0 ) {
model->n_verts_outline = outline_n_lines * 2;
model->outline_buffer = (vertex*)vm_malloc(sizeof(vertex) * model->n_verts_outline);
model->outline_buffer = make_shared<vertex[]>(model->n_verts_outline);
bsp_polies->generate_lines(-1, model->outline_buffer);
bsp_polies->generate_lines(-1, model->outline_buffer.get());
}
// done with the bsp now that we have the vertex data
@@ -2516,14 +2510,16 @@ void model_interp_process_shield_mesh(polymodel * pm)
}
if ( !buffer.empty() ) {
pm->shield.buffer_id = gr_create_buffer(BufferType::Vertex, BufferUsageHint::Static);
pm->shield.buffer_n_verts = n_verts;
gr_update_buffer_data(pm->shield.buffer_id, buffer.size() * sizeof(vec3d), &buffer[0]);
if (*pm->shield.buffer_id == gr_buffer_handle::invalid()) {
*pm->shield.buffer_id = gr_create_buffer(BufferType::Vertex, BufferUsageHint::Static);
pm->shield.buffer_n_verts = n_verts;
gr_update_buffer_data(*pm->shield.buffer_id, buffer.size() * sizeof(vec3d), buffer.data());
pm->shield.layout.add_vertex_component(vertex_format_data::POSITION3, sizeof(vec3d) * 2, 0);
pm->shield.layout.add_vertex_component(vertex_format_data::NORMAL, sizeof(vec3d) * 2, sizeof(vec3d));
pm->shield.layout.add_vertex_component(vertex_format_data::POSITION3, sizeof(vec3d) * 2, 0);
pm->shield.layout.add_vertex_component(vertex_format_data::NORMAL, sizeof(vec3d) * 2, sizeof(vec3d));
}
} else {
pm->shield.buffer_id = gr_buffer_handle::invalid();
*pm->shield.buffer_id = gr_buffer_handle::invalid();
}
}
@@ -3233,5 +3229,5 @@ void bsp_polygon_data::replace_textures_used(const SCP_map<int, int>& replacemen
}
SCP_set<int> model_get_textures_used(const polymodel* pm, int submodel) {
return bsp_polygon_data{ pm->submodel[submodel].bsp_data, pm->submodel[submodel].bsp_data_size }.get_textures_used();
return bsp_polygon_data{ pm->submodel[submodel].bsp_data.get(), pm->submodel[submodel].bsp_data_size }.get_textures_used();
}
+53 -161
View File
@@ -186,112 +186,24 @@ public:
SCP_unordered_map<int, intrinsic_motion> Intrinsic_motions;
void model_free(polymodel* pm)
{
int i, j;
safe_kill(pm->ship_bay);
if (pm->paths) {
for (i = 0; i < pm->n_paths; i++) {
for (j = 0; j < pm->paths[i].nverts; j++) {
if (pm->paths[i].verts[j].turret_ids) {
vm_free(pm->paths[i].verts[j].turret_ids);
}
}
if (pm->paths[i].verts) {
vm_free(pm->paths[i].verts);
}
}
vm_free(pm->paths);
}
if (pm->shield.verts) {
vm_free(pm->shield.verts);
}
if (pm->shield.tris) {
vm_free(pm->shield.tris);
}
if (pm->gun_banks) { // NOLINT
delete[] pm->gun_banks;
}
if (pm->missile_banks) { // NOLINT
delete[] pm->missile_banks;
}
if (pm->docking_bays) {
for (i = 0; i < pm->n_docks; i++) {
if (pm->docking_bays[i].splines) {
vm_free(pm->docking_bays[i].splines);
}
}
vm_free(pm->docking_bays);
}
if (pm->thrusters) {
for (i = 0; i < pm->n_thrusters; i++) {
if (pm->thrusters[i].points)
vm_free(pm->thrusters[i].points);
}
vm_free(pm->thrusters);
}
if (pm->glow_point_banks) { // free the glows!!! -Bobboau
for (i = 0; i < pm->n_glow_point_banks; i++) {
if (pm->glow_point_banks[i].points)
vm_free(pm->glow_point_banks[i].points);
}
vm_free(pm->glow_point_banks);
}
#ifndef NDEBUG
if (pm->debug_info) {
vm_free(pm->debug_info);
}
#endif
int i;
if (pm->submodel) {
for (i = 0; i < pm->n_models; i++) {
pm->submodel[i].buffer.clear();
if (pm->submodel[i].bsp_data) {
vm_free(pm->submodel[i].bsp_data);
}
if (pm->submodel[i].collision_tree_index >= 0) {
model_remove_bsp_collision_tree(pm->submodel[i].collision_tree_index);
}
if (pm->submodel[i].outline_buffer != nullptr) {
vm_free(pm->submodel[i].outline_buffer);
pm->submodel[i].outline_buffer = nullptr;
pm->submodel[i].collision_tree_index = 0;
}
}
delete[] pm->submodel;
}
if (pm->xc) {
vm_free(pm->xc);
}
if (pm->lights) {
vm_free(pm->lights);
}
if (pm->shield_collision_tree) {
vm_free(pm->shield_collision_tree);
}
if (pm->shield.buffer_id.isValid()) {
gr_delete_buffer(pm->shield.buffer_id);
pm->shield.buffer_id = gr_buffer_handle::invalid();
if (pm->shield.buffer_id->isValid()) {
gr_delete_buffer(*pm->shield.buffer_id);
*pm->shield.buffer_id = gr_buffer_handle::invalid();
pm->shield.buffer_n_verts = 0;
}
@@ -303,10 +215,7 @@ void model_free(polymodel* pm)
pm->vert_source.Base_vertex_offset = 0;
}
if (pm->vert_source.Vertex_list != NULL) {
vm_free(pm->vert_source.Vertex_list);
pm->vert_source.Vertex_list = NULL;
}
pm->vert_source.Vertex_list.reset();
if (pm->vert_source.Ibuffer_handle.isValid()) {
gr_heap_deallocate(GpuHeap::ModelIndex, pm->vert_source.Index_offset);
@@ -315,10 +224,7 @@ void model_free(polymodel* pm)
pm->vert_source.Index_offset = 0;
}
if (pm->vert_source.Index_list != NULL) {
vm_free(pm->vert_source.Index_list);
pm->vert_source.Index_list = NULL;
}
pm->vert_source.Index_list.reset();
pm->vert_source.Vertex_list_size = 0;
pm->vert_source.Index_list_size = 0;
@@ -1652,8 +1558,6 @@ modelread_status read_model_file_no_subsys(polymodel * pm, const char* filename,
}
pm->version = version;
Assert(strlen(filename) < FILESPEC_LENGTH );
strcpy_s(pm->filename, filename);
memset( &pm->view_positions, 0, sizeof(pm->view_positions) );
@@ -1708,7 +1612,7 @@ modelread_status read_model_file_no_subsys(polymodel * pm, const char* filename,
Warning(LOCATION, "Model <%s> has a radius <= 0.00001f\n", filename);
}
pm->submodel = new bsp_info[MAX(1,pm->n_models)];
pm->submodel = make_shared<bsp_info[]>(MAX(1,pm->n_models));
//Assert(pm->n_models <= MAX_SUBMODELS);
@@ -1801,11 +1705,11 @@ modelread_status read_model_file_no_subsys(polymodel * pm, const char* filename,
}
// read in cross section info
pm->xc = NULL;
pm->xc = nullptr;
if ( pm->version >= 2014 ) {
pm->num_xc = cfread_int(fp);
if (pm->num_xc > 0) {
pm->xc = (cross_section*) vm_malloc(pm->num_xc*sizeof(cross_section));
pm->xc = make_shared<cross_section[]>(pm->num_xc);
for (i=0; i<pm->num_xc; i++) {
pm->xc[i].z = cfread_float(fp);
pm->xc[i].radius = cfread_float(fp);
@@ -1820,7 +1724,7 @@ modelread_status read_model_file_no_subsys(polymodel * pm, const char* filename,
//mprintf(( "Found %d lights!\n", pm->num_lights ));
if (pm->num_lights > 0) {
pm->lights = (bsp_light *)vm_malloc( sizeof(bsp_light)*pm->num_lights );
pm->lights = make_shared<bsp_light[]>(pm->num_lights );
for (i=0; i<pm->num_lights; i++ ) {
cfread_vector(&pm->lights[i].pos,fp);
pm->lights[i].type = cfread_int(fp);
@@ -2112,9 +2016,9 @@ modelread_status read_model_file_no_subsys(polymodel * pm, const char* filename,
{
sm->bsp_data_size = cfread_int(fp);
if (sm->bsp_data_size > 0) {
sm->bsp_data = reinterpret_cast<ubyte*>(vm_malloc(sm->bsp_data_size));
cfread(sm->bsp_data, 1, sm->bsp_data_size, fp);
swap_bsp_data(pm, sm->bsp_data);
sm->bsp_data = make_shared<ubyte[]>(sm->bsp_data_size);
cfread(sm->bsp_data.get(), 1, sm->bsp_data_size, fp);
swap_bsp_data(pm, sm->bsp_data.get());
}
else {
sm->bsp_data = nullptr;
@@ -2125,28 +2029,27 @@ modelread_status read_model_file_no_subsys(polymodel * pm, const char* filename,
sm->bsp_data_size = cfread_int(fp);
if (sm->bsp_data_size > 0) {
auto bsp_data = reinterpret_cast<ubyte*>(vm_malloc(sm->bsp_data_size));
auto bsp_data = make_shared<ubyte[]>(sm->bsp_data_size);
cfread(bsp_data, 1, sm->bsp_data_size, fp);
cfread(bsp_data.get(), 1, sm->bsp_data_size, fp);
// byte swap first thing
swap_bsp_data(pm, bsp_data);
swap_bsp_data(pm, bsp_data.get());
extern bool Cmdline_no_bsp_align;
if (Cmdline_no_bsp_align) {
sm->bsp_data = bsp_data;
}
else {
auto bsp_data_size_aligned = align_bsp_data(bsp_data, nullptr, sm->bsp_data_size);
auto bsp_data_size_aligned = align_bsp_data(bsp_data.get(), nullptr, sm->bsp_data_size);
if (bsp_data_size_aligned != static_cast<uint>(sm->bsp_data_size)) {
auto bsp_data_aligned = reinterpret_cast<ubyte*>(vm_malloc(bsp_data_size_aligned));
auto bsp_data_aligned = make_shared<ubyte[]>(bsp_data_size_aligned);
align_bsp_data(bsp_data, bsp_data_aligned, sm->bsp_data_size);
align_bsp_data(bsp_data.get(), bsp_data_aligned.get(), sm->bsp_data_size);
// release unaligned data
vm_free(bsp_data);
bsp_data = nullptr;
bsp_data.reset();
nprintf(("Model", "BSP ALIGN => %s:%s resized by %d bytes (%d total)\n", pm->filename, sm->name, bsp_data_size_aligned - sm->bsp_data_size, bsp_data_size_aligned));
@@ -2190,9 +2093,9 @@ modelread_status read_model_file_no_subsys(polymodel * pm, const char* filename,
//mprintf(("SLDC Shield Collision Tree was %d bytes in size\n", pm->sldc_size));
pm->sldc_size = convert_sldc_to_slc2(sldc_tree.get(), slc2_tree.get(), pm->sldc_size);
//mprintf(("SLC2 Shield Collision Tree is %d bytes in size\n", pm->sldc_size));
pm->shield_collision_tree = (ubyte*)vm_malloc(pm->sldc_size); //sldc_size is slc2 size, reused variable
memcpy(pm->shield_collision_tree, slc2_tree.get(), pm->sldc_size);
swap_sldc_data(pm->shield_collision_tree);
pm->shield_collision_tree = make_shared<ubyte[]>(pm->sldc_size); //sldc_size is slc2 size, reused variable
memcpy(pm->shield_collision_tree.get(), slc2_tree.get(), pm->sldc_size);
swap_sldc_data(pm->shield_collision_tree.get());
}
}
break;
@@ -2201,9 +2104,9 @@ modelread_status read_model_file_no_subsys(polymodel * pm, const char* filename,
{
if (pm->version >= 2200) {
pm->sldc_size = cfread_int(fp);
pm->shield_collision_tree = (ubyte*)vm_malloc(pm->sldc_size);
cfread(pm->shield_collision_tree, 1, pm->sldc_size, fp);
swap_sldc_data(pm->shield_collision_tree);
pm->shield_collision_tree = make_shared<ubyte[]>(pm->sldc_size);
cfread(pm->shield_collision_tree.get(), 1, pm->sldc_size, fp);
swap_sldc_data(pm->shield_collision_tree.get());
//mprintf(( "SLC2 Shield Collision Tree, %d bytes in size\n", pm->sldc_size));
}
}
@@ -2214,7 +2117,7 @@ modelread_status read_model_file_no_subsys(polymodel * pm, const char* filename,
pm->shield.nverts = cfread_int( fp ); // get the number of vertices in the list
if (pm->shield.nverts > 0) {
pm->shield.verts = (shield_vertex *)vm_malloc(pm->shield.nverts * sizeof(shield_vertex) );
pm->shield.verts = make_shared<shield_vertex[]>(pm->shield.nverts);
Assert( pm->shield.verts );
for ( i = 0; i < pm->shield.nverts; i++ ) { // read in the vertex list
cfread_vector( &(pm->shield.verts[i].pos), fp );
@@ -2224,7 +2127,7 @@ modelread_status read_model_file_no_subsys(polymodel * pm, const char* filename,
pm->shield.ntris = cfread_int( fp ); // get the number of triangles that compose the shield
if (pm->shield.ntris > 0) {
pm->shield.tris = (shield_tri *)vm_malloc(pm->shield.ntris * sizeof(shield_tri) );
pm->shield.tris = make_shared<shield_tri[]>(pm->shield.ntris);
Assert( pm->shield.tris );
for ( i = 0; i < pm->shield.ntris; i++ ) {
cfread_vector( &temp_vec, fp );
@@ -2257,11 +2160,11 @@ modelread_status read_model_file_no_subsys(polymodel * pm, const char* filename,
case ID_MPNT:
{
int n_weps = cfread_int(fp);
w_bank *wep_banks = nullptr;
std::shared_ptr<w_bank[]> wep_banks = nullptr;
if (n_weps > 0)
{
wep_banks = new w_bank[n_weps];
wep_banks = make_shared<w_bank[]>(n_weps);
for (i = 0; i < n_weps; ++i)
{
w_bank *bank = &wep_banks[i];
@@ -2310,8 +2213,7 @@ modelread_status read_model_file_no_subsys(polymodel * pm, const char* filename,
pm->n_docks = cfread_int(fp);
if (pm->n_docks > 0) {
pm->docking_bays = (dock_bay *)vm_malloc(sizeof(dock_bay) * pm->n_docks);
Assert( pm->docking_bays != NULL );
pm->docking_bays = make_shared<dock_bay[]>(pm->n_docks);
for (i = 0; i < pm->n_docks; i++ ) {
char *p;
@@ -2340,7 +2242,7 @@ modelread_status read_model_file_no_subsys(polymodel * pm, const char* filename,
bay->num_spline_paths = cfread_int( fp );
if ( bay->num_spline_paths > 0 ) {
bay->splines = (int *)vm_malloc(sizeof(int) * bay->num_spline_paths);
bay->splines = make_shared<int[]>(bay->num_spline_paths);
for ( j = 0; j < bay->num_spline_paths; j++ )
bay->splines[j] = cfread_int(fp);
} else {
@@ -2417,13 +2319,10 @@ modelread_status read_model_file_no_subsys(polymodel * pm, const char* filename,
int gpb_num = cfread_int(fp);
pm->n_glow_point_banks = gpb_num;
pm->glow_point_banks = NULL;
pm->glow_point_banks = nullptr;
if (gpb_num > 0)
{
pm->glow_point_banks = (glow_point_bank *) vm_malloc(sizeof(glow_point_bank) * gpb_num);
Assert(pm->glow_point_banks != NULL);
}
pm->glow_point_banks = make_shared<glow_point_bank[]>(gpb_num);
for (int gpb = 0; gpb < gpb_num; gpb++)
{
@@ -2438,12 +2337,12 @@ modelread_status read_model_file_no_subsys(polymodel * pm, const char* filename,
bank->LOD = cfread_int(fp);
bank->type = cfread_int(fp);
bank->num_points = cfread_int(fp);
bank->points = NULL;
bank->points = nullptr;
bank->glow_bitmap = -1;
bank->glow_neb_bitmap = -1;
if (bank->num_points > 0)
bank->points = (glow_point *) vm_malloc(sizeof(glow_point) * bank->num_points);
bank->points = make_shared<glow_point[]>(bank->num_points);
//if((bank->off_time > 0) && (bank->disp_time > 0))
//bank->is_on = false;
@@ -2517,17 +2416,16 @@ modelread_status read_model_file_no_subsys(polymodel * pm, const char* filename,
pm->n_thrusters = cfread_int(fp);
if (pm->n_thrusters > 0) {
pm->thrusters = (thruster_bank *)vm_malloc(sizeof(thruster_bank) * pm->n_thrusters);
Assert( pm->thrusters != NULL );
pm->thrusters = make_shared<thruster_bank[]>(pm->n_thrusters);
for (i = 0; i < pm->n_thrusters; i++ ) {
thruster_bank *bank = &pm->thrusters[i];
bank->num_points = cfread_int(fp);
bank->points = NULL;
bank->points = nullptr;
if (bank->num_points > 0)
bank->points = (glow_point *) vm_malloc(sizeof(glow_point) * bank->num_points);
bank->points = make_shared<glow_point[]>(bank->num_points);
bank->obj_num = -1;
bank->submodel_num = -1;
@@ -2703,10 +2601,8 @@ modelread_status read_model_file_no_subsys(polymodel * pm, const char* filename,
#ifndef NDEBUG
pm->debug_info_size = len;
pm->debug_info = (char *)vm_malloc(pm->debug_info_size+1);
Assert(pm->debug_info!=NULL);
memset(pm->debug_info,0,len+1);
cfread( pm->debug_info, 1, len, fp );
pm->debug_info = make_shared<char[]>(pm->debug_info_size+1);
cfread( pm->debug_info.get(), 1, len, fp );
#endif
break;
@@ -2720,10 +2616,7 @@ modelread_status read_model_file_no_subsys(polymodel * pm, const char* filename,
break;
}
pm->paths = (model_path *)vm_malloc(sizeof(model_path)*pm->n_paths);
Assert( pm->paths != NULL );
memset( pm->paths, 0, sizeof(model_path) * pm->n_paths );
pm->paths = make_shared<model_path[]>(pm->n_paths);
for (i=0; i<pm->n_paths; i++ ) {
cfread_string_len(pm->paths[i].name, MAX_NAME_LEN, fp);
@@ -2757,12 +2650,10 @@ modelread_status read_model_file_no_subsys(polymodel * pm, const char* filename,
}
pm->paths[i].nverts = cfread_int( fp );
pm->paths[i].verts = (mp_vert *)vm_malloc( sizeof(mp_vert) * pm->paths[i].nverts );
pm->paths[i].verts = make_shared<mp_vert[]>(pm->paths[i].nverts);
pm->paths[i].goal = pm->paths[i].nverts - 1;
pm->paths[i].type = MP_TYPE_UNUSED;
pm->paths[i].value = 0;
Assert(pm->paths[i].verts!=NULL);
memset( pm->paths[i].verts, 0, sizeof(mp_vert) * pm->paths[i].nverts );
for (j=0; j<pm->paths[i].nverts; j++ ) {
cfread_vector(&pm->paths[i].verts[j].pos,fp );
@@ -2775,7 +2666,7 @@ modelread_status read_model_file_no_subsys(polymodel * pm, const char* filename,
pm->paths[i].verts[j].nturrets = nturrets;
if (nturrets > 0) {
pm->paths[i].verts[j].turret_ids = (int *)vm_malloc( sizeof(int) * nturrets );
pm->paths[i].verts[j].turret_ids = make_shared<int[]>(nturrets);
for ( k = 0; k < nturrets; k++ )
pm->paths[i].verts[j].turret_ids[k] = cfread_int( fp );
}
@@ -3051,6 +2942,9 @@ modelread_status read_model_file(polymodel* pm, const char* filename, ErrorType
//reads a binary file containing a 3d model
modelread_status read_and_process_model_file(polymodel* pm, const char* filename, int n_subsystems, model_subsystem* subsystems, ErrorType error_type, model_read_deferred_tasks& deferredTasks)
{
Assert(strlen(filename) < FILESPEC_LENGTH );
strcpy_s(pm->filename, filename);
modelread_status status = read_model_file(pm, filename, error_type, deferredTasks);
//By now, we have finished reading this model. If it was virtual, we might have accumulated cache.
@@ -3558,8 +3452,8 @@ int model_load(const char* filename, ship_info* sip, ErrorType error_type, bool
pm->submodel[i].collision_tree_index = model_create_bsp_collision_tree();
bsp_collision_tree* tree = model_get_bsp_collision_tree(pm->submodel[i].collision_tree_index);
Macro_ubyte_bounds = pm->submodel[i].bsp_data + pm->submodel[i].bsp_data_size;
model_collide_parse_bsp(tree, pm->submodel[i].bsp_data, pm->version);
Macro_ubyte_bounds = pm->submodel[i].bsp_data.get() + pm->submodel[i].bsp_data_size;
model_collide_parse_bsp(tree, pm->submodel[i].bsp_data.get(), pm->version);
Macro_ubyte_bounds = nullptr;
}
@@ -3742,10 +3636,9 @@ void model_set_bay_path_nums(polymodel *pm)
{
int i;
if (pm->ship_bay != NULL)
if (pm->ship_bay != nullptr)
{
vm_free(pm->ship_bay);
pm->ship_bay = NULL;
pm->ship_bay.reset();
}
/*
@@ -3756,8 +3649,7 @@ void model_set_bay_path_nums(polymodel *pm)
*/
// malloc out storage for the path information
pm->ship_bay = (ship_bay *) vm_malloc(sizeof(ship_bay));
Assert(pm->ship_bay != NULL);
pm->ship_bay = make_shared<ship_bay_t>();
pm->ship_bay->num_paths = 0;
// TODO: determine if zeroing out here is affecting any earlier initializations
+2 -2
View File
@@ -1293,7 +1293,7 @@ void model_render_children_buffers(model_draw_list* scene, model_material *rende
if ( (model_flags & MR_SHOW_OUTLINE || model_flags & MR_SHOW_OUTLINE_HTL || model_flags & MR_SHOW_OUTLINE_PRESET) &&
sm->outline_buffer != nullptr ) {
color outline_color = interp->get_color();
scene->add_outline(sm->outline_buffer, sm->n_verts_outline, &outline_color);
scene->add_outline(sm->outline_buffer.get(), sm->n_verts_outline, &outline_color);
} else {
if ( trans_buffer && sm->trans_buffer.flags & VB_FLAG_TRANS ) {
model_render_buffers(scene, rendering_material, interp, &sm->trans_buffer, pm, mn, detail_level, tmap_flags);
@@ -2932,7 +2932,7 @@ void model_render_queue(const model_render_params* interp, model_draw_list* scen
if ( (is_outlines_only || is_outlines_only_htl) && pm->submodel[detail_model_num].outline_buffer != NULL ) {
color outline_color = interp->get_color();
scene->add_outline(pm->submodel[detail_model_num].outline_buffer, pm->submodel[detail_model_num].n_verts_outline, &outline_color);
scene->add_outline(pm->submodel[detail_model_num].outline_buffer.get(), pm->submodel[detail_model_num].n_verts_outline, &outline_color);
} else {
model_render_buffers(scene, &rendering_material, interp, &pm->submodel[detail_model_num].buffer, pm, detail_model_num, detail_level, tmap_flags);
+13 -32
View File
@@ -202,10 +202,12 @@ void virtual_pof_init() {
template<typename T, bool vmalloc, typename member_t>
inline void object_copy_including_array_member_inner(const T& item, T& result, int size, member_t T::* ptm) {
if (vmalloc)
result.*ptm = (member_t)vm_malloc(sizeof(typename std::remove_pointer<member_t>::type) * (size));
if constexpr (is_smart_pointer_v<std::decay_t<decltype(result.*ptm)>>)
result.*ptm = make_shared<typename std::decay_t<decltype(result.*ptm)>::element_type[]>(size);
else if constexpr (vmalloc)
result.*ptm = static_cast<member_t>(vm_malloc(sizeof(std::remove_pointer_t<member_t>) * size));
else
result.*ptm = new typename std::remove_pointer<member_t>::type[size];
result.*ptm = new std::remove_pointer_t<member_t>[size];
for (int i = 0; i < size; i++)
(result.*ptm)[i] = (item.*ptm)[i];
@@ -225,40 +227,19 @@ T object_copy_including_array_member(const T& item, int T::* size, member_t T::*
}
template<typename T>
int reallocate_and_copy_array(T*& array, int& size, size_t to_add) {
int reallocate_and_copy_array(std::shared_ptr<T[]>& array, int& size, size_t to_add) {
//Make sure to keep old data
T* oldArray = array;
Assertion(size >= 0, "Tried to realloc an array of negative size %d!", size);
int size_before = size;
//Realloc new submodel array of proper size
size += static_cast<int>(to_add);
array = new T[MAX(0,size)];
//Copy over old data. Pointers in the struct can still point to old members, we will just delete the outer bsp_info array
for (int i = 0; i < size_before; i++)
array[i] = std::move(oldArray[i]);
delete[] oldArray;
return size_before;
}
template<typename T>
int reallocate_and_copy_array_vmalloc(T*& array, int& size, size_t to_add) {
//Make sure to keep old data
T* oldArray = array;
std::shared_ptr<T[]> oldArray = array;
int size_before = size;
//Realloc new submodel array of proper size
size += static_cast<int>(to_add);
array = (T*)vm_malloc(sizeof(T) * size);
array = make_shared<T[]>(size);
//Copy over old data. Pointers in the struct can still point to old members, we will just delete the outer bsp_info array
for (int i = 0; i < size_before; i++)
array[i] = std::move(oldArray[i]);
vm_free(oldArray);
return size_before;
}
@@ -753,10 +734,10 @@ VirtualPOFOperationAddWeapons::VirtualPOFOperationAddWeapons() {
void VirtualPOFOperationAddWeapons::process(polymodel* pm, model_read_deferred_tasks& /*deferredTasks*/, model_parse_depth depth, const VirtualPOFDefinition& virtualPof) const {
auto appendingPM = virtual_pof_build_cache(appendingPOF, depth);
w_bank*& banks = primary ? pm->gun_banks : pm->missile_banks;
auto& banks = primary ? pm->gun_banks : pm->missile_banks;
int& n_banks = primary ? pm->n_guns : pm->n_missiles;
const w_bank* const& banks_src = primary ? appendingPM->pm()->gun_banks : appendingPM->pm()->missile_banks;
const auto& banks_src = primary ? appendingPM->pm()->gun_banks : appendingPM->pm()->missile_banks;
const int& n_banks_src = primary ? appendingPM->pm()->n_guns : appendingPM->pm()->n_missiles;
const int& n_banks_max = primary ? MAX_SHIP_PRIMARY_BANKS : MAX_SHIP_SECONDARY_BANKS;
@@ -860,9 +841,9 @@ void VirtualPOFOperationAddDockPoint::process(polymodel* pm, model_read_deferred
}
}
int destdock = reallocate_and_copy_array_vmalloc(pm->docking_bays, pm->n_docks, 1);
int destdock = reallocate_and_copy_array(pm->docking_bays, pm->n_docks, 1);
pm->docking_bays[destdock] = object_copy_including_array_member(appendingPM->docking_bays[dockpoint], &dock_bay::num_spline_paths, &dock_bay::splines);
int splinefrom = reallocate_and_copy_array_vmalloc(pm->paths, pm->n_paths, pm->docking_bays[destdock].num_spline_paths);
int splinefrom = reallocate_and_copy_array(pm->paths, pm->n_paths, pm->docking_bays[destdock].num_spline_paths);
for (int i = 0; i < pm->docking_bays[destdock].num_spline_paths; i++) {
pm->paths[i + splinefrom] = object_copy_including_array_member(appendingPM->paths[appendingPM->docking_bays[dockpoint].splines[i]], &model_path::nverts, &model_path::verts);
@@ -957,7 +938,7 @@ void VirtualPOFOperationAddPath::process(polymodel* pm, model_read_deferred_task
return;
}
int destpath = reallocate_and_copy_array_vmalloc(pm->paths, pm->n_paths, 1);
int destpath = reallocate_and_copy_array(pm->paths, pm->n_paths, 1);
pm->paths[destpath] = object_copy_including_array_member(appendingPM->paths[sourcePathNr], &model_path::nverts, &model_path::verts);
if (targetParentSubsystem) {
+4 -5
View File
@@ -394,7 +394,7 @@ void shield_render_triangle(int texture, float alpha, gshield_tri *trip, matrix
void shield_render_decal(polymodel *pm, matrix *orient, vec3d *pos, matrix* hit_orient, vec3d *hit_pos, float hit_radius, int bitmap_id, color *clr)
{
if (!pm->shield.buffer_id.isValid() || pm->shield.buffer_n_verts < 3) {
if (!pm->shield.buffer_id->isValid() || pm->shield.buffer_n_verts < 3) {
return;
}
@@ -410,7 +410,7 @@ void shield_render_decal(polymodel *pm, matrix *orient, vec3d *pos, matrix* hit_
material_info.set_impact_transform(*hit_orient, *hit_pos);
material_info.set_cull_mode(false);
gr_render_shield_impact(&material_info, PRIM_TYPE_TRIS, &pm->shield.layout, pm->shield.buffer_id, pm->shield.buffer_n_verts);
gr_render_shield_impact(&material_info, PRIM_TYPE_TRIS, &pm->shield.layout, *pm->shield.buffer_id, pm->shield.buffer_n_verts);
g3_done_instance(true);
}
@@ -562,9 +562,8 @@ void render_shields()
void create_tris_containing(vec3d *vp, matrix *orient, shield_info *shieldp, vec3d *tcp, vec3d *centerp, float radius, vec3d *rvec, vec3d *uvec)
{
int i, j;
shield_vertex *verts;
verts = shieldp->verts;
const auto& verts = shieldp->verts;
for (i=0; i<Num_tris; i++) {
if ( !shieldp->tris[i].used ) {
@@ -624,7 +623,7 @@ int get_global_shield_tri()
void create_shield_from_triangle(int trinum, matrix *orient, shield_info *shieldp, vec3d *tcp, vec3d *centerp, float radius, vec3d *rvec, vec3d *uvec)
{
rs_compute_uvs( &shieldp->tris[trinum], shieldp->verts, tcp, radius, rvec, uvec);
rs_compute_uvs( &shieldp->tris[trinum], shieldp->verts.get(), tcp, radius, rvec, uvec);
shieldp->tris[trinum].used = 1;
+1 -1
View File
@@ -12351,7 +12351,7 @@ void change_ship_type(int n, int ship_type, int by_sexp)
}
// see if this dockpoint is found on the new model under a different name
int new_dockpoint_index = find_item_with_string(pm->docking_bays, pm->n_docks, &dock_bay::name, dockpoint_name);
int new_dockpoint_index = find_item_with_string(pm->docking_bays.get(), pm->n_docks, &dock_bay::name, dockpoint_name);
if (new_dockpoint_index >= 0)
{
dock_ptr->dockpoint_used = new_dockpoint_index;
+2 -2
View File
@@ -26,7 +26,7 @@ protected:
pm = new polymodel();
pmi = new polymodel_instance();
pm->submodel = new bsp_info[3];
pm->submodel = make_shared<bsp_info[]>(3);
pmi->submodel = new submodel_instance[3];
pm->submodel[0].parent = -1;
@@ -51,7 +51,7 @@ protected:
void TearDown() override {
test::FSTestFixture::TearDown();
delete[] pm->submodel;
pm->submodel.reset();
delete[] pmi->submodel;
delete pm;
delete pmi;