/* Copyright (C) 2001-2006, William Joseph. All Rights Reserved. This file is part of GtkRadiant. GtkRadiant is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. GtkRadiant is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GtkRadiant; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #if !defined(INCLUDED_RENDERER_H) #define INCLUDED_RENDERER_H #include "irender.h" #include "renderable.h" #include "iselection.h" #include "cullable.h" #include "scenelib.h" #include "math/frustum.h" #include inline Cullable* Instance_getCullable(scene::Instance& instance) { return InstanceTypeCast::cast(instance); } inline Renderable* Instance_getRenderable(scene::Instance& instance) { return InstanceTypeCast::cast(instance); } inline VolumeIntersectionValue Cullable_testVisible(scene::Instance& instance, const VolumeTest& volume, VolumeIntersectionValue parentVisible) { if(parentVisible == c_volumePartial) { Cullable* cullable = Instance_getCullable(instance); if(cullable != 0) { return cullable->intersectVolume(volume, instance.localToWorld()); } } return parentVisible; } template class CullingWalker { const VolumeTest& m_volume; const _Walker& m_walker; public: CullingWalker(const VolumeTest& volume, const _Walker& walker) : m_volume(volume), m_walker(walker) { } bool pre(const scene::Path& path, scene::Instance& instance, VolumeIntersectionValue parentVisible) const { VolumeIntersectionValue visible = Cullable_testVisible(instance, m_volume, parentVisible); if(visible != c_volumeOutside) { return m_walker.pre(path, instance); } return true; } void post(const scene::Path& path, scene::Instance& instance, VolumeIntersectionValue parentVisible) const { return m_walker.post(path, instance); } }; template class ForEachVisible : public scene::Graph::Walker { const VolumeTest& m_volume; const Walker_& m_walker; mutable std::vector m_state; public: ForEachVisible(const VolumeTest& volume, const Walker_& walker) : m_volume(volume), m_walker(walker) { m_state.push_back(c_volumePartial); } bool pre(const scene::Path& path, scene::Instance& instance) const { VolumeIntersectionValue visible = (path.top().get().visible()) ? m_state.back() : c_volumeOutside; if(visible == c_volumePartial) { visible = m_volume.TestAABB(instance.worldAABB()); } m_state.push_back(visible); if(visible == c_volumeOutside) { return false; } else { return m_walker.pre(path, instance, m_state.back()); } } void post(const scene::Path& path, scene::Instance& instance) const { if(m_state.back() != c_volumeOutside) { m_walker.post(path, instance, m_state.back()); } m_state.pop_back(); } }; template inline void Scene_forEachVisible(scene::Graph& graph, const VolumeTest& volume, const Functor& functor) { graph.traverse(ForEachVisible< CullingWalker >(volume, CullingWalker(volume, functor))); } class RenderHighlighted { Renderer& m_renderer; const VolumeTest& m_volume; public: RenderHighlighted(Renderer& renderer, const VolumeTest& volume) : m_renderer(renderer), m_volume(volume) { } void render(const Renderable& renderable) const { switch(m_renderer.getStyle()) { case Renderer::eFullMaterials: renderable.renderSolid(m_renderer, m_volume); break; case Renderer::eWireframeOnly: renderable.renderWireframe(m_renderer, m_volume); break; } } typedef ConstMemberCaller1 RenderCaller; bool pre(const scene::Path& path, scene::Instance& instance, VolumeIntersectionValue parentVisible) const { m_renderer.PushState(); if(Cullable_testVisible(instance, m_volume, parentVisible) != c_volumeOutside) { Renderable* renderable = Instance_getRenderable(instance); if(renderable) { renderable->viewChanged(); } Selectable* selectable = Instance_getSelectable(instance); if(selectable != 0 && selectable->isSelected()) { if(GlobalSelectionSystem().Mode() != SelectionSystem::eComponent) { m_renderer.Highlight(Renderer::eFace); } else if(renderable) { renderable->renderComponents(m_renderer, m_volume); } m_renderer.Highlight(Renderer::ePrimitive); } if(renderable) { render(*renderable); } } return true; } void post(const scene::Path& path, scene::Instance& instance, VolumeIntersectionValue parentVisible) const { m_renderer.PopState(); } }; inline void Scene_Render(Renderer& renderer, const VolumeTest& volume) { GlobalSceneGraph().traverse(ForEachVisible(volume, RenderHighlighted(renderer, volume))); GlobalShaderCache().forEachRenderable(RenderHighlighted::RenderCaller(RenderHighlighted(renderer, volume))); } #endif