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