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