Correctly reload mesh materials on definition reload

This does not fix #76 yet, but it's a first step.
Armin Burgmeier 2011-08-17 23:50:33 +02:00
parent 751ae18ae2
commit 771163be4b
9 changed files with 239 additions and 6 deletions

View File

@ -391,6 +391,8 @@ set(OC_CLONK_SOURCES
src/lib/StdMeshLoaderXml.cpp
src/lib/StdMeshMaterial.cpp
src/lib/StdMeshMaterial.h
src/lib/StdMeshUpdate.cpp
src/lib/StdMeshUpdate.h
src/lib/StdResStr2.cpp
src/lib/StdResStr2.h
src/lib/StdResStr.h

View File

@ -394,6 +394,8 @@ src/lib/StdMeshLoader.h \
src/lib/StdMeshLoaderXml.cpp \
src/lib/StdMeshMaterial.cpp \
src/lib/StdMeshMaterial.h \
src/lib/StdMeshUpdate.cpp \
src/lib/StdMeshUpdate.h \
src/lib/StdResStr.h \
src/lib/texture/C4Facet.cpp \
src/lib/texture/C4FacetEx.cpp \

View File

@ -334,7 +334,8 @@ C4AdditionalDefGraphics::C4AdditionalDefGraphics(C4Def *pOwnDef, const char *szN
SCopy(szName, Name, C4MaxName);
}
C4DefGraphicsPtrBackup::C4DefGraphicsPtrBackup(C4DefGraphics *pSourceGraphics)
C4DefGraphicsPtrBackup::C4DefGraphicsPtrBackup(C4DefGraphics *pSourceGraphics):
MeshMaterialUpdate(::MeshMaterialManager)
{
// assign graphics + def
pGraphicsPtr = pSourceGraphics;
@ -342,6 +343,20 @@ C4DefGraphicsPtrBackup::C4DefGraphicsPtrBackup(C4DefGraphics *pSourceGraphics)
// assign name
const char *szName = pGraphicsPtr->GetName();
if (szName) SCopy(szName, Name, C4MaxName); else *Name=0;
// Remove all mesh materials that were loaded from this definition
for(StdMeshMatManager::Iterator iter = ::MeshMaterialManager.Begin(); iter != MeshMaterialManager.End(); )
{
StdStrBuf Filename;
Filename.Copy(pDef->Filename);
Filename.Append("/"); Filename.Append(GetFilename(iter->FileName.getData()));
if(Filename == iter->FileName)
iter = ::MeshMaterialManager.Remove(iter, &MeshMaterialUpdate);
else
++iter;
}
// create next graphics recursively
C4DefGraphics *pNextGfx = pGraphicsPtr->pNext;
if (pNextGfx)
@ -360,6 +375,8 @@ C4DefGraphicsPtrBackup::~C4DefGraphicsPtrBackup()
void C4DefGraphicsPtrBackup::AssignUpdate(C4DefGraphics *pNewGraphics)
{
UpdateMeshMaterials();
// only if graphics are assigned
if (pGraphicsPtr)
{
@ -378,6 +395,7 @@ void C4DefGraphicsPtrBackup::AssignUpdate(C4DefGraphics *pNewGraphics)
pObj->AssignRemoval(); pObj->pGraphics=NULL;
}
}
// remove any overlay graphics
for (;;)
{
@ -406,8 +424,36 @@ void C4DefGraphicsPtrBackup::AssignUpdate(C4DefGraphics *pNewGraphics)
if (pNext) pNext->AssignUpdate(pNewGraphics);
}
void C4DefGraphicsPtrBackup::UpdateMeshMaterials()
{
// Update mesh materials for all meshes
for(C4DefList::Table::iterator iter = Definitions.table.begin(); iter != Definitions.table.end(); ++iter)
if(iter->second->Graphics.Type == C4DefGraphics::TYPE_Mesh)
MeshMaterialUpdate.Update(iter->second->Graphics.Mesh);
// Update mesh materials for all mesh instances, except ones which belong
// to this definition. Such graphics have an invalid pointer to the underlying
// StdMesh, and they will be updated separately below.
C4Object *pObj;
for (C4ObjectLink *pLnk = ::Objects.First; pLnk; pLnk=pLnk->Next)
if ((pObj=pLnk->Obj)) if (pObj->Status)
{
//if(pObj->pGraphics != pGraphicsPtr)
if(pObj->pMeshInstance)
MeshMaterialUpdate.Update(pObj->pMeshInstance);
for (C4GraphicsOverlay* pGfxOverlay = pObj->pGfxOverlay; pGfxOverlay; pGfxOverlay = pGfxOverlay->GetNext())
//if (pGfxOverlay->GetGfx() != pGraphicsPtr)
if(pGfxOverlay->pMeshInstance)
MeshMaterialUpdate.Update(pGfxOverlay->pMeshInstance);
}
}
void C4DefGraphicsPtrBackup::AssignRemoval()
{
// Reset all mesh materials to what they were before the update
MeshMaterialUpdate.Cancel();
UpdateMeshMaterials();
// only if graphics are assigned
if (pGraphicsPtr)
{

View File

@ -29,6 +29,7 @@
#include "C4ObjectPtr.h"
#include "C4InputValidation.h"
#include "C4Id.h"
#include "StdMeshUpdate.h"
class C4Def;
@ -110,6 +111,7 @@ protected:
C4Def *pDef; // definition of dead graphics
char Name[C4MaxName+1]; // name of graphics
C4DefGraphicsPtrBackup *pNext; // next member of linked list
StdMeshMaterialUpdate MeshMaterialUpdate; // Backup of dead mesh materials
public:
C4DefGraphicsPtrBackup(C4DefGraphics *pSourceGraphics); // ctor
@ -117,6 +119,9 @@ public:
void AssignUpdate(C4DefGraphics *pNewGraphics); // update all game objects with new graphics pointers
void AssignRemoval(); // remove graphics of this def from all game objects
private:
void UpdateMeshMaterials();
};
// Helper to compile C4DefGraphics-Pointer
@ -136,6 +141,7 @@ public:
// graphics overlay used to attach additional graphics to objects
class C4GraphicsOverlay
{
friend class C4DefGraphicsPtrBackup;
public:
enum Mode
{

View File

@ -234,6 +234,7 @@ class StdSubMesh
{
friend class StdMesh;
friend class StdMeshLoader;
friend class StdMeshMaterialUpdate;
public:
// Remember bone assignments for vertices
class Vertex: public StdMeshVertex
@ -262,6 +263,8 @@ private:
class StdMesh
{
friend class StdMeshLoader;
friend class StdMeshMaterialUpdate;
StdMesh();
public:
~StdMesh();
@ -300,6 +303,7 @@ private:
class StdSubMeshInstance
{
friend class StdMeshInstance;
friend class StdMeshMaterialUpdate;
public:
StdSubMeshInstance(const StdSubMesh& submesh);
@ -354,6 +358,7 @@ private:
class StdMeshInstance
{
friend class StdMeshMaterialUpdate;
public:
StdMeshInstance(const StdMesh& mesh);
~StdMeshInstance();
@ -419,8 +424,6 @@ public:
NewFunc newfunc;
};
template<typename T>
struct ID: IDBase
{

View File

@ -2,7 +2,7 @@
* OpenClonk, http://www.openclonk.org
*
* Copyright (c) 2009 Mark Haßelbusch
* Copyright (c) 2009-2010 Armin Burgmeier
* Copyright (c) 2009-2011 Armin Burgmeier
* Copyright (c) 2009 Günther Brammer
* Copyright (c) 2010 Benjamin Herr
* Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de
@ -21,6 +21,7 @@
#include "C4Include.h"
#include <StdMeshMaterial.h>
#include <StdMeshUpdate.h>
#include <StdDDraw2.h>
#include <cctype>
@ -1037,4 +1038,10 @@ const StdMeshMaterial* StdMeshMatManager::GetMaterial(const char* material_name)
return &iter->second;
}
StdMeshMatManager::Iterator StdMeshMatManager::Remove(const Iterator& iter, StdMeshMaterialUpdate* update)
{
if(update) update->Add(&*iter);
return Iterator(Materials.erase(iter.iter_));
}
StdMeshMatManager MeshMaterialManager;

View File

@ -1,7 +1,7 @@
/*
* OpenClonk, http://www.openclonk.org
*
* Copyright (c) 2009-2010 Armin Burgmeier
* Copyright (c) 2009-2011 Armin Burgmeier
* Copyright (c) 2010 Benjamin Herr
* Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de
*
@ -320,7 +320,29 @@ public:
class StdMeshMatManager
{
friend class StdMeshMaterialUpdate;
private:
typedef std::map<StdCopyStrBuf, StdMeshMaterial> MaterialMap;
public:
class Iterator
{
friend class StdMeshMatManager;
public:
Iterator(const MaterialMap::iterator& iter): iter_(iter) {}
Iterator(const Iterator& iter): iter_(iter.iter_) {}
Iterator operator=(const Iterator& iter) { iter_ = iter.iter_; return *this; }
Iterator& operator++() { ++iter_; return *this; }
bool operator==(const Iterator& other) const { return iter_ == other.iter_; }
bool operator!=(const Iterator& other) const { return iter_ != other.iter_; }
const StdMeshMaterial& operator*() const { return iter_->second; }
const StdMeshMaterial* operator->() const { return &iter_->second; }
private:
MaterialMap::iterator iter_;
};
// Remove all materials from manager. Make sure there is no StdMesh
// referencing any out there before calling this.
void Clear();
@ -334,8 +356,12 @@ public:
// Get material by name. NULL if there is no such material with this name.
const StdMeshMaterial* GetMaterial(const char* material_name) const;
Iterator Begin() { return Iterator(Materials.begin()); }
Iterator End() { return Iterator(Materials.end()); }
Iterator Remove(const Iterator& iter, class StdMeshMaterialUpdate* update);
private:
std::map<StdCopyStrBuf, StdMeshMaterial> Materials;
MaterialMap Materials;
};
extern StdMeshMatManager MeshMaterialManager;

View File

@ -0,0 +1,91 @@
/*
* OpenClonk, http://www.openclonk.org
*
* Copyright (c) 2009-2011 Armin Burgmeier
*
* Portions might be copyrighted by other authors who have contributed
* to OpenClonk.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
* See isc_license.txt for full license and disclaimer.
*
* "Clonk" is a registered trademark of Matthes Bender.
* See clonk_trademark_license.txt for full license.
*/
#include "C4Include.h"
#include <StdMesh.h>
#include <StdMeshMaterial.h>
#include <StdMeshUpdate.h>
StdMeshMaterialUpdate::StdMeshMaterialUpdate(StdMeshMatManager& manager):
MaterialManager(manager)
{
}
void StdMeshMaterialUpdate::Update(StdMesh* mesh) const
{
for(std::vector<StdSubMesh>::iterator iter = mesh->SubMeshes.begin(); iter != mesh->SubMeshes.end(); ++iter)
{
std::map<const StdMeshMaterial*, StdMeshMaterial>::const_iterator mat_iter = Materials.find(iter->Material);
if(mat_iter != Materials.end())
{
const StdMeshMaterial* new_material = MaterialManager.GetMaterial(mat_iter->second.Name.getData());
if(new_material)
{
iter->Material = new_material;
}
else
{
// If no replacement material is available, then re-insert the previous
// material into the material map. This is mainly just to keep things
// going - next time the scenario will be started the mesh will fail
// to load because the material cannot be found.
MaterialManager.Materials[mat_iter->second.Name] = mat_iter->second;
iter->Material = MaterialManager.GetMaterial(mat_iter->second.Name.getData());
}
}
}
}
void StdMeshMaterialUpdate::Update(StdMeshInstance* instance) const
{
UpdateSingle(instance);
for(StdMeshInstance::AttachedMeshIter iter = instance->AttachedMeshesBegin(); iter != instance->AttachedMeshesEnd(); ++iter)
Update((*iter)->Child);
}
void StdMeshMaterialUpdate::Cancel() const
{
// Reset all materials in manager
for(std::map<const StdMeshMaterial*, StdMeshMaterial>::const_iterator iter = Materials.begin(); iter != Materials.end(); ++iter)
MaterialManager.Materials[iter->second.Name] = iter->second;
}
void StdMeshMaterialUpdate::UpdateSingle(StdMeshInstance* instance) const
{
for(unsigned int i = 0; i < instance->SubMeshInstances.size(); ++i) //std::vector<StdSubMeshInstance*>::iterator iter = instance->SubMeshInstances->begin(); iter != instance->SubMeshInstances->end(); ++iter)
{
StdSubMeshInstance* sub_instance = instance->SubMeshInstances[i];
std::map<const StdMeshMaterial*, StdMeshMaterial>::const_iterator mat_iter = Materials.find(sub_instance->Material);
if(mat_iter != Materials.end())
{
// Material needs to be updated
const StdMeshMaterial* new_material = MaterialManager.GetMaterial(mat_iter->second.Name.getData());
// If new material is not available, fall back to StdMesh (definition) material
if(!new_material) new_material = instance->Mesh.GetSubMesh(i).Material;
sub_instance->SetMaterial(*new_material);
}
}
std::vector<StdSubMeshInstance*> SubMeshInstances;
}
void StdMeshMaterialUpdate::Add(const StdMeshMaterial* material)
{
assert(Materials.find(material) == Materials.end());
Materials[material] = *material;
}

View File

@ -0,0 +1,50 @@
/*
* OpenClonk, http://www.openclonk.org
*
* Copyright (c) 2009-2011 Armin Burgmeier
*
* Portions might be copyrighted by other authors who have contributed
* to OpenClonk.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
* See isc_license.txt for full license and disclaimer.
*
* "Clonk" is a registered trademark of Matthes Bender.
* See clonk_trademark_license.txt for full license.
*/
#ifndef INC_StdMeshUpdate
#define INC_StdMeshUpdate
#include <StdMeshMaterial.h>
// This is a helper class to fix pointers after an update of StdMeshMaterials.
// To update one or more materials, remove them from the MaterialManager with
// erase(), then add new materials, then run Update() on all StdMeshes.
// Afterwards, run Update on all StdMeshInstances.
// If Cancel() is called before any Update() call then the Update() calls
// will reset all materials to what they have been before they were removed
// from the material manager.
class StdMeshMaterialUpdate
{
friend class StdMeshMatManager; // calls Add() for each removed material
public:
StdMeshMaterialUpdate(StdMeshMatManager& manager);
void Update(StdMesh* mesh) const;
void Update(StdMeshInstance* instance) const;
void Cancel() const;
private:
void UpdateSingle(StdMeshInstance* instance) const;
void Add(const StdMeshMaterial* material);
StdMeshMatManager& MaterialManager;
std::map<const StdMeshMaterial*, StdMeshMaterial> Materials;
};
#endif