]> git.xonotic.org Git - voretournament/voretournament.git/blob - misc/mediasource/netradiant-src/plugins/model/model.cpp
Move all other sources in a separate subfolder
[voretournament/voretournament.git] / misc / mediasource / netradiant-src / plugins / model / model.cpp
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 #include "model.h"
23
24 #include "picomodel.h"
25
26 #include "iarchive.h"
27 #include "idatastream.h"
28 #include "imodel.h"
29 #include "modelskin.h"
30
31 #include "cullable.h"
32 #include "renderable.h"
33 #include "selectable.h"
34
35 #include "math/frustum.h"
36 #include "string/string.h"
37 #include "generic/static.h"
38 #include "shaderlib.h"
39 #include "scenelib.h"
40 #include "instancelib.h"
41 #include "transformlib.h"
42 #include "traverselib.h"
43 #include "render.h"
44
45 class VectorLightList : public LightList
46 {
47   typedef std::vector<const RendererLight*> Lights;
48   Lights m_lights;
49 public:
50   void addLight(const RendererLight& light)
51   {
52     m_lights.push_back(&light);
53   }
54   void clear()
55   {
56     m_lights.clear();
57   }
58   void evaluateLights() const
59   {
60   }
61   void lightsChanged() const
62   {
63   }
64   void forEachLight(const RendererLightCallback& callback) const
65   {
66     for(Lights::const_iterator i = m_lights.begin(); i != m_lights.end(); ++i)
67     {
68       callback(*(*i));
69     }
70   }
71 };
72
73 class PicoSurface : 
74 public OpenGLRenderable
75 {
76   AABB m_aabb_local;
77   CopiedString m_shader;
78   Shader* m_state;
79
80   Array<ArbitraryMeshVertex> m_vertices;
81   Array<RenderIndex> m_indices;
82
83 public:
84
85   PicoSurface()
86   {
87     constructNull();
88     CaptureShader();
89   }
90   PicoSurface(picoSurface_t* surface)
91   {
92     CopyPicoSurface(surface);
93     CaptureShader();
94   }
95   ~PicoSurface()
96   {
97     ReleaseShader();
98   }
99
100   void render(RenderStateFlags state) const
101   {
102     if((state & RENDER_BUMP) != 0)
103     {
104       if(GlobalShaderCache().useShaderLanguage())
105       {
106         glNormalPointer(GL_FLOAT, sizeof(ArbitraryMeshVertex), &m_vertices.data()->normal);
107         glVertexAttribPointerARB(c_attr_TexCoord0, 2, GL_FLOAT, 0, sizeof(ArbitraryMeshVertex), &m_vertices.data()->texcoord);
108         glVertexAttribPointerARB(c_attr_Tangent, 3, GL_FLOAT, 0, sizeof(ArbitraryMeshVertex), &m_vertices.data()->tangent);
109         glVertexAttribPointerARB(c_attr_Binormal, 3, GL_FLOAT, 0, sizeof(ArbitraryMeshVertex), &m_vertices.data()->bitangent);
110       }
111       else
112       {
113         glVertexAttribPointerARB(11, 3, GL_FLOAT, 0, sizeof(ArbitraryMeshVertex), &m_vertices.data()->normal);
114         glVertexAttribPointerARB(8, 2, GL_FLOAT, 0, sizeof(ArbitraryMeshVertex), &m_vertices.data()->texcoord);
115         glVertexAttribPointerARB(9, 3, GL_FLOAT, 0, sizeof(ArbitraryMeshVertex), &m_vertices.data()->tangent);
116         glVertexAttribPointerARB(10, 3, GL_FLOAT, 0, sizeof(ArbitraryMeshVertex), &m_vertices.data()->bitangent);
117       }
118     }
119     else
120     {
121       glNormalPointer(GL_FLOAT, sizeof(ArbitraryMeshVertex), &m_vertices.data()->normal);
122       glTexCoordPointer(2, GL_FLOAT, sizeof(ArbitraryMeshVertex), &m_vertices.data()->texcoord);
123     }
124     glVertexPointer(3, GL_FLOAT, sizeof(ArbitraryMeshVertex), &m_vertices.data()->vertex);
125     glDrawElements(GL_TRIANGLES, GLsizei(m_indices.size()), RenderIndexTypeID, m_indices.data());
126
127 #if defined(_DEBUG)
128         GLfloat modelview[16];
129         glGetFloatv(GL_MODELVIEW_MATRIX, modelview); // I know this is slow as hell, but hey - we're in _DEBUG
130         Matrix4 modelview_inv(
131                 modelview[0], modelview[1], modelview[2], modelview[3],
132                 modelview[4], modelview[5], modelview[6], modelview[7],
133                 modelview[8], modelview[9], modelview[10], modelview[11],
134                 modelview[12], modelview[13], modelview[14], modelview[15]);
135         matrix4_full_invert(modelview_inv);
136         Matrix4 modelview_inv_transposed = matrix4_transposed(modelview_inv);
137
138     glBegin(GL_LINES);
139
140     for(Array<ArbitraryMeshVertex>::const_iterator i = m_vertices.begin(); i != m_vertices.end(); ++i)
141     {
142           Vector3 normal = normal3f_to_vector3((*i).normal);
143           normal = matrix4_transformed_direction(modelview_inv, vector3_normalised(matrix4_transformed_direction(modelview_inv_transposed, normal))); // do some magic
144       Vector3 normalTransformed = vector3_added(vertex3f_to_vector3((*i).vertex), vector3_scaled(normal, 8));
145       glVertex3fv(vertex3f_to_array((*i).vertex));
146       glVertex3fv(vector3_to_array(normalTransformed));
147     }
148     glEnd();
149 #endif
150   }
151
152   VolumeIntersectionValue intersectVolume(const VolumeTest& test, const Matrix4& localToWorld) const
153   {
154     return test.TestAABB(m_aabb_local, localToWorld);
155   }
156
157   const AABB& localAABB() const
158   {
159     return m_aabb_local;
160   }
161
162   void render(Renderer& renderer, const Matrix4& localToWorld, Shader* state) const
163   {
164     renderer.SetState(state, Renderer::eFullMaterials);
165     renderer.addRenderable(*this, localToWorld);
166   }
167
168   void render(Renderer& renderer, const Matrix4& localToWorld) const
169   {
170     render(renderer, localToWorld, m_state);
171   }
172
173   void testSelect(Selector& selector, SelectionTest& test, const Matrix4& localToWorld)
174   {
175     test.BeginMesh(localToWorld);
176
177     SelectionIntersection best;
178     testSelect(test, best);
179     if(best.valid())
180     {
181       selector.addIntersection(best);
182     }
183   }
184
185   const char* getShader() const
186   {
187     return m_shader.c_str();
188   }
189   Shader* getState() const
190   {
191     return m_state;
192   }
193
194 private:
195
196   void CaptureShader()
197   {
198     m_state = GlobalShaderCache().capture(m_shader.c_str());
199   }
200   void ReleaseShader()
201   {
202     GlobalShaderCache().release(m_shader.c_str());
203   }
204
205   void UpdateAABB()
206   {
207     m_aabb_local = AABB();
208     for(std::size_t i = 0; i < m_vertices.size(); ++i )
209       aabb_extend_by_point_safe(m_aabb_local, reinterpret_cast<const Vector3&>(m_vertices[i].vertex));
210
211
212     for(Array<RenderIndex>::iterator i = m_indices.begin(); i != m_indices.end(); i += 3)
213     {
214                         ArbitraryMeshVertex& a = m_vertices[*(i + 0)];
215                         ArbitraryMeshVertex& b = m_vertices[*(i + 1)];
216                         ArbitraryMeshVertex& c = m_vertices[*(i + 2)];
217
218       ArbitraryMeshTriangle_sumTangents(a, b, c);
219     }
220
221     for(Array<ArbitraryMeshVertex>::iterator i = m_vertices.begin(); i != m_vertices.end(); ++i)
222     {
223       vector3_normalise(reinterpret_cast<Vector3&>((*i).tangent));
224       vector3_normalise(reinterpret_cast<Vector3&>((*i).bitangent));
225     }
226   }
227
228   void testSelect(SelectionTest& test, SelectionIntersection& best)
229   {
230     test.TestTriangles(
231       VertexPointer(VertexPointer::pointer(&m_vertices.data()->vertex), sizeof(ArbitraryMeshVertex)),
232       IndexPointer(m_indices.data(), IndexPointer::index_type(m_indices.size())),
233       best
234     );
235   }
236
237   void CopyPicoSurface(picoSurface_t* surface)
238   {
239     picoShader_t* shader = PicoGetSurfaceShader( surface );
240     if( shader == 0 )
241       m_shader = "";
242     else
243       m_shader = PicoGetShaderName( shader );
244     
245     m_vertices.resize( PicoGetSurfaceNumVertexes( surface ) );  
246     m_indices.resize( PicoGetSurfaceNumIndexes( surface ) );
247     
248     for(std::size_t i = 0; i < m_vertices.size(); ++i )
249     {
250       picoVec_t* xyz = PicoGetSurfaceXYZ( surface, int(i) );
251       m_vertices[i].vertex = vertex3f_from_array(xyz);
252       
253       picoVec_t* normal = PicoGetSurfaceNormal( surface, int(i) );
254       m_vertices[i].normal = normal3f_from_array(normal);
255       
256       picoVec_t* st = PicoGetSurfaceST( surface, 0, int(i) );
257       m_vertices[i].texcoord = TexCoord2f(st[0], st[1]);
258       
259 #if 0
260       picoVec_t* color = PicoGetSurfaceColor( surface, 0, int(i) );
261       m_vertices[i].colour = Colour4b(color[0], color[1], color[2], color[3]);
262 #endif
263     }
264     
265     picoIndex_t* indexes = PicoGetSurfaceIndexes( surface, 0 );
266     for(std::size_t j = 0; j < m_indices.size(); ++j )
267       m_indices[ j ] = indexes[ j ];
268
269     UpdateAABB();
270   }
271
272   void constructQuad(std::size_t index, const Vector3& a, const Vector3& b, const Vector3& c, const Vector3& d, const Vector3& normal)
273   {
274     m_vertices[index * 4 + 0] = ArbitraryMeshVertex(
275       vertex3f_for_vector3(a),
276       normal3f_for_vector3(normal),
277       texcoord2f_from_array(aabb_texcoord_topleft)
278     );
279     m_vertices[index * 4 + 1] = ArbitraryMeshVertex(
280       vertex3f_for_vector3(b),
281       normal3f_for_vector3(normal),
282       texcoord2f_from_array(aabb_texcoord_topright)
283     );
284     m_vertices[index * 4 + 2] = ArbitraryMeshVertex(
285       vertex3f_for_vector3(c),
286       normal3f_for_vector3(normal),
287       texcoord2f_from_array(aabb_texcoord_botright)
288     );
289     m_vertices[index * 4 + 3] = ArbitraryMeshVertex(
290       vertex3f_for_vector3(d),
291       normal3f_for_vector3(normal),
292       texcoord2f_from_array(aabb_texcoord_botleft)
293     );
294   }
295
296   void constructNull()
297   {
298     AABB aabb(Vector3(0, 0, 0), Vector3(8, 8, 8));
299
300     Vector3 points[8];
301           aabb_corners(aabb, points);
302
303     m_vertices.resize(24);
304
305     constructQuad(0, points[2], points[1], points[5], points[6], aabb_normals[0]);
306     constructQuad(1, points[1], points[0], points[4], points[5], aabb_normals[1]);
307     constructQuad(2, points[0], points[1], points[2], points[3], aabb_normals[2]);
308     constructQuad(3, points[0], points[3], points[7], points[4], aabb_normals[3]);
309     constructQuad(4, points[3], points[2], points[6], points[7], aabb_normals[4]);
310     constructQuad(5, points[7], points[6], points[5], points[4], aabb_normals[5]);
311
312     m_indices.resize(36);
313
314     RenderIndex indices[36] = {
315       0,  1,  2,  0,  2,  3,
316       4,  5,  6,  4,  6,  7,
317       8,  9, 10,  8, 10, 11,
318       12, 13, 14, 12, 14, 15,
319       16, 17, 18, 16, 18, 19,
320       20, 21, 22, 10, 22, 23,
321     };
322
323
324     Array<RenderIndex>::iterator j = m_indices.begin();
325     for(RenderIndex* i = indices; i != indices+(sizeof(indices)/sizeof(RenderIndex)); ++i)
326     {
327       *j++ = *i;
328     }
329
330     m_shader = "";
331
332     UpdateAABB();
333   }
334 };
335
336
337 typedef std::pair<CopiedString, int> PicoModelKey;
338
339
340 class PicoModel :
341 public Cullable,
342 public Bounded
343 {
344   typedef std::vector<PicoSurface*> surfaces_t;
345   surfaces_t m_surfaces;
346
347   AABB m_aabb_local;
348 public:
349   Callback m_lightsChanged;
350
351   PicoModel()
352   {
353     constructNull();
354   }
355   PicoModel(picoModel_t* model)
356   {
357     CopyPicoModel(model);
358   }
359   ~PicoModel()
360   {
361     for(surfaces_t::iterator i = m_surfaces.begin(); i != m_surfaces.end(); ++i)
362       delete *i;
363   }
364
365   typedef surfaces_t::const_iterator const_iterator;
366
367   const_iterator begin() const
368   {
369     return m_surfaces.begin();
370   }
371   const_iterator end() const
372   {
373     return m_surfaces.end();
374   }
375   std::size_t size() const
376   {
377     return m_surfaces.size();
378   }
379
380   VolumeIntersectionValue intersectVolume(const VolumeTest& test, const Matrix4& localToWorld) const
381   {
382     return test.TestAABB(m_aabb_local, localToWorld);
383   }
384
385   virtual const AABB& localAABB() const
386   {
387     return m_aabb_local;
388   }
389
390   void render(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld, std::vector<Shader*> states) const
391   {
392     for(surfaces_t::const_iterator i = m_surfaces.begin(); i != m_surfaces.end(); ++i)
393     {
394       if((*i)->intersectVolume(volume, localToWorld) != c_volumeOutside)
395       {
396         (*i)->render(renderer, localToWorld, states[i - m_surfaces.begin()]);
397       }
398     }
399   }
400
401   void testSelect(Selector& selector, SelectionTest& test, const Matrix4& localToWorld)
402   {
403     for(surfaces_t::iterator i = m_surfaces.begin(); i != m_surfaces.end(); ++i)
404     {
405       if((*i)->intersectVolume(test.getVolume(), localToWorld) != c_volumeOutside)
406       {
407         (*i)->testSelect(selector, test, localToWorld);
408       }
409     }
410   }
411
412 private:
413   void CopyPicoModel(picoModel_t* model)
414   {
415     m_aabb_local = AABB();
416
417     /* each surface on the model will become a new map drawsurface */
418     int numSurfaces = PicoGetModelNumSurfaces( model );
419     //%  SYs_FPrintf( SYS_VRB, "Model %s has %d surfaces\n", name, numSurfaces );
420     for(int s = 0; s < numSurfaces; ++s)
421     {
422       /* get surface */
423       picoSurface_t* surface = PicoGetModelSurface( model, s );
424       if( surface == 0 )
425         continue;
426       
427       /* only handle triangle surfaces initially (fixme: support patches) */
428       if( PicoGetSurfaceType( surface ) != PICO_TRIANGLES )
429         continue;
430       
431       /* fix the surface's normals */
432       PicoFixSurfaceNormals( surface );
433       
434       PicoSurface* picosurface = new PicoSurface(surface);
435       aabb_extend_by_aabb_safe(m_aabb_local, picosurface->localAABB());
436       m_surfaces.push_back(picosurface);
437     }
438   }
439   void constructNull()
440   {
441     PicoSurface* picosurface = new PicoSurface();
442     m_aabb_local = picosurface->localAABB();
443     m_surfaces.push_back(picosurface);
444   }
445 };
446
447 inline void Surface_addLight(PicoSurface& surface, VectorLightList& lights, const Matrix4& localToWorld, const RendererLight& light)
448 {
449   if(light.testAABB(aabb_for_oriented_aabb(surface.localAABB(), localToWorld)))
450   {
451     lights.addLight(light);
452   }
453 }
454
455 class PicoModelInstance :
456   public scene::Instance,
457   public Renderable,
458   public SelectionTestable,
459   public LightCullable,
460   public SkinnedModel
461 {
462   class TypeCasts
463   {
464     InstanceTypeCastTable m_casts;
465   public:
466     TypeCasts()
467     {
468       InstanceContainedCast<PicoModelInstance, Bounded>::install(m_casts);
469       InstanceContainedCast<PicoModelInstance, Cullable>::install(m_casts);
470       InstanceStaticCast<PicoModelInstance, Renderable>::install(m_casts);
471       InstanceStaticCast<PicoModelInstance, SelectionTestable>::install(m_casts);
472       InstanceStaticCast<PicoModelInstance, SkinnedModel>::install(m_casts);
473     }
474     InstanceTypeCastTable& get()
475     {
476       return m_casts;
477     }
478   };
479
480   PicoModel& m_picomodel;
481
482   const LightList* m_lightList;
483   typedef Array<VectorLightList> SurfaceLightLists;
484   SurfaceLightLists m_surfaceLightLists;
485
486   class Remap
487   {
488   public:
489     CopiedString first;
490     Shader* second;
491     Remap() : second(0)
492     {
493     }
494   };
495   typedef Array<Remap> SurfaceRemaps;
496   SurfaceRemaps m_skins;
497
498   PicoModelInstance(const PicoModelInstance&);
499   PicoModelInstance operator=(const PicoModelInstance&);
500 public:
501   typedef LazyStatic<TypeCasts> StaticTypeCasts;
502
503   void* m_test;
504
505   Bounded& get(NullType<Bounded>)
506   {
507     return m_picomodel;
508   }
509   Cullable& get(NullType<Cullable>)
510   {
511     return m_picomodel;
512   }
513
514   void lightsChanged()
515   {
516     m_lightList->lightsChanged();
517   }
518   typedef MemberCaller<PicoModelInstance, &PicoModelInstance::lightsChanged> LightsChangedCaller;
519
520   void constructRemaps()
521   {
522     ASSERT_MESSAGE(m_skins.size() == m_picomodel.size(), "ERROR");
523     ModelSkin* skin = NodeTypeCast<ModelSkin>::cast(path().parent());
524     if(skin != 0 && skin->realised())
525     {
526       SurfaceRemaps::iterator j = m_skins.begin();
527       for(PicoModel::const_iterator i = m_picomodel.begin(); i != m_picomodel.end(); ++i, ++j)
528       {
529         const char* remap = skin->getRemap((*i)->getShader());
530         if(!string_empty(remap))
531         {
532           (*j).first = remap;
533           (*j).second = GlobalShaderCache().capture(remap);
534         }
535         else
536         {
537           (*j).second = 0;
538         }
539       }
540       SceneChangeNotify();
541     }
542   }
543   void destroyRemaps()
544   {
545     ASSERT_MESSAGE(m_skins.size() == m_picomodel.size(), "ERROR");
546     for(SurfaceRemaps::iterator i = m_skins.begin(); i != m_skins.end(); ++i)
547     {
548       if((*i).second != 0)
549       {
550         GlobalShaderCache().release((*i).first.c_str());
551         (*i).second = 0;
552       }
553     }
554   }
555   void skinChanged()
556   {
557     destroyRemaps();
558     constructRemaps();
559   }
560
561   PicoModelInstance(const scene::Path& path, scene::Instance* parent, PicoModel& picomodel) :
562     Instance(path, parent, this, StaticTypeCasts::instance().get()),
563     m_picomodel(picomodel),
564     m_surfaceLightLists(m_picomodel.size()),
565     m_skins(m_picomodel.size())
566   {
567     m_lightList = &GlobalShaderCache().attach(*this);
568     m_picomodel.m_lightsChanged = LightsChangedCaller(*this);
569
570     Instance::setTransformChangedCallback(LightsChangedCaller(*this));
571
572     constructRemaps();
573   }
574   ~PicoModelInstance()
575   {
576     destroyRemaps();
577
578     Instance::setTransformChangedCallback(Callback());
579
580     m_picomodel.m_lightsChanged = Callback();
581     GlobalShaderCache().detach(*this);
582   }
583
584   void render(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld) const
585   {
586     SurfaceLightLists::const_iterator j = m_surfaceLightLists.begin();
587     SurfaceRemaps::const_iterator k = m_skins.begin();
588     for(PicoModel::const_iterator i = m_picomodel.begin(); i != m_picomodel.end(); ++i, ++j, ++k)
589     {
590       if((*i)->intersectVolume(volume, localToWorld) != c_volumeOutside)
591       {
592         renderer.setLights(*j);
593         (*i)->render(renderer, localToWorld, (*k).second != 0 ? (*k).second : (*i)->getState());
594       }
595     }
596   }
597
598   void renderSolid(Renderer& renderer, const VolumeTest& volume) const
599   {
600     m_lightList->evaluateLights();
601
602     render(renderer, volume, Instance::localToWorld());
603   }
604   void renderWireframe(Renderer& renderer, const VolumeTest& volume) const
605   {
606     renderSolid(renderer, volume);
607   }
608
609   void testSelect(Selector& selector, SelectionTest& test)
610   {
611     m_picomodel.testSelect(selector, test, Instance::localToWorld());
612   }
613
614   bool testLight(const RendererLight& light) const
615   {
616     return light.testAABB(worldAABB());
617   }
618   void insertLight(const RendererLight& light)
619   {
620     const Matrix4& localToWorld = Instance::localToWorld();
621     SurfaceLightLists::iterator j = m_surfaceLightLists.begin();
622     for(PicoModel::const_iterator i = m_picomodel.begin(); i != m_picomodel.end(); ++i)
623     {
624       Surface_addLight(*(*i), *j++, localToWorld, light);
625     }
626   }
627   void clearLights()
628   {
629     for(SurfaceLightLists::iterator i = m_surfaceLightLists.begin(); i != m_surfaceLightLists.end(); ++i)
630     {
631       (*i).clear();
632     }
633   }
634 };
635
636 class PicoModelNode : public scene::Node::Symbiot, public scene::Instantiable
637 {
638   class TypeCasts
639   {
640     NodeTypeCastTable m_casts;
641   public:
642     TypeCasts()
643     {
644       NodeStaticCast<PicoModelNode, scene::Instantiable>::install(m_casts);
645     }
646     NodeTypeCastTable& get()
647     {
648       return m_casts;
649     }
650   };
651
652
653   scene::Node m_node;
654   InstanceSet m_instances;
655   PicoModel m_picomodel;
656
657 public:
658   typedef LazyStatic<TypeCasts> StaticTypeCasts;
659
660   PicoModelNode() : m_node(this, this, StaticTypeCasts::instance().get())
661   {
662   }
663   PicoModelNode(picoModel_t* model) : m_node(this, this, StaticTypeCasts::instance().get()), m_picomodel(model)
664   {
665   }
666
667   void release()
668   {
669     delete this;
670   }
671   scene::Node& node()
672   {
673     return m_node;
674   }
675
676   scene::Instance* create(const scene::Path& path, scene::Instance* parent)
677   {
678     return new PicoModelInstance(path, parent, m_picomodel);
679   }
680   void forEachInstance(const scene::Instantiable::Visitor& visitor)
681   {
682     m_instances.forEachInstance(visitor);
683   }
684   void insert(scene::Instantiable::Observer* observer, const scene::Path& path, scene::Instance* instance)
685   {
686     m_instances.insert(observer, path, instance);
687   }
688   scene::Instance* erase(scene::Instantiable::Observer* observer, const scene::Path& path)
689   {
690     return m_instances.erase(observer, path);
691   }
692 };
693
694
695 #if 0
696
697 template<typename Key, typename Type>
698 class create_new
699 {
700 public:
701   static Type* construct(const Key& key)
702   {
703     return new Type(key);
704   }
705   static void destroy(Type* value)
706   {
707     delete value;
708   }
709 };
710
711 template<typename Key, typename Type, typename creation_policy = create_new<Key, Type> >
712 class cache_element : public creation_policy
713 {
714 public:
715   inline cache_element() : m_count(0), m_value(0) {}
716   inline ~cache_element()
717   {
718     ASSERT_MESSAGE(m_count == 0 , "destroyed a reference before it was released\n");
719     if(m_count > 0)
720       destroy();
721   }
722   inline Type* capture(const Key& key)
723   {
724     if(++m_count == 1)
725       construct(key);
726     return m_value;
727   }
728   inline void release()
729   {
730     ASSERT_MESSAGE(!empty(), "failed to release reference - not found in cache\n");
731     if(--m_count == 0)
732       destroy();
733   }
734   inline bool empty()
735   {
736     return m_count == 0;
737   }
738   inline void refresh(const Key& key)
739   {
740     m_value->refresh(key);
741   }
742 private:
743   inline void construct(const Key& key)
744   {
745     m_value = creation_policy::construct(key);
746   }
747   inline void destroy()
748   {
749     creation_policy::destroy(m_value);
750   }
751
752   std::size_t m_count;
753   Type* m_value;
754 };
755
756 class create_picomodel
757 {
758   typedef PicoModelKey key_type;
759   typedef PicoModel value_type;
760 public:
761   static value_type* construct(const key_type& key)
762   {
763     picoModel_t* picomodel = PicoLoadModel(const_cast<char*>(key.first.c_str()), key.second);
764     value_type* value = new value_type(picomodel);
765     PicoFreeModel(picomodel);
766     return value;
767   }
768   static void destroy(value_type* value)
769   {
770     delete value;
771   }
772 };
773
774 #include <map>
775
776 class ModelCache
777 {
778   typedef PicoModel value_type;
779   
780 public:
781   typedef PicoModelKey key_type;
782   typedef cache_element<key_type, value_type, create_picomodel> elem_type;
783   typedef std::map<key_type, elem_type> cache_type;
784   
785   value_type* capture(const key_type& key)
786   {
787     return m_cache[key].capture(key);
788   }
789   void release(const key_type& key)
790   {
791     m_cache[key].release();
792   }
793
794 private:
795   cache_type m_cache;
796 };
797
798 ModelCache g_model_cache;
799
800
801
802 typedef struct remap_s {
803   char m_remapbuff[64+1024];
804   char *original;
805   char *remap;
806 } remap_t;
807
808 class RemapWrapper :
809 public Cullable,
810 public Bounded
811 {
812 public:
813   RemapWrapper(const char* name)
814   {
815     parse_namestr(name);
816
817     m_model = g_model_cache.capture(ModelCache::key_type(m_name, m_frame));
818
819     construct_shaders();
820   }
821   virtual ~RemapWrapper()
822   {
823     g_model_cache.release(ModelCache::key_type(m_name, m_frame));
824
825     for(shaders_t::iterator i = m_shaders.begin(); i != m_shaders.end(); ++i)
826     {
827       GlobalShaderCache().release((*i).c_str());
828     }
829
830     for(remaps_t::iterator j = m_remaps.begin(); j != m_remaps.end(); ++j)
831     {
832       delete (*j);
833     }
834   }
835
836   VolumeIntersectionValue intersectVolume(const VolumeTest& test, const Matrix4& localToWorld) const
837   {
838     return m_model->intersectVolume(test, localToWorld);
839   }
840
841   virtual const AABB& localAABB() const
842   {
843     return m_model->localAABB();
844   }
845
846   void render(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld) const
847   {
848     m_model->render(renderer, volume, localToWorld, m_states);
849   }
850
851   void testSelect(Selector& selector, SelectionTest& test, const Matrix4& localToWorld)
852   {
853     m_model->testSelect(selector, test, localToWorld);
854   }
855
856 private:
857   void add_remap(const char *remap)
858   {
859     const char *ch;
860     remap_t *pRemap;
861
862     ch = remap;
863
864     while( *ch && *ch != ';' )
865       ch++;
866
867     if( *ch == '\0' ) {
868       // bad remap
869       globalErrorStream() << "WARNING: Shader _remap key found in a model entity without a ; character\n";
870     } else {
871       pRemap = new remap_t;
872
873       strncpy( pRemap->m_remapbuff, remap, sizeof(pRemap->m_remapbuff) );
874
875       pRemap->m_remapbuff[ch - remap] = '\0';
876
877       pRemap->original = pRemap->m_remapbuff;
878       pRemap->remap = pRemap->m_remapbuff + ( ch - remap ) + 1;
879
880       m_remaps.push_back( pRemap );
881     }
882   }
883
884   void parse_namestr(const char *name)
885   {
886     const char *ptr, *s;
887     bool hasName, hasFrame;
888
889     hasName = hasFrame = false;
890
891     m_frame = 0;
892
893     for( s = ptr = name; ; ++ptr )
894     {
895       if( !hasName && (*ptr == ':' || *ptr == '\0'))
896       {
897         // model name
898         hasName = true;
899         m_name = CopiedString(s, ptr);
900         s = ptr + 1;
901       }
902       else if(*ptr == '?' || *ptr == '\0')
903       {
904         // model frame
905         hasFrame = true;
906         m_frame = atoi(CopiedString(s, ptr).c_str());
907         s = ptr + 1;
908       }
909       else if(*ptr == '&' || *ptr == '\0') 
910       {
911         // a remap
912         add_remap(CopiedString(s, ptr).c_str());
913         s = ptr + 1;
914       }
915
916       if(*ptr == '\0')
917         break; 
918     }
919   }
920
921   void construct_shaders()
922   {
923     const char* global_shader = shader_for_remap("*");
924
925     m_shaders.reserve(m_model->size());
926     m_states.reserve(m_model->size());
927     for(PicoModel::iterator i = m_model->begin(); i != m_model->end(); ++i)
928     {
929       const char* shader = shader_for_remap((*i)->getShader());
930       m_shaders.push_back(
931         (shader[0] != '\0')
932         ? shader
933         : (global_shader[0] != '\0')
934           ? global_shader
935           : (*i)->getShader());
936       m_states.push_back(GlobalShaderCache().capture(m_shaders.back().c_str()));
937     }
938   }
939   
940   inline const char* shader_for_remap(const char* remap)
941   {
942     for(remaps_t::iterator i = m_remaps.begin(); i != m_remaps.end(); ++i)
943     {
944       if(shader_equal(remap, (*i)->original))
945       {
946         return (*i)->remap;
947       }
948     }
949     return "";
950   }
951
952   CopiedString m_name;
953   int m_frame;
954   PicoModel* m_model;
955
956   typedef std::vector<remap_t*> remaps_t;
957   remaps_t m_remaps;
958   typedef std::vector<CopiedString> shaders_t;
959   shaders_t m_shaders;
960   typedef std::vector<Shader*> states_t;
961   states_t m_states;
962 };
963
964 class RemapWrapperInstance : public scene::Instance, public Renderable, public SelectionTestable
965 {
966   RemapWrapper& m_remapwrapper;
967 public:
968   RemapWrapperInstance(const scene::Path& path, scene::Instance* parent, RemapWrapper& remapwrapper) : Instance(path, parent), m_remapwrapper(remapwrapper)
969   {
970     scene::Instance::m_cullable = &m_remapwrapper;
971     scene::Instance::m_render = this;
972     scene::Instance::m_select = this;
973   }
974
975   void renderSolid(Renderer& renderer, const VolumeTest& volume) const
976   {
977     m_remapwrapper.render(renderer, volume, Instance::localToWorld());
978   }
979   void renderWireframe(Renderer& renderer, const VolumeTest& volume) const
980   {
981     renderSolid(renderer, volume);
982   }
983
984   void testSelect(Selector& selector, SelectionTest& test)
985   {
986     m_remapwrapper.testSelect(selector, test, Instance::localToWorld());
987   }
988 };
989
990 class RemapWrapperNode : public scene::Node::Symbiot, public scene::Instantiable
991 {
992   scene::Node m_node;
993   typedef RemapWrapperInstance instance_type;
994   InstanceSet m_instances;
995   RemapWrapper m_remapwrapper;
996 public:
997   RemapWrapperNode(const char* name) : m_node(this), m_remapwrapper(name)
998   {
999     m_node.m_instance = this;
1000   }
1001
1002   void release()
1003   {
1004     delete this;
1005   }
1006   scene::Node& node()
1007   {
1008     return m_node;
1009   }
1010
1011   scene::Instance* create(const scene::Path& path, scene::Instance* parent)
1012   {
1013     return new instance_type(path, parent, m_remapwrapper);
1014   }
1015   void forEachInstance(const scene::Instantiable::Visitor& visitor)
1016   {
1017     m_instances.forEachInstance(visitor);
1018   }
1019   void insert(scene::Instantiable::Observer* observer, const scene::Path& path, scene::Instance* instance)
1020   {
1021     m_instances.insert(observer, path, instance);
1022   }
1023   scene::Instance* erase(scene::Instantiable::Observer* observer, const scene::Path& path)
1024   {
1025     return m_instances.erase(observer, path);
1026   }
1027 };
1028
1029 scene::Node& LoadRemapModel(const char* name)
1030 {
1031   return (new RemapWrapperNode(name))->node();
1032 }
1033
1034 #endif
1035
1036
1037 size_t picoInputStreamReam(void* inputStream, unsigned char* buffer, size_t length)
1038 {
1039   return reinterpret_cast<InputStream*>(inputStream)->read(buffer, length);
1040 }
1041
1042 scene::Node& loadPicoModel(const picoModule_t* module, ArchiveFile& file)
1043 {
1044   picoModel_t* model = PicoModuleLoadModelStream(module, &file.getInputStream(), picoInputStreamReam, file.size(), 0, file.getName());
1045   PicoModelNode* modelNode = new PicoModelNode(model);
1046   PicoFreeModel(model);
1047   return modelNode->node();
1048 }