Skip to content
Newer
Older
100644 200 lines (175 sloc) 5.49 KB
0991a5c @tbradshaw The GtkRadiant sources as originally released under the GPL license.
tbradshaw authored Jan 31, 2012
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 {
35 return InstanceTypeCast<Cullable>::cast(instance);
36 }
37
38 inline Renderable* Instance_getRenderable(scene::Instance& instance)
39 {
40 return InstanceTypeCast<Renderable>::cast(instance);
41 }
42
43 inline VolumeIntersectionValue Cullable_testVisible(scene::Instance& instance, const VolumeTest& volume, VolumeIntersectionValue parentVisible)
44 {
45 if(parentVisible == c_volumePartial)
46 {
47 Cullable* cullable = Instance_getCullable(instance);
48 if(cullable != 0)
49 {
50 return cullable->intersectVolume(volume, instance.localToWorld());
51 }
52 }
53 return parentVisible;
54 }
55
56 template<typename _Walker>
57 class CullingWalker
58 {
59 const VolumeTest& m_volume;
60 const _Walker& m_walker;
61 public:
62 CullingWalker(const VolumeTest& volume, const _Walker& walker)
63 : m_volume(volume), m_walker(walker)
64 {
65 }
66 bool pre(const scene::Path& path, scene::Instance& instance, VolumeIntersectionValue parentVisible) const
67 {
68 VolumeIntersectionValue visible = Cullable_testVisible(instance, m_volume, parentVisible);
69 if(visible != c_volumeOutside)
70 {
71 return m_walker.pre(path, instance);
72 }
73 return true;
74 }
75 void post(const scene::Path& path, scene::Instance& instance, VolumeIntersectionValue parentVisible) const
76 {
77 return m_walker.post(path, instance);
78 }
79 };
80
81 template<typename Walker_>
82 class ForEachVisible : public scene::Graph::Walker
83 {
84 const VolumeTest& m_volume;
85 const Walker_& m_walker;
86 mutable std::vector<VolumeIntersectionValue> m_state;
87 public:
88 ForEachVisible(const VolumeTest& volume, const Walker_& walker)
89 : m_volume(volume), m_walker(walker)
90 {
91 m_state.push_back(c_volumePartial);
92 }
93 bool pre(const scene::Path& path, scene::Instance& instance) const
94 {
95 VolumeIntersectionValue visible = (path.top().get().visible()) ? m_state.back() : c_volumeOutside;
96
97 if(visible == c_volumePartial)
98 {
99 visible = m_volume.TestAABB(instance.worldAABB());
100 }
101
102 m_state.push_back(visible);
103
104 if(visible == c_volumeOutside)
105 {
106 return false;
107 }
108 else
109 {
110 return m_walker.pre(path, instance, m_state.back());
111 }
112 }
113 void post(const scene::Path& path, scene::Instance& instance) const
114 {
115 if(m_state.back() != c_volumeOutside)
116 {
117 m_walker.post(path, instance, m_state.back());
118 }
119
120 m_state.pop_back();
121 }
122 };
123
124 template<typename Functor>
125 inline void Scene_forEachVisible(scene::Graph& graph, const VolumeTest& volume, const Functor& functor)
126 {
127 graph.traverse(ForEachVisible< CullingWalker<Functor> >(volume, CullingWalker<Functor>(volume, functor)));
128 }
129
130 class RenderHighlighted
131 {
132 Renderer& m_renderer;
133 const VolumeTest& m_volume;
134 public:
135 RenderHighlighted(Renderer& renderer, const VolumeTest& volume)
136 : m_renderer(renderer), m_volume(volume)
137 {
138 }
139 void render(const Renderable& renderable) const
140 {
141 switch(m_renderer.getStyle())
142 {
143 case Renderer::eFullMaterials:
144 renderable.renderSolid(m_renderer, m_volume);
145 break;
146 case Renderer::eWireframeOnly:
147 renderable.renderWireframe(m_renderer, m_volume);
148 break;
149 }
150 }
151 typedef ConstMemberCaller1<RenderHighlighted, const Renderable&, &RenderHighlighted::render> RenderCaller;
152
153 bool pre(const scene::Path& path, scene::Instance& instance, VolumeIntersectionValue parentVisible) const
154 {
155 m_renderer.PushState();
156
157 if(Cullable_testVisible(instance, m_volume, parentVisible) != c_volumeOutside)
158 {
159 Renderable* renderable = Instance_getRenderable(instance);
160 if(renderable)
161 {
162 renderable->viewChanged();
163 }
164
165 Selectable* selectable = Instance_getSelectable(instance);
166 if(selectable != 0 && selectable->isSelected())
167 {
168 if(GlobalSelectionSystem().Mode() != SelectionSystem::eComponent)
169 {
170 m_renderer.Highlight(Renderer::eFace);
171 }
172 else if(renderable)
173 {
174 renderable->renderComponents(m_renderer, m_volume);
175 }
176 m_renderer.Highlight(Renderer::ePrimitive);
177 }
178
179 if(renderable)
180 {
181 render(*renderable);
182 }
183 }
184
185 return true;
186 }
187 void post(const scene::Path& path, scene::Instance& instance, VolumeIntersectionValue parentVisible) const
188 {
189 m_renderer.PopState();
190 }
191 };
192
193 inline void Scene_Render(Renderer& renderer, const VolumeTest& volume)
194 {
195 GlobalSceneGraph().traverse(ForEachVisible<RenderHighlighted>(volume, RenderHighlighted(renderer, volume)));
196 GlobalShaderCache().forEachRenderable(RenderHighlighted::RenderCaller(RenderHighlighted(renderer, volume)));
197 }
198
199 #endif
Something went wrong with that request. Please try again.