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