Fixed crash when overriding materials in a renderable

This commit is contained in:
Mikulas Florek 2016-02-06 00:44:43 +01:00
parent c0167bf401
commit a9d14692bf
3 changed files with 83 additions and 73 deletions

View file

@ -1715,6 +1715,8 @@ struct PipelineImpl : public Pipeline
void setMaterial(Material* material)
{
if (!material->isReady()) return;
if (m_is_current_light_global)
{
setDirectionalLightUniforms(m_current_light);

View file

@ -152,7 +152,7 @@ private:
}
else if (old_state == Resource::State::READY && new_state == Resource::State::EMPTY)
{
m_scene.modeUnloaded(m_model);
m_scene.modelUnloaded(m_model);
}
}
@ -233,7 +233,7 @@ public:
auto& manager = i.model->getResourceManager();
if (i.meshes && &i.model->getMesh(0) != i.meshes)
{
freeMeshes(i, material_manager);
freeCustomMeshes(i, material_manager);
}
manager.get(ResourceManager::MODEL)->unload(*i.model);
LUMIX_DELETE(m_allocator, i.pose);
@ -664,6 +664,9 @@ public:
ASSERT(r.entity == i || r.entity == INVALID_ENTITY);
r.model = nullptr;
r.pose = nullptr;
r.custom_meshes = false;
r.meshes = nullptr;
r.mesh_count = 0;
if(r.entity != INVALID_ENTITY)
{
@ -684,22 +687,14 @@ public:
serializer.read(material_count);
if (material_count > 0)
{
r.meshes = (Mesh*)m_allocator.allocate(material_count * sizeof(Mesh));
r.mesh_count = material_count;
allocateCustomMeshes(r, material_count);
for (int j = 0; j < material_count; ++j)
{
char path[MAX_PATH_LENGTH];
serializer.readString(path, lengthOf(path));
Material* material = static_cast<Material*>(
m_engine.getResourceManager().get(ResourceManager::MATERIAL)->load(Path(path)));
new (NewPlaceholder(), r.meshes + j) Mesh(m_renderer.getBasicVertexDecl(),
material,
0,
0,
0,
0,
"",
m_allocator);
r.meshes[j].material = material;
}
}
}
@ -2860,13 +2855,20 @@ public:
void modelUnloaded(Model*, ComponentIndex component)
{
auto& r = m_renderables[component];
if (!r.custom_meshes)
{
r.meshes = nullptr;
r.mesh_count = 0;
}
m_culling_system->removeStatic(component);
}
void freeMeshes(Renderable& r, MaterialManager* manager)
void freeCustomMeshes(Renderable& r, MaterialManager* manager)
{
ASSERT(r.meshes != &r.model->getMesh(0));
if (!r.custom_meshes) return;
for (int i = 0; i < r.mesh_count; ++i)
{
manager->unload(*r.meshes[i].material);
@ -2874,6 +2876,8 @@ public:
}
m_allocator.deallocate(r.meshes);
r.meshes = nullptr;
r.custom_meshes = false;
r.mesh_count = 0;
}
@ -2899,33 +2903,28 @@ public:
r.pose = nullptr;
}
r.matrix = m_universe.getMatrix(r.entity);
ASSERT(!r.meshes || r.custom_meshes)
if (r.meshes)
{
if (r.mesh_count != model->getMeshCount())
allocateCustomMeshes(r, model->getMeshCount());
for (int i = 0; i < r.mesh_count; ++i)
{
freeMeshes(r, material_manager);
}
else
{
for (int i = 0; i < r.mesh_count; ++i)
auto& src = model->getMesh(i);
if (!r.meshes[i].material)
{
auto& src = model->getMesh(i);
if (!r.meshes[i].material)
{
material_manager->load(*src.material);
r.meshes[i].material = src.material;
}
r.meshes[i].set(
src.vertex_def,
src.attribute_array_offset,
src.attribute_array_size,
src.indices_offset,
src.indices_count
);
material_manager->load(*src.material);
r.meshes[i].material = src.material;
}
r.meshes[i].set(
src.vertex_def,
src.attribute_array_offset,
src.attribute_array_size,
src.indices_offset,
src.indices_count
);
}
}
if(!r.meshes)
else
{
r.meshes = &r.model->getMesh(0);
r.mesh_count = r.model->getMeshCount();
@ -2945,8 +2944,10 @@ public:
}
void modeUnloaded(Model* model)
void modelUnloaded(Model* model)
{
auto& rm = model->getResourceManager();
auto* material_manager = static_cast<MaterialManager*>(rm.get(ResourceManager::MATERIAL));
for (int i = 0, c = m_renderables.size(); i < c; ++i)
{
if (m_renderables[i].entity != INVALID_ENTITY && m_renderables[i].model == model)
@ -2985,52 +2986,60 @@ public:
}
void setRenderableMaterial(ComponentIndex cmp, int index, const Path& path) override
void allocateCustomMeshes(Renderable& r, int count)
{
auto& r = m_renderables[cmp];
if (!r.model) return;
if (path == r.meshes[index].material->getPath()) return;
if (r.custom_meshes && r.mesh_count == count) return;
auto& rm = r.model->getResourceManager();
auto* material_manager = static_cast<MaterialManager*>(rm.get(ResourceManager::MATERIAL));
if (index >= r.mesh_count)
auto* new_meshes = (Mesh*)m_allocator.allocate(count * sizeof(Mesh));
if (r.meshes)
{
if (r.model->isReady()) freeMeshes(r, material_manager);
r.mesh_count = index + 1;
r.meshes = (Mesh*)m_allocator.allocate(r.mesh_count * sizeof(Mesh));
auto* material = static_cast<Material*>(material_manager->load(path));
for (int i = 0; i < r.mesh_count; ++i)
{
new (NewPlaceholder(), r.meshes + i) Mesh(m_renderer.getBasicVertexDecl(),
i == index ? material : nullptr,
0,
0,
0,
0,
"",
m_allocator);
new (NewPlaceholder(), new_meshes + i) Mesh(r.meshes[i]);
}
}
else if (r.meshes == &r.model->getMesh(0))
{
r.mesh_count = r.model->getMeshCount();
r.meshes = (Mesh*)m_allocator.allocate(r.mesh_count * sizeof(Mesh));
for (int i = 0; i < r.mesh_count; ++i)
if (r.custom_meshes)
{
auto& src = r.model->getMesh(i);
material_manager->load(*src.material);
new (NewPlaceholder(), r.meshes + i) Mesh(src.vertex_def,
src.material,
src.attribute_array_offset,
src.attribute_array_size,
src.indices_offset,
src.indices_count,
"",
m_allocator);
for (int i = count; i < r.mesh_count; ++i)
{
material_manager->unload(*r.meshes[i].material);
}
m_allocator.deallocate(r.meshes);
}
else
{
for (int i = 0; i < r.mesh_count; ++i)
{
material_manager->load(*r.meshes[i].material);
}
}
}
for (int i = r.mesh_count; i < count; ++i)
{
new (NewPlaceholder(), new_meshes + i)
Mesh(m_renderer.getBasicVertexDecl(), nullptr, 0, 0, 0, 0, "", m_allocator);
}
r.meshes = new_meshes;
r.mesh_count = count;
r.custom_meshes = true;
}
void setRenderableMaterial(ComponentIndex cmp, int index, const Path& path) override
{
auto& r = m_renderables[cmp];
if (r.meshes && r.mesh_count > index && path == r.meshes[index].material->getPath()) return;
auto& rm = r.model->getResourceManager();
auto* material_manager = static_cast<MaterialManager*>(rm.get(ResourceManager::MATERIAL));
int new_count = Math::maxValue(int8(index + 1), r.mesh_count);
allocateCustomMeshes(r, new_count);
if (r.meshes[index].material) material_manager->unload(*r.meshes[index].material);
auto* new_material = static_cast<Material*>(material_manager->load(path));
r.meshes[index].material = new_material;
@ -3061,10 +3070,7 @@ public:
{
auto& rm = old_model->getResourceManager();
auto* material_manager = static_cast<MaterialManager*>(rm.get(ResourceManager::MATERIAL));
if (m_renderables[component].meshes != &old_model->getMesh(0))
{
freeMeshes(m_renderables[component], material_manager);
}
freeCustomMeshes(m_renderables[component], material_manager);
ModelLoadedCallback* callback = getModelLoadedCallback(old_model);
--callback->m_ref_count;
if (old_model->isReady())
@ -3333,6 +3339,7 @@ public:
r.layer_mask = 1;
r.meshes = nullptr;
r.pose = nullptr;
r.custom_meshes = false;
r.mesh_count = 0;
r.matrix = m_universe.getMatrix(entity);
m_universe.addComponent(entity, RENDERABLE_HASH, this, entity);

View file

@ -47,6 +47,7 @@ struct Renderable
Entity entity;
int64 layer_mask;
Mesh* meshes;
bool custom_meshes;
int8 mesh_count;
};