]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - radiant/renderer.h
reformat code! now the code is only ugly on the *inside*
[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 {
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
44 Cullable_testVisible(scene::Instance &instance, const VolumeTest &volume, VolumeIntersectionValue parentVisible)
45 {
46     if (parentVisible == c_volumePartial) {
47         Cullable *cullable = Instance_getCullable(instance);
48         if (cullable != 0) {
49             return cullable->intersectVolume(volume, instance.localToWorld());
50         }
51     }
52     return parentVisible;
53 }
54
55 template<typename _Walker>
56 class CullingWalker {
57     const VolumeTest &m_volume;
58     const _Walker &m_walker;
59 public:
60     CullingWalker(const VolumeTest &volume, const _Walker &walker)
61             : m_volume(volume), m_walker(walker)
62     {
63     }
64
65     bool pre(const scene::Path &path, scene::Instance &instance, VolumeIntersectionValue parentVisible) const
66     {
67         VolumeIntersectionValue visible = Cullable_testVisible(instance, m_volume, parentVisible);
68         if (visible != c_volumeOutside) {
69             return m_walker.pre(path, instance);
70         }
71         return true;
72     }
73
74     void post(const scene::Path &path, scene::Instance &instance, VolumeIntersectionValue parentVisible) const
75     {
76         return m_walker.post(path, instance);
77     }
78 };
79
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;
85 public:
86     ForEachVisible(const VolumeTest &volume, const Walker_ &walker)
87             : m_volume(volume), m_walker(walker)
88     {
89         m_state.push_back(c_volumePartial);
90     }
91
92     bool pre(const scene::Path &path, scene::Instance &instance) const
93     {
94         VolumeIntersectionValue visible = (path.top().get().visible()) ? m_state.back() : c_volumeOutside;
95
96         if (visible == c_volumePartial) {
97             visible = m_volume.TestAABB(instance.worldAABB());
98         }
99
100         m_state.push_back(visible);
101
102         if (visible == c_volumeOutside) {
103             return false;
104         } else {
105             return m_walker.pre(path, instance, m_state.back());
106         }
107     }
108
109     void post(const scene::Path &path, scene::Instance &instance) const
110     {
111         if (m_state.back() != c_volumeOutside) {
112             m_walker.post(path, instance, m_state.back());
113         }
114
115         m_state.pop_back();
116     }
117 };
118
119 template<typename Functor>
120 inline void Scene_forEachVisible(scene::Graph &graph, const VolumeTest &volume, const Functor &functor)
121 {
122     graph.traverse(ForEachVisible<CullingWalker<Functor> >(volume, CullingWalker<Functor>(volume, functor)));
123 }
124
125 class RenderHighlighted {
126     Renderer &m_renderer;
127     const VolumeTest &m_volume;
128 public:
129     RenderHighlighted(Renderer &renderer, const VolumeTest &volume)
130             : m_renderer(renderer), m_volume(volume)
131     {
132     }
133
134     void render(const Renderable &renderable) const
135     {
136         switch (m_renderer.getStyle()) {
137             case Renderer::eFullMaterials:
138                 renderable.renderSolid(m_renderer, m_volume);
139                 break;
140             case Renderer::eWireframeOnly:
141                 renderable.renderWireframe(m_renderer, m_volume);
142                 break;
143         }
144     }
145
146     typedef ConstMemberCaller<RenderHighlighted, void(const Renderable &), &RenderHighlighted::render> RenderCaller;
147
148     bool pre(const scene::Path &path, scene::Instance &instance, VolumeIntersectionValue parentVisible) const
149     {
150         m_renderer.PushState();
151
152         if (Cullable_testVisible(instance, m_volume, parentVisible) != c_volumeOutside) {
153             Renderable *renderable = Instance_getRenderable(instance);
154             if (renderable) {
155                 renderable->viewChanged();
156             }
157
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);
164                 }
165                 m_renderer.Highlight(Renderer::ePrimitive);
166             }
167
168             if (renderable) {
169                 render(*renderable);
170             }
171         }
172
173         return true;
174     }
175
176     void post(const scene::Path &path, scene::Instance &instance, VolumeIntersectionValue parentVisible) const
177     {
178         m_renderer.PopState();
179     }
180 };
181
182 inline void Scene_Render(Renderer &renderer, const VolumeTest &volume)
183 {
184     GlobalSceneGraph().traverse(ForEachVisible<RenderHighlighted>(volume, RenderHighlighted(renderer, volume)));
185     GlobalShaderCache().forEachRenderable(RenderHighlighted::RenderCaller(RenderHighlighted(renderer, volume)));
186 }
187
188 #endif