forked from Mirrors/openclonk
Correctly reload mesh materials on definition reload
This does not fix #76 yet, but it's a first step.
parent
751ae18ae2
commit
771163be4b
|
@ -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
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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
|
Loading…
Reference in New Issue