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)
35 return InstanceTypeCast<Cullable>::cast(instance);
38 inline Renderable *Instance_getRenderable(scene::Instance &instance)
40 return InstanceTypeCast<Renderable>::cast(instance);
43 inline VolumeIntersectionValue
44 Cullable_testVisible(scene::Instance &instance, const VolumeTest &volume, VolumeIntersectionValue parentVisible)
46 if (parentVisible == c_volumePartial) {
47 Cullable *cullable = Instance_getCullable(instance);
49 return cullable->intersectVolume(volume, instance.localToWorld());
55 template<typename _Walker>
57 const VolumeTest &m_volume;
58 const _Walker &m_walker;
60 CullingWalker(const VolumeTest &volume, const _Walker &walker)
61 : m_volume(volume), m_walker(walker)
65 bool pre(const scene::Path &path, scene::Instance &instance, VolumeIntersectionValue parentVisible) const
67 VolumeIntersectionValue visible = Cullable_testVisible(instance, m_volume, parentVisible);
68 if (visible != c_volumeOutside) {
69 return m_walker.pre(path, instance);
74 void post(const scene::Path &path, scene::Instance &instance, VolumeIntersectionValue parentVisible) const
76 return m_walker.post(path, instance);
80 template<typename Walker_>
81 class ForEachVisible : public scene::Graph::Walker {
82 const VolumeTest &m_volume;
83 const Walker_ &m_walker;
84 mutable std::vector<VolumeIntersectionValue> m_state;
86 ForEachVisible(const VolumeTest &volume, const Walker_ &walker)
87 : m_volume(volume), m_walker(walker)
89 m_state.push_back(c_volumePartial);
92 bool pre(const scene::Path &path, scene::Instance &instance) const
94 VolumeIntersectionValue visible = (path.top().get().visible()) ? m_state.back() : c_volumeOutside;
96 if (visible == c_volumePartial) {
97 visible = m_volume.TestAABB(instance.worldAABB());
100 m_state.push_back(visible);
102 if (visible == c_volumeOutside) {
105 return m_walker.pre(path, instance, m_state.back());
109 void post(const scene::Path &path, scene::Instance &instance) const
111 if (m_state.back() != c_volumeOutside) {
112 m_walker.post(path, instance, m_state.back());
119 template<typename Functor>
120 inline void Scene_forEachVisible(scene::Graph &graph, const VolumeTest &volume, const Functor &functor)
122 graph.traverse(ForEachVisible<CullingWalker<Functor> >(volume, CullingWalker<Functor>(volume, functor)));
125 class RenderHighlighted {
126 Renderer &m_renderer;
127 const VolumeTest &m_volume;
129 RenderHighlighted(Renderer &renderer, const VolumeTest &volume)
130 : m_renderer(renderer), m_volume(volume)
134 void render(const Renderable &renderable) const
136 switch (m_renderer.getStyle()) {
137 case Renderer::eFullMaterials:
138 renderable.renderSolid(m_renderer, m_volume);
140 case Renderer::eWireframeOnly:
141 renderable.renderWireframe(m_renderer, m_volume);
146 typedef ConstMemberCaller<RenderHighlighted, void(const Renderable &), &RenderHighlighted::render> RenderCaller;
148 bool pre(const scene::Path &path, scene::Instance &instance, VolumeIntersectionValue parentVisible) const
150 m_renderer.PushState();
152 if (Cullable_testVisible(instance, m_volume, parentVisible) != c_volumeOutside) {
153 Renderable *renderable = Instance_getRenderable(instance);
155 renderable->viewChanged();
158 Selectable *selectable = Instance_getSelectable(instance);
159 if (selectable != 0 && selectable->isSelected()) {
160 if (GlobalSelectionSystem().Mode() != SelectionSystem::eComponent) {
161 m_renderer.Highlight(Renderer::eFace);
162 } else if (renderable) {
163 renderable->renderComponents(m_renderer, m_volume);
165 m_renderer.Highlight(Renderer::ePrimitive);
176 void post(const scene::Path &path, scene::Instance &instance, VolumeIntersectionValue parentVisible) const
178 m_renderer.PopState();
182 inline void Scene_Render(Renderer &renderer, const VolumeTest &volume)
184 GlobalSceneGraph().traverse(ForEachVisible<RenderHighlighted>(volume, RenderHighlighted(renderer, volume)));
185 GlobalShaderCache().forEachRenderable(RenderHighlighted::RenderCaller(RenderHighlighted(renderer, volume)));