renderer.h

Go to the documentation of this file.
00001 /*
00002  Copyright (C) 2001-2006, William Joseph.
00003  All Rights Reserved.
00004 
00005  This file is part of GtkRadiant.
00006 
00007  GtkRadiant is free software; you can redistribute it and/or modify
00008  it under the terms of the GNU General Public License as published by
00009  the Free Software Foundation; either version 2 of the License, or
00010  (at your option) any later version.
00011 
00012  GtkRadiant is distributed in the hope that it will be useful,
00013  but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  GNU General Public License for more details.
00016 
00017  You should have received a copy of the GNU General Public License
00018  along with GtkRadiant; if not, write to the Free Software
00019  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00020  */
00021 
00022 #if !defined(INCLUDED_RENDERER_H)
00023 #define INCLUDED_RENDERER_H
00024 
00025 #include "irender.h"
00026 #include "renderable.h"
00027 #include "iselection.h"
00028 #include "cullable.h"
00029 #include "scenelib.h"
00030 #include "math/frustum.h"
00031 #include <vector>
00032 
00033 inline Cullable* Instance_getCullable (scene::Instance& instance)
00034 {
00035     return InstanceTypeCast<Cullable>::cast(instance);
00036 }
00037 
00038 inline Renderable* Instance_getRenderable (scene::Instance& instance)
00039 {
00040     return InstanceTypeCast<Renderable>::cast(instance);
00041 }
00042 
00043 inline VolumeIntersectionValue Cullable_testVisible (scene::Instance& instance, const VolumeTest& volume,
00044         VolumeIntersectionValue parentVisible)
00045 {
00046     if (parentVisible == c_volumePartial) {
00047         Cullable* cullable = Instance_getCullable(instance);
00048         if (cullable != 0) {
00049             return cullable->intersectVolume(volume, instance.localToWorld());
00050         }
00051     }
00052     return parentVisible;
00053 }
00054 
00055 template<typename _Walker>
00056 class CullingWalker
00057 {
00058         const VolumeTest& m_volume;
00059         const _Walker& m_walker;
00060     public:
00061         CullingWalker (const VolumeTest& volume, const _Walker& walker) :
00062             m_volume(volume), m_walker(walker)
00063         {
00064         }
00065         bool pre (const scene::Path& path, scene::Instance& instance, VolumeIntersectionValue parentVisible) const
00066         {
00067             VolumeIntersectionValue visible = Cullable_testVisible(instance, m_volume, parentVisible);
00068             if (visible != c_volumeOutside) {
00069                 return m_walker.pre(path, instance);
00070             }
00071             return true;
00072         }
00073         void post (const scene::Path& path, scene::Instance& instance, VolumeIntersectionValue parentVisible) const
00074         {
00075             return m_walker.post(path, instance);
00076         }
00077 };
00078 
00079 template<typename Walker_>
00080 class ForEachVisible: public scene::Graph::Walker
00081 {
00082         const VolumeTest& m_volume;
00083         const Walker_& m_walker;
00084         mutable std::vector<VolumeIntersectionValue> m_state;
00085     public:
00086         ForEachVisible (const VolumeTest& volume, const Walker_& walker) :
00087             m_volume(volume), m_walker(walker)
00088         {
00089             m_state.push_back(c_volumePartial);
00090         }
00091         bool pre (const scene::Path& path, scene::Instance& instance) const
00092         {
00093             VolumeIntersectionValue visible = (path.top().get().visible()) ? m_state.back() : c_volumeOutside;
00094 
00095             if (visible == c_volumePartial) {
00096                 visible = m_volume.TestAABB(instance.worldAABB());
00097             }
00098 
00099             m_state.push_back(visible);
00100 
00101             if (visible == c_volumeOutside) {
00102                 return false;
00103             } else {
00104                 return m_walker.pre(path, instance, m_state.back());
00105             }
00106         }
00107         void post (const scene::Path& path, scene::Instance& instance) const
00108         {
00109             if (m_state.back() != c_volumeOutside) {
00110                 m_walker.post(path, instance, m_state.back());
00111             }
00112 
00113             m_state.pop_back();
00114         }
00115 };
00116 
00117 template<typename Functor>
00118 inline void Scene_forEachVisible (scene::Graph& graph, const VolumeTest& volume, const Functor& functor)
00119 {
00120     graph.traverse(ForEachVisible<CullingWalker<Functor> > (volume, CullingWalker<Functor> (volume, functor)));
00121 }
00122 
00123 class RenderHighlighted
00124 {
00125         Renderer& m_renderer;
00126         const VolumeTest& m_volume;
00127     public:
00128         RenderHighlighted (Renderer& renderer, const VolumeTest& volume) :
00129             m_renderer(renderer), m_volume(volume)
00130         {
00131         }
00132         void render (const Renderable& renderable) const
00133         {
00134             switch (m_renderer.getStyle()) {
00135             case Renderer::eFullMaterials:
00136                 renderable.renderSolid(m_renderer, m_volume);
00137                 break;
00138             case Renderer::eWireframeOnly:
00139                 renderable.renderWireframe(m_renderer, m_volume);
00140                 break;
00141             }
00142         }
00143         typedef ConstMemberCaller1<RenderHighlighted, const Renderable&, &RenderHighlighted::render> RenderCaller;
00144 
00145         bool pre (const scene::Path& path, scene::Instance& instance, VolumeIntersectionValue parentVisible) const
00146         {
00147             m_renderer.PushState();
00148 
00149             if (Cullable_testVisible(instance, m_volume, parentVisible) != c_volumeOutside) {
00150                 Renderable* renderable = Instance_getRenderable(instance);
00151                 if (renderable) {
00152                     renderable->viewChanged();
00153                 }
00154 
00155                 Selectable* selectable = Instance_getSelectable(instance);
00156                 if (selectable != 0 && selectable->isSelected()) {
00157                     if (GlobalSelectionSystem().Mode() != SelectionSystem::eComponent) {
00158                         m_renderer.Highlight(Renderer::eFace);
00159                     } else if (renderable) {
00160                         renderable->renderComponents(m_renderer, m_volume);
00161                     }
00162                     m_renderer.Highlight(Renderer::ePrimitive);
00163                 }
00164 
00165                 if (renderable) {
00166                     render(*renderable);
00167                 }
00168             }
00169 
00170             return true;
00171         }
00172         void post (const scene::Path& path, scene::Instance& instance, VolumeIntersectionValue parentVisible) const
00173         {
00174             m_renderer.PopState();
00175         }
00176 };
00177 
00178 inline void Scene_Render (Renderer& renderer, const VolumeTest& volume)
00179 {
00180     GlobalSceneGraph().traverse(ForEachVisible<RenderHighlighted> (volume, RenderHighlighted(renderer, volume)));
00181     GlobalShaderCache().forEachRenderable(RenderHighlighted::RenderCaller(RenderHighlighted(renderer, volume)));
00182 }
00183 
00184 #endif

Generated by  doxygen 1.6.2