local variables ALSO work better when declared
[divverent/netradiant.git] / plugins / entity / modelskinkey.h
1 /*
2 Copyright (C) 2001-2006, William Joseph.
3 All Rights Reserved.
4
5 This file is part of GtkRadiant.
6
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20 */
21
22 #if !defined(INCLUDED_MODELSKINKEY_H)
23 #define INCLUDED_MODELSKINKEY_H
24
25 #include "modelskin.h"
26
27 #include "os/path.h"
28 #include "stream/stringstream.h"
29 #include "moduleobserver.h"
30 #include "entitylib.h"
31 #include "traverselib.h"
32
33 inline void parseTextureName(CopiedString& name, const char* token)
34 {
35   StringOutputStream cleaned(256);
36   cleaned << PathCleaned(token);
37   name = StringRange(cleaned.c_str(), path_get_filename_base_end(cleaned.c_str())); // remove extension
38 }
39
40 class ModelSkinKey : public ModuleObserver
41 {
42   CopiedString m_name;
43   ModelSkin* m_skin;
44   Callback m_skinChangedCallback;
45
46   ModelSkinKey(const ModelSkinKey&);
47   ModelSkinKey operator=(const ModelSkinKey&);
48
49   void construct()
50   {
51     m_skin = &GlobalModelSkinCache().capture(m_name.c_str());
52     m_skin->attach(*this);
53   }
54   void destroy()
55   {
56     m_skin->detach(*this);
57     GlobalModelSkinCache().release(m_name.c_str());
58   }
59
60 public:
61   ModelSkinKey(const Callback& skinChangedCallback) : m_skinChangedCallback(skinChangedCallback)
62   {
63     construct();
64   }
65   ~ModelSkinKey()
66   {
67     destroy();
68   }
69   ModelSkin& get() const
70   {
71     return *m_skin;
72   }
73   void skinChanged(const char* value)
74   {
75     destroy();
76     parseTextureName(m_name, value);
77     construct();
78   }
79   typedef MemberCaller1<ModelSkinKey, const char*, &ModelSkinKey::skinChanged> SkinChangedCaller;
80
81   void realise()
82   {
83     m_skinChangedCallback();
84   }
85   void unrealise()
86   {
87   }
88 };
89
90 class InstanceSkinChanged : public scene::Instantiable::Visitor
91 {
92 public:
93   void visit(scene::Instance& instance) const
94   {
95     //\todo don't do this for instances that are not children of the entity setting the skin
96     SkinnedModel* skinned = InstanceTypeCast<SkinnedModel>::cast(instance);
97     if(skinned != 0)
98     {
99       skinned->skinChanged();
100     }
101   }
102 };
103
104 inline void Node_modelSkinChanged(scene::Node& node)
105 {
106   scene::Instantiable* instantiable = Node_getInstantiable(node);
107   ASSERT_NOTNULL(instantiable);
108   instantiable->forEachInstance(InstanceSkinChanged());
109 }
110
111 #endif