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