2 Copyright (C) 2001-2006, William Joseph.
5 This file is part of GtkRadiant.
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.
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.
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
22 #if !defined( INCLUDED_RENDERER_H )
23 #define INCLUDED_RENDERER_H
26 #include "renderable.h"
27 #include "iselection.h"
30 #include "math/frustum.h"
33 inline Cullable* Instance_getCullable( scene::Instance& instance ){
34 return InstanceTypeCast<Cullable>::cast( instance );
37 inline Renderable* Instance_getRenderable( scene::Instance& instance ){
38 return InstanceTypeCast<Renderable>::cast( instance );
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() );
51 template<typename _Walker>
54 const VolumeTest& m_volume;
55 const _Walker& m_walker;
57 CullingWalker( const VolumeTest& volume, const _Walker& walker )
58 : m_volume( volume ), m_walker( walker ){
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 );
67 void post( const scene::Path& path, scene::Instance& instance, VolumeIntersectionValue parentVisible ) const {
68 return m_walker.post( path, instance );
72 template<typename Walker_>
73 class ForEachVisible : public scene::Graph::Walker
75 const VolumeTest& m_volume;
76 const Walker_& m_walker;
77 mutable std::vector<VolumeIntersectionValue> m_state;
79 ForEachVisible( const VolumeTest& volume, const Walker_& walker )
80 : m_volume( volume ), m_walker( walker ){
81 m_state.push_back( c_volumePartial );
83 bool pre( const scene::Path& path, scene::Instance& instance ) const {
84 VolumeIntersectionValue visible = ( path.top().get().visible() ) ? m_state.back() : c_volumeOutside;
86 if ( visible == c_volumePartial ) {
87 visible = m_volume.TestAABB( instance.worldAABB() );
90 m_state.push_back( visible );
92 if ( visible == c_volumeOutside ) {
97 return m_walker.pre( path, instance, m_state.back() );
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() );
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 ) ) );
114 class RenderHighlighted
116 Renderer& m_renderer;
117 const VolumeTest& m_volume;
119 RenderHighlighted( Renderer& renderer, const VolumeTest& volume )
120 : m_renderer( renderer ), m_volume( volume ){
122 void render( const Renderable& renderable ) const {
123 switch ( m_renderer.getStyle() )
125 case Renderer::eFullMaterials:
126 renderable.renderSolid( m_renderer, m_volume );
128 case Renderer::eWireframeOnly:
129 renderable.renderWireframe( m_renderer, m_volume );
133 typedef ConstMemberCaller<RenderHighlighted, void(const Renderable&), &RenderHighlighted::render> RenderCaller;
135 bool pre( const scene::Path& path, scene::Instance& instance, VolumeIntersectionValue parentVisible ) const {
136 m_renderer.PushState();
138 if ( Cullable_testVisible( instance, m_volume, parentVisible ) != c_volumeOutside ) {
139 Renderable* renderable = Instance_getRenderable( instance );
141 renderable->viewChanged();
144 Selectable* selectable = Instance_getSelectable( instance );
145 if ( selectable != 0 && selectable->isSelected() ) {
146 if ( GlobalSelectionSystem().Mode() != SelectionSystem::eComponent ) {
147 m_renderer.Highlight( Renderer::eFace );
149 else if ( renderable ) {
150 renderable->renderComponents( m_renderer, m_volume );
152 m_renderer.Highlight( Renderer::ePrimitive );
156 render( *renderable );
162 void post( const scene::Path& path, scene::Instance& instance, VolumeIntersectionValue parentVisible ) const {
163 m_renderer.PopState();
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 ) ) );