]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - plugins/md3model/model.h
added buffering to minimise GtkTextBuffer insert calls
[xonotic/netradiant.git] / plugins / md3model / model.h
1 /*
2 Copyright (C) 2001-2006, William Joseph.
3 All Rights Reserved.
4
5 This file is part of GtkRadiant.
6
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20 */
21
22 #if !defined(INCLUDED_MODEL_H)
23 #define INCLUDED_MODEL_H
24
25 #include "cullable.h"
26 #include "renderable.h"
27 #include "selectable.h"
28 #include "modelskin.h"
29
30 #include "math/frustum.h"
31 #include "string/string.h"
32 #include "generic/static.h"
33 #include "stream/stringstream.h"
34 #include "os/path.h"
35 #include "scenelib.h"
36 #include "instancelib.h"
37 #include "transformlib.h"
38 #include "traverselib.h"
39 #include "render.h"
40
41 class VectorLightList : public LightList
42 {
43   typedef std::vector<const RendererLight*> Lights;
44   Lights m_lights;
45 public:
46   void addLight(const RendererLight& light)
47   {
48     m_lights.push_back(&light);
49   }
50   void clear()
51   {
52     m_lights.clear();
53   }
54   void evaluateLights() const
55   {
56   }
57   void lightsChanged() const
58   {
59   }
60   void forEachLight(const RendererLightCallback& callback) const
61   {
62     for(Lights::const_iterator i = m_lights.begin(); i != m_lights.end(); ++i)
63     {
64       callback(*(*i));
65     }
66   }
67 };
68
69 inline VertexPointer vertexpointer_arbitrarymeshvertex(const ArbitraryMeshVertex* array)
70 {
71   return VertexPointer(VertexPointer::pointer(&array->vertex), sizeof(ArbitraryMeshVertex));
72 }
73
74 inline void parseTextureName(CopiedString& name, const char* token)
75 {
76   StringOutputStream cleaned(256);
77   cleaned << PathCleaned(token);
78   name = CopiedString(cleaned.c_str(), path_get_filename_base_end(cleaned.c_str())); // remove extension
79 }
80
81 // generic renderable triangle surface
82 class Surface : 
83 public OpenGLRenderable
84 {
85 public:
86   typedef VertexBuffer<ArbitraryMeshVertex> vertices_t;
87   typedef IndexBuffer indices_t;
88 private:
89
90   AABB m_aabb_local;
91   CopiedString m_shader;
92   Shader* m_state;
93
94   vertices_t m_vertices;
95   indices_t m_indices;
96
97   void CaptureShader()
98   {
99     m_state = GlobalShaderCache().capture(m_shader.c_str());
100   }
101   void ReleaseShader()
102   {
103     GlobalShaderCache().release(m_shader.c_str());
104   }
105
106 public:
107
108   Surface()
109     : m_shader(""), m_state(0)
110   {
111     CaptureShader();
112   }
113   ~Surface()
114   {
115     ReleaseShader();
116   }
117
118   vertices_t& vertices()
119   {
120     return m_vertices;
121   }
122   indices_t& indices()
123   {
124     return m_indices;
125   }
126
127   void setShader(const char* name)
128   {
129     ReleaseShader();
130     parseTextureName(m_shader, name);
131     CaptureShader();
132   }
133   const char* getShader() const
134   {
135     return m_shader.c_str();
136   }
137   Shader* getState() const
138   {
139     return m_state;
140   }
141   void updateAABB()
142   {
143     m_aabb_local = AABB();
144     for(vertices_t::iterator i = m_vertices.begin(); i != m_vertices.end(); ++i)
145       aabb_extend_by_point_safe(m_aabb_local, reinterpret_cast<const Vector3&>((*i).vertex));
146
147
148
149     for(Surface::indices_t::iterator i = m_indices.begin(); i != m_indices.end(); i += 3)
150     {
151                         ArbitraryMeshVertex& a = m_vertices[*(i + 0)];
152                         ArbitraryMeshVertex& b = m_vertices[*(i + 1)];
153                         ArbitraryMeshVertex& c = m_vertices[*(i + 2)];
154
155       ArbitraryMeshTriangle_sumTangents(a, b, c);
156     }
157
158     for(Surface::vertices_t::iterator i = m_vertices.begin(); i != m_vertices.end(); ++i)
159     {
160       vector3_normalise(reinterpret_cast<Vector3&>((*i).tangent));
161       vector3_normalise(reinterpret_cast<Vector3&>((*i).bitangent));
162     }
163   }
164
165   void render(RenderStateFlags state) const
166   {
167 #if 1
168     if((state & RENDER_BUMP) != 0)
169     {
170       if(GlobalShaderCache().useShaderLanguage())
171       {
172         glNormalPointer(GL_FLOAT, sizeof(ArbitraryMeshVertex), &m_vertices.data()->normal);
173         glVertexAttribPointerARB(c_attr_TexCoord0, 2, GL_FLOAT, 0, sizeof(ArbitraryMeshVertex), &m_vertices.data()->texcoord);
174         glVertexAttribPointerARB(c_attr_Tangent, 3, GL_FLOAT, 0, sizeof(ArbitraryMeshVertex), &m_vertices.data()->tangent);
175         glVertexAttribPointerARB(c_attr_Binormal, 3, GL_FLOAT, 0, sizeof(ArbitraryMeshVertex), &m_vertices.data()->bitangent);
176       }
177       else
178       {
179         glVertexAttribPointerARB(11, 3, GL_FLOAT, 0, sizeof(ArbitraryMeshVertex), &m_vertices.data()->normal);
180         glVertexAttribPointerARB(8, 2, GL_FLOAT, 0, sizeof(ArbitraryMeshVertex), &m_vertices.data()->texcoord);
181         glVertexAttribPointerARB(9, 3, GL_FLOAT, 0, sizeof(ArbitraryMeshVertex), &m_vertices.data()->tangent);
182         glVertexAttribPointerARB(10, 3, GL_FLOAT, 0, sizeof(ArbitraryMeshVertex), &m_vertices.data()->bitangent);
183       }
184     }
185     else
186     {
187       glNormalPointer(GL_FLOAT, sizeof(ArbitraryMeshVertex), &m_vertices.data()->normal);
188       glTexCoordPointer(2, GL_FLOAT, sizeof(ArbitraryMeshVertex), &m_vertices.data()->texcoord);
189     }
190     glVertexPointer(3, GL_FLOAT, sizeof(ArbitraryMeshVertex), &m_vertices.data()->vertex);
191     glDrawElements(GL_TRIANGLES, GLsizei(m_indices.size()), RenderIndexTypeID, m_indices.data());
192 #else
193     glBegin(GL_TRIANGLES);
194     for(unsigned int i = 0; i < m_indices.size(); ++i)
195     {
196       glTexCoord2fv(&m_vertices[m_indices[i]].texcoord.s);
197       glNormal3fv(&m_vertices[m_indices[i]].normal.x);
198       glVertex3fv(&m_vertices[m_indices[i]].vertex.x);
199     }
200     glEnd();
201 #endif
202
203 #if defined(_DEBUG)
204     glBegin(GL_LINES);
205
206     for(VertexBuffer<ArbitraryMeshVertex>::const_iterator i = m_vertices.begin(); i != m_vertices.end(); ++i)
207     {
208       Vector3 normal = vector3_added(vertex3f_to_vector3((*i).vertex), vector3_scaled(normal3f_to_vector3((*i).normal), 8));
209       glVertex3fv(vertex3f_to_array((*i).vertex));
210       glVertex3fv(vector3_to_array(normal));
211     }
212     glEnd();
213 #endif
214   }
215
216   VolumeIntersectionValue intersectVolume(const VolumeTest& test, const Matrix4& localToWorld) const
217   {
218     return test.TestAABB(m_aabb_local, localToWorld);
219   }
220
221   const AABB& localAABB() const
222   {
223     return m_aabb_local;
224   }
225
226   void render(Renderer& renderer, const Matrix4& localToWorld, Shader* state) const
227   {
228     renderer.SetState(state, Renderer::eFullMaterials);
229     renderer.addRenderable(*this, localToWorld);
230   }
231
232   void render(Renderer& renderer, const Matrix4& localToWorld) const
233   {
234     render(renderer, localToWorld, m_state);
235   }
236
237   void testSelect(Selector& selector, SelectionTest& test, const Matrix4& localToWorld)
238   {
239     test.BeginMesh(localToWorld);
240
241     SelectionIntersection best;
242     test.TestTriangles(
243       vertexpointer_arbitrarymeshvertex(m_vertices.data()),
244       IndexPointer(m_indices.data(), IndexPointer::index_type(m_indices.size())),
245       best
246     );
247     if(best.valid())
248     {
249       selector.addIntersection(best);
250     }
251   }
252 };
253
254 // generic model node
255 class Model :
256 public Cullable,
257 public Bounded
258 {
259   typedef std::vector<Surface*> surfaces_t;
260   surfaces_t m_surfaces;
261
262   AABB m_aabb_local;
263 public:
264   Callback m_lightsChanged;
265
266   ~Model()
267   {
268     for(surfaces_t::iterator i = m_surfaces.begin(); i != m_surfaces.end(); ++i)
269     {
270       delete *i;
271     }
272   }
273
274   typedef surfaces_t::const_iterator const_iterator;
275
276   const_iterator begin() const
277   {
278     return m_surfaces.begin();
279   }
280   const_iterator end() const
281   {
282     return m_surfaces.end();
283   }
284   std::size_t size() const
285   {
286     return m_surfaces.size();
287   }
288
289   Surface& newSurface()
290   {
291     m_surfaces.push_back(new Surface);
292     return *m_surfaces.back();
293   }
294   void updateAABB()
295   {
296     m_aabb_local = AABB();
297     for(surfaces_t::iterator i = m_surfaces.begin(); i != m_surfaces.end(); ++i)
298     {
299       aabb_extend_by_aabb_safe(m_aabb_local, (*i)->localAABB());
300     }
301   }
302
303   VolumeIntersectionValue intersectVolume(const VolumeTest& test, const Matrix4& localToWorld) const
304   {
305     return test.TestAABB(m_aabb_local, localToWorld);
306   }
307
308   virtual const AABB& localAABB() const
309   {
310     return m_aabb_local;
311   }
312
313   void testSelect(Selector& selector, SelectionTest& test, const Matrix4& localToWorld)
314   {
315     for(surfaces_t::iterator i = m_surfaces.begin(); i != m_surfaces.end(); ++i)
316     {
317       if((*i)->intersectVolume(test.getVolume(), localToWorld) != c_volumeOutside)
318       {
319         (*i)->testSelect(selector, test, localToWorld);
320       }
321     }
322   }
323 };
324
325 inline void Surface_addLight(const Surface& surface, VectorLightList& lights, const Matrix4& localToWorld, const RendererLight& light)
326 {
327   if(light.testAABB(aabb_for_oriented_aabb(surface.localAABB(), localToWorld)))
328   {
329     lights.addLight(light);
330   }
331 }
332
333 class ModelInstance :
334   public scene::Instance,
335   public Renderable,
336   public SelectionTestable,
337   public LightCullable,
338   public SkinnedModel
339 {
340   class TypeCasts
341   {
342     InstanceTypeCastTable m_casts;
343   public:
344     TypeCasts()
345     {
346       InstanceContainedCast<ModelInstance, Bounded>::install(m_casts);
347       InstanceContainedCast<ModelInstance, Cullable>::install(m_casts);
348       InstanceStaticCast<ModelInstance, Renderable>::install(m_casts);
349       InstanceStaticCast<ModelInstance, SelectionTestable>::install(m_casts);
350       InstanceStaticCast<ModelInstance, SkinnedModel>::install(m_casts);
351     }
352     InstanceTypeCastTable& get()
353     {
354       return m_casts;
355     }
356   };
357
358   Model& m_model;
359
360   const LightList* m_lightList;
361   typedef Array<VectorLightList> SurfaceLightLists;
362   SurfaceLightLists m_surfaceLightLists;
363
364   class Remap
365   {
366   public:
367     CopiedString first;
368     Shader* second;
369     Remap() : second(0)
370     {
371     }
372   };
373   typedef Array<Remap> SurfaceRemaps;
374   SurfaceRemaps m_skins;
375 public:
376
377   typedef LazyStatic<TypeCasts> StaticTypeCasts;
378
379   Bounded& get(NullType<Bounded>)
380   {
381     return m_model;
382   }
383   Cullable& get(NullType<Cullable>)
384   {
385     return m_model;
386   }
387
388   void lightsChanged()
389   {
390     m_lightList->lightsChanged();
391   }
392   typedef MemberCaller<ModelInstance, &ModelInstance::lightsChanged> LightsChangedCaller;
393
394   void constructRemaps()
395   {
396     ModelSkin* skin = NodeTypeCast<ModelSkin>::cast(path().parent());
397     if(skin != 0 && skin->realised())
398     {
399       SurfaceRemaps::iterator j = m_skins.begin();
400       for(Model::const_iterator i = m_model.begin(); i != m_model.end(); ++i, ++j)
401       {
402         const char* remap = skin->getRemap((*i)->getShader());
403         if(!string_empty(remap))
404         {
405           (*j).first = remap;
406           (*j).second = GlobalShaderCache().capture(remap);
407         }
408         else
409         {
410           (*j).second = 0;
411         }
412       }
413       SceneChangeNotify();
414     }
415   }
416   void destroyRemaps()
417   {
418     for(SurfaceRemaps::iterator i = m_skins.begin(); i != m_skins.end(); ++i)
419     {
420       if((*i).second != 0)
421       {
422         GlobalShaderCache().release((*i).first.c_str());
423         (*i).second = 0;
424       }
425     }
426   }
427   void skinChanged()
428   {
429     ASSERT_MESSAGE(m_skins.size() == m_model.size(), "ERROR");
430     destroyRemaps();
431     constructRemaps();
432   }
433
434   ModelInstance(const scene::Path& path, scene::Instance* parent, Model& model) :
435     Instance(path, parent, this, StaticTypeCasts::instance().get()), 
436     m_model(model),
437     m_surfaceLightLists(m_model.size()),
438     m_skins(m_model.size())
439   {
440     m_lightList = &GlobalShaderCache().attach(*this);
441     m_model.m_lightsChanged = LightsChangedCaller(*this);
442
443     Instance::setTransformChangedCallback(LightsChangedCaller(*this));
444
445     constructRemaps();
446   }
447   ~ModelInstance()
448   {
449     destroyRemaps();
450
451     Instance::setTransformChangedCallback(Callback());
452
453     m_model.m_lightsChanged = Callback();
454     GlobalShaderCache().detach(*this);
455   }
456
457   void render(Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld) const
458   {
459     SurfaceLightLists::const_iterator j = m_surfaceLightLists.begin();
460     SurfaceRemaps::const_iterator k = m_skins.begin();
461     for(Model::const_iterator i = m_model.begin(); i != m_model.end(); ++i, ++j, ++k)
462     {
463       if((*i)->intersectVolume(volume, localToWorld) != c_volumeOutside)
464       {
465         renderer.setLights(*j);
466         (*i)->render(renderer, localToWorld, (*k).second != 0 ? (*k).second : (*i)->getState());
467       }
468     }
469   }
470
471   void renderSolid(Renderer& renderer, const VolumeTest& volume) const
472   {
473     m_lightList->evaluateLights();
474
475     render(renderer, volume, Instance::localToWorld());
476   }
477   void renderWireframe(Renderer& renderer, const VolumeTest& volume) const
478   {
479     renderSolid(renderer, volume);
480   }
481
482   void testSelect(Selector& selector, SelectionTest& test)
483   {
484     m_model.testSelect(selector, test, Instance::localToWorld());
485   }
486
487   bool testLight(const RendererLight& light) const
488   {
489     return light.testAABB(worldAABB());
490   }
491   void insertLight(const RendererLight& light)
492   {
493     const Matrix4& localToWorld = Instance::localToWorld();
494     SurfaceLightLists::iterator j = m_surfaceLightLists.begin();
495     for(Model::const_iterator i = m_model.begin(); i != m_model.end(); ++i)
496     {
497       Surface_addLight(*(*i), *j++, localToWorld, light);
498     }
499   }
500   void clearLights()
501   {
502     for(SurfaceLightLists::iterator i = m_surfaceLightLists.begin(); i != m_surfaceLightLists.end(); ++i)
503     {
504       (*i).clear();
505     }
506   }
507 };
508
509 class ModelNode : public scene::Node::Symbiot, public scene::Instantiable
510 {
511   class TypeCasts
512   {
513     NodeTypeCastTable m_casts;
514   public:
515     TypeCasts()
516     {
517       NodeStaticCast<ModelNode, scene::Instantiable>::install(m_casts);
518     }
519     NodeTypeCastTable& get()
520     {
521       return m_casts;
522     }
523   };
524
525
526   scene::Node m_node;
527   InstanceSet m_instances;
528   Model m_model;
529 public:
530
531   typedef LazyStatic<TypeCasts> StaticTypeCasts;
532
533   ModelNode() : m_node(this, this, StaticTypeCasts::instance().get())
534   {
535   }
536
537   Model& model()
538   {
539     return m_model;
540   }
541
542   void release()
543   {
544     delete this;
545   }
546   scene::Node& node()
547   {
548     return m_node;
549   }
550
551   scene::Instance* create(const scene::Path& path, scene::Instance* parent)
552   {
553     return new ModelInstance(path, parent, m_model);
554   }
555   void forEachInstance(const scene::Instantiable::Visitor& visitor)
556   {
557     m_instances.forEachInstance(visitor);
558   }
559   void insert(scene::Instantiable::Observer* observer, const scene::Path& path, scene::Instance* instance)
560   {
561     m_instances.insert(observer, path, instance);
562   }
563   scene::Instance* erase(scene::Instantiable::Observer* observer, const scene::Path& path)
564   {
565     return m_instances.erase(observer, path);
566   }
567 };
568
569
570 inline void Surface_constructQuad(Surface& surface, const Vector3& a, const Vector3& b, const Vector3& c, const Vector3& d, const Vector3& normal)
571 {
572   surface.vertices().push_back(
573     ArbitraryMeshVertex(
574       vertex3f_for_vector3(a),
575       normal3f_for_vector3(normal),
576       texcoord2f_from_array(aabb_texcoord_topleft)
577     )
578   );
579   surface.vertices().push_back(
580     ArbitraryMeshVertex(
581       vertex3f_for_vector3(b),
582       normal3f_for_vector3(normal),
583       texcoord2f_from_array(aabb_texcoord_topright)
584     )
585   );
586   surface.vertices().push_back(
587     ArbitraryMeshVertex(
588       vertex3f_for_vector3(c),
589       normal3f_for_vector3(normal),
590       texcoord2f_from_array(aabb_texcoord_botright)
591     )
592   );
593   surface.vertices().push_back(
594     ArbitraryMeshVertex(
595       vertex3f_for_vector3(d),
596       normal3f_for_vector3(normal),
597       texcoord2f_from_array(aabb_texcoord_botleft)
598     )
599   );
600 }
601
602 inline void Model_constructNull(Model& model)
603 {
604   Surface& surface = model.newSurface();
605
606   AABB aabb(Vector3(0, 0, 0), Vector3(8, 8, 8));
607
608   Vector3 points[8];
609         aabb_corners(aabb, points);
610
611   surface.vertices().reserve(24);
612
613   Surface_constructQuad(surface, points[2], points[1], points[5], points[6], aabb_normals[0]);
614   Surface_constructQuad(surface, points[1], points[0], points[4], points[5], aabb_normals[1]);
615   Surface_constructQuad(surface, points[0], points[1], points[2], points[3], aabb_normals[2]);
616   Surface_constructQuad(surface, points[0], points[3], points[7], points[4], aabb_normals[3]);
617   Surface_constructQuad(surface, points[3], points[2], points[6], points[7], aabb_normals[4]);
618   Surface_constructQuad(surface, points[7], points[6], points[5], points[4], aabb_normals[5]);
619
620   surface.indices().reserve(36);
621
622   RenderIndex indices[36] = {
623      0,  1,  2,  0,  2,  3,
624      4,  5,  6,  4,  6,  7,
625      8,  9, 10,  8, 10, 11,
626     12, 13, 14, 12, 14, 15,
627     16, 17, 18, 16, 18, 19,
628     20, 21, 22, 10, 22, 23,
629   };
630
631   for(RenderIndex* i = indices; i != indices+(sizeof(indices)/sizeof(RenderIndex)); ++i)
632   {
633     surface.indices().insert(*i);
634   }
635
636   surface.setShader("");
637
638   surface.updateAABB();
639
640   model.updateAABB();
641 }
642
643 #endif