]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - radiant/renderer.h
Merge branch 'vfs' into 'master'
[xonotic/netradiant.git] / radiant / renderer.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_RENDERER_H )
23 #define INCLUDED_RENDERER_H
24
25 #include "irender.h"
26 #include "renderable.h"
27 #include "iselection.h"
28 #include "cullable.h"
29 #include "scenelib.h"
30 #include "math/frustum.h"
31 #include <vector>
32
33 inline Cullable* Instance_getCullable( scene::Instance& instance ){
34         return InstanceTypeCast<Cullable>::cast( instance );
35 }
36
37 inline Renderable* Instance_getRenderable( scene::Instance& instance ){
38         return InstanceTypeCast<Renderable>::cast( instance );
39 }
40
41 inline VolumeIntersectionValue Cullable_testVisible( scene::Instance& instance, const VolumeTest& volume, VolumeIntersectionValue parentVisible ){
42         if ( parentVisible == c_volumePartial ) {
43                 Cullable* cullable = Instance_getCullable( instance );
44                 if ( cullable != 0 ) {
45                         return cullable->intersectVolume( volume, instance.localToWorld() );
46                 }
47         }
48         return parentVisible;
49 }
50
51 template<typename _Walker>
52 class CullingWalker
53 {
54 const VolumeTest& m_volume;
55 const _Walker& m_walker;
56 public:
57 CullingWalker( const VolumeTest& volume, const _Walker& walker )
58         : m_volume( volume ), m_walker( walker ){
59 }
60 bool pre( const scene::Path& path, scene::Instance& instance, VolumeIntersectionValue parentVisible ) const {
61         VolumeIntersectionValue visible = Cullable_testVisible( instance, m_volume, parentVisible );
62         if ( visible != c_volumeOutside ) {
63                 return m_walker.pre( path, instance );
64         }
65         return true;
66 }
67 void post( const scene::Path& path, scene::Instance& instance, VolumeIntersectionValue parentVisible ) const {
68         return m_walker.post( path, instance );
69 }
70 };
71
72 template<typename Walker_>
73 class ForEachVisible : public scene::Graph::Walker
74 {
75 const VolumeTest& m_volume;
76 const Walker_& m_walker;
77 mutable std::vector<VolumeIntersectionValue> m_state;
78 public:
79 ForEachVisible( const VolumeTest& volume, const Walker_& walker )
80         : m_volume( volume ), m_walker( walker ){
81         m_state.push_back( c_volumePartial );
82 }
83 bool pre( const scene::Path& path, scene::Instance& instance ) const {
84         VolumeIntersectionValue visible = ( path.top().get().visible() ) ? m_state.back() : c_volumeOutside;
85
86         if ( visible == c_volumePartial ) {
87                 visible = m_volume.TestAABB( instance.worldAABB() );
88         }
89
90         m_state.push_back( visible );
91
92         if ( visible == c_volumeOutside ) {
93                 return false;
94         }
95         else
96         {
97                 return m_walker.pre( path, instance, m_state.back() );
98         }
99 }
100 void post( const scene::Path& path, scene::Instance& instance ) const {
101         if ( m_state.back() != c_volumeOutside ) {
102                 m_walker.post( path, instance, m_state.back() );
103         }
104
105         m_state.pop_back();
106 }
107 };
108
109 template<typename Functor>
110 inline void Scene_forEachVisible( scene::Graph& graph, const VolumeTest& volume, const Functor& functor ){
111         graph.traverse( ForEachVisible< CullingWalker<Functor> >( volume, CullingWalker<Functor>( volume, functor ) ) );
112 }
113
114 class RenderHighlighted
115 {
116 Renderer& m_renderer;
117 const VolumeTest& m_volume;
118 public:
119 RenderHighlighted( Renderer& renderer, const VolumeTest& volume )
120         : m_renderer( renderer ), m_volume( volume ){
121 }
122 void render( const Renderable& renderable ) const {
123         switch ( m_renderer.getStyle() )
124         {
125         case Renderer::eFullMaterials:
126                 renderable.renderSolid( m_renderer, m_volume );
127                 break;
128         case Renderer::eWireframeOnly:
129                 renderable.renderWireframe( m_renderer, m_volume );
130                 break;
131         }
132 }
133 typedef ConstMemberCaller<RenderHighlighted, void(const Renderable&), &RenderHighlighted::render> RenderCaller;
134
135 bool pre( const scene::Path& path, scene::Instance& instance, VolumeIntersectionValue parentVisible ) const {
136         m_renderer.PushState();
137
138         if ( Cullable_testVisible( instance, m_volume, parentVisible ) != c_volumeOutside ) {
139                 Renderable* renderable = Instance_getRenderable( instance );
140                 if ( renderable ) {
141                         renderable->viewChanged();
142                 }
143
144                 Selectable* selectable = Instance_getSelectable( instance );
145                 if ( selectable != 0 && selectable->isSelected() ) {
146                         if ( GlobalSelectionSystem().Mode() != SelectionSystem::eComponent ) {
147                                 m_renderer.Highlight( Renderer::eFace );
148                         }
149                         else if ( renderable ) {
150                                 renderable->renderComponents( m_renderer, m_volume );
151                         }
152                         m_renderer.Highlight( Renderer::ePrimitive );
153                 }
154
155                 if ( renderable ) {
156                         render( *renderable );
157                 }
158         }
159
160         return true;
161 }
162 void post( const scene::Path& path, scene::Instance& instance, VolumeIntersectionValue parentVisible ) const {
163         m_renderer.PopState();
164 }
165 };
166
167 inline void Scene_Render( Renderer& renderer, const VolumeTest& volume ){
168         GlobalSceneGraph().traverse( ForEachVisible<RenderHighlighted>( volume, RenderHighlighted( renderer, volume ) ) );
169         GlobalShaderCache().forEachRenderable( RenderHighlighted::RenderCaller( RenderHighlighted( renderer, volume ) ) );
170 }
171
172 #endif