targetable.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_TARGETABLE_H)
00023 #define INCLUDED_TARGETABLE_H
00024 
00025 #include <set>
00026 #include <map>
00027 
00028 #include "cullable.h"
00029 #include "renderable.h"
00030 
00031 #include "math/line.h"
00032 #include "render.h"
00033 #include "generic/callback.h"
00034 #include "selectionlib.h"
00035 #include "entitylib.h"
00036 #include "eclasslib.h"
00037 #include "stringio.h"
00038 
00039 class Targetable
00040 {
00041     public:
00042         virtual ~Targetable ()
00043         {
00044         }
00045         virtual const Vector3& world_position () const = 0;
00046 };
00047 
00048 typedef std::set<Targetable*> targetables_t;
00049 
00050 extern const std::string g_targetable_nameKey;
00051 
00052 targetables_t* getTargetables (const std::string& targetname);
00053 
00054 class EntityConnectionLine: public OpenGLRenderable
00055 {
00056     public:
00057         Vector3 start;
00058         Vector3 end;
00059 
00060         void render (RenderStateFlags state) const
00061         {
00062             float s1[2], s2[2];
00063             Vector3 dir(end - start);
00064             double len = dir.getLength();
00065             dir *= 8.0 * (1.0 / len);
00066             s1[0] = dir[0] - dir[1];
00067             s1[1] = dir[0] + dir[1];
00068             s2[0] = dir[0] + dir[1];
00069             s2[1] = -dir[0] + dir[1];
00070 
00071             glBegin(GL_LINES);
00072 
00073             glVertex3fv(start);
00074             glVertex3fv(end);
00075 
00076             len *= 0.0625; // half / 8
00077 
00078             Vector3 arrow(start);
00079             for (unsigned int i = 0, count = (len < 32) ? 1 : static_cast<unsigned int> (len * 0.0625); i < count; i++) {
00080                 arrow += dir * ((len < 32) ? len : 32);
00081                 glVertex3fv(arrow);
00082                 glVertex3f(arrow[0] + s1[0], arrow[1] + s1[1], arrow[2] + dir[2]);
00083                 glVertex3fv(arrow);
00084                 glVertex3f(arrow[0] + s2[0], arrow[1] + s2[1], arrow[2] + dir[2]);
00085             }
00086 
00087             glEnd();
00088         }
00089 };
00090 
00091 class TargetedEntity
00092 {
00093         Targetable& m_targetable;
00094         targetables_t* m_targets;
00095 
00096         void construct ()
00097         {
00098             if (m_targets != 0)
00099                 m_targets->insert(&m_targetable);
00100         }
00101         void destroy ()
00102         {
00103             if (m_targets != 0)
00104                 m_targets->erase(&m_targetable);
00105         }
00106     public:
00107         TargetedEntity (Targetable& targetable) :
00108             m_targetable(targetable), m_targets(getTargetables(""))
00109         {
00110             construct();
00111         }
00112         ~TargetedEntity ()
00113         {
00114             destroy();
00115         }
00116         void targetnameChanged (const std::string& name)
00117         {
00118             destroy();
00119             m_targets = getTargetables(name.c_str());
00120             construct();
00121         }
00122         typedef MemberCaller1<TargetedEntity, const std::string&, &TargetedEntity::targetnameChanged> TargetnameChangedCaller;
00123 };
00124 
00125 class TargetingEntity
00126 {
00127         targetables_t* m_targets;
00128     public:
00129         TargetingEntity () :
00130             m_targets(getTargetables(""))
00131         {
00132         }
00133         void targetChanged (const std::string& target)
00134         {
00135             m_targets = getTargetables(target.c_str());
00136         }
00137         typedef MemberCaller1<TargetingEntity, const std::string&, &TargetingEntity::targetChanged> TargetChangedCaller;
00138 
00139         typedef targetables_t::iterator iterator;
00140 
00141         iterator begin () const
00142         {
00143             if (m_targets == 0) {
00144                 return iterator();
00145             }
00146             return m_targets->begin();
00147         }
00148         iterator end () const
00149         {
00150             if (m_targets == 0) {
00151                 return iterator();
00152             }
00153             return m_targets->end();
00154         }
00155         size_t size () const
00156         {
00157             if (m_targets == 0) {
00158                 return 0;
00159             }
00160             return m_targets->size();
00161         }
00162         bool empty () const
00163         {
00164             return m_targets == 0 || m_targets->empty();
00165         }
00166 };
00167 
00168 template<typename Functor>
00169 void TargetingEntity_forEach (const TargetingEntity& targets, const Functor& functor)
00170 {
00171     for (TargetingEntity::iterator i = targets.begin(); i != targets.end(); ++i) {
00172         functor((*i)->world_position());
00173     }
00174 }
00175 
00176 typedef std::map<std::size_t, TargetingEntity> TargetingEntities;
00177 
00178 template<typename Functor>
00179 void TargetingEntities_forEach (const TargetingEntities& targetingEntities, const Functor& functor)
00180 {
00181     for (TargetingEntities::const_iterator i = targetingEntities.begin(); i != targetingEntities.end(); ++i) {
00182         TargetingEntity_forEach((*i).second, functor);
00183     }
00184 }
00185 
00186 class TargetLinesPushBack
00187 {
00188         RenderablePointVector& m_targetLines;
00189         const Vector3& m_worldPosition;
00190         const VolumeTest& m_volume;
00191     public:
00192         TargetLinesPushBack (RenderablePointVector& targetLines, const Vector3& worldPosition, const VolumeTest& volume) :
00193             m_targetLines(targetLines), m_worldPosition(worldPosition), m_volume(volume)
00194         {
00195         }
00196         void operator() (const Vector3& worldPosition) const
00197         {
00198             if (m_volume.TestLine(segment_for_startend(m_worldPosition, worldPosition))) {
00199                 m_targetLines.push_back(PointVertex(reinterpret_cast<const Vertex3f&> (m_worldPosition)));
00200                 m_targetLines.push_back(PointVertex(reinterpret_cast<const Vertex3f&> (worldPosition)));
00201             }
00202         }
00203 };
00204 
00205 class TargetKeys: public Entity::Observer
00206 {
00207         TargetingEntities m_targetingEntities;
00208         Callback m_targetsChanged;
00209 
00210         bool readTargetKey (const std::string& key, std::size_t& index)
00211         {
00213             if (string_equal_n(key.c_str(), "target", 6)) {
00214                 index = 0;
00215                 if (string_empty(key.c_str() + 6) || string_parse_size(key.c_str() + 6, index)) {
00216                     return true;
00217                 }
00218             }
00219             return false;
00220         }
00221     public:
00222         void setTargetsChanged (const Callback& targetsChanged)
00223         {
00224             m_targetsChanged = targetsChanged;
00225         }
00226         void targetsChanged ()
00227         {
00228             m_targetsChanged();
00229         }
00230 
00231         void insert (const std::string& key, EntityKeyValue& value)
00232         {
00233             std::size_t index;
00234             if (readTargetKey(key, index)) {
00235                 TargetingEntities::iterator i = m_targetingEntities.insert(TargetingEntities::value_type(index,
00236                         TargetingEntity())).first;
00237                 value.attach(TargetingEntity::TargetChangedCaller((*i).second));
00238                 targetsChanged();
00239             }
00240         }
00241         void erase (const std::string& key, EntityKeyValue& value)
00242         {
00243             std::size_t index;
00244             if (readTargetKey(key, index)) {
00245                 TargetingEntities::iterator i = m_targetingEntities.find(index);
00246                 value.detach(TargetingEntity::TargetChangedCaller((*i).second));
00247                 m_targetingEntities.erase(i);
00248                 targetsChanged();
00249             }
00250         }
00251         const TargetingEntities& get () const
00252         {
00253             return m_targetingEntities;
00254         }
00255 };
00256 
00257 class RenderableTargetingEntity
00258 {
00259         TargetingEntity& m_targets;
00260         mutable RenderablePointVector m_target_lines;
00261     public:
00262         static Shader* m_state;
00263 
00264         RenderableTargetingEntity (TargetingEntity& targets) :
00265             m_targets(targets), m_target_lines(GL_LINES)
00266         {
00267         }
00268         void compile (const VolumeTest& volume, const Vector3& world_position) const
00269         {
00270             m_target_lines.clear();
00271             m_target_lines.reserve(m_targets.size() * 2);
00272             TargetingEntity_forEach(m_targets, TargetLinesPushBack(m_target_lines, world_position, volume));
00273         }
00274         void render (Renderer& renderer, const VolumeTest& volume, const Vector3& world_position) const
00275         {
00276             if (!m_targets.empty()) {
00277                 compile(volume, world_position);
00278                 if (!m_target_lines.empty()) {
00279                     renderer.addRenderable(m_target_lines, g_matrix4_identity);
00280                 }
00281             }
00282         }
00283 };
00284 
00285 class RenderableTargetingEntities
00286 {
00287         const TargetingEntities& m_targets;
00288         mutable RenderablePointVector m_target_lines;
00289     public:
00290         static Shader* m_state;
00291 
00292         RenderableTargetingEntities (const TargetingEntities& targets) :
00293             m_targets(targets), m_target_lines(GL_LINES)
00294         {
00295         }
00296         void compile (const VolumeTest& volume, const Vector3& world_position) const
00297         {
00298             m_target_lines.clear();
00299             TargetingEntities_forEach(m_targets, TargetLinesPushBack(m_target_lines, world_position, volume));
00300         }
00301         void render (Renderer& renderer, const VolumeTest& volume, const Vector3& world_position) const
00302         {
00303             if (!m_targets.empty()) {
00304                 compile(volume, world_position);
00305                 if (!m_target_lines.empty()) {
00306                     renderer.addRenderable(m_target_lines, g_matrix4_identity);
00307                 }
00308             }
00309         }
00310 };
00311 
00312 class TargetableInstance: public SelectableInstance, public Targetable, public Entity::Observer
00313 {
00314         mutable Vertex3f m_position;
00315         EntityKeyValues& m_entity;
00316         TargetKeys m_targeting;
00317         TargetedEntity m_targeted;
00318         RenderableTargetingEntities m_renderable;
00319     public:
00320 
00321         TargetableInstance (const scene::Path& path, scene::Instance* parent, void* instance,
00322                 InstanceTypeCastTable& casts, EntityKeyValues& entity, Targetable& targetable) :
00323             SelectableInstance(path, parent, instance, casts), m_entity(entity), m_targeted(targetable), m_renderable(
00324                     m_targeting.get())
00325         {
00326             m_entity.attach(*this);
00327             m_entity.attach(m_targeting);
00328         }
00329         ~TargetableInstance ()
00330         {
00331             m_entity.detach(m_targeting);
00332             m_entity.detach(*this);
00333         }
00334 
00335         void setTargetsChanged (const Callback& targetsChanged)
00336         {
00337             m_targeting.setTargetsChanged(targetsChanged);
00338         }
00339         void targetsChanged ()
00340         {
00341             m_targeting.targetsChanged();
00342         }
00343 
00344         void insert (const std::string& key, EntityKeyValue& value)
00345         {
00346             if (key == g_targetable_nameKey) {
00347                 value.attach(TargetedEntity::TargetnameChangedCaller(m_targeted));
00348             }
00349         }
00350         void erase (const std::string& key, EntityKeyValue& value)
00351         {
00352             if (key == g_targetable_nameKey) {
00353                 value.detach(TargetedEntity::TargetnameChangedCaller(m_targeted));
00354             }
00355         }
00356 
00357         const Vector3& world_position () const
00358         {
00359             const AABB& bounds = Instance::worldAABB();
00360             if (aabb_valid(bounds)) {
00361                 return bounds.origin;
00362             }
00363             return localToWorld().t().getVector3();
00364         }
00365 
00366         void render (Renderer& renderer, const VolumeTest& volume) const
00367         {
00368             renderer.SetState(m_entity.getEntityClass().m_state_wire, Renderer::eWireframeOnly);
00369             renderer.SetState(m_entity.getEntityClass().m_state_wire, Renderer::eFullMaterials);
00370             m_renderable.render(renderer, volume, world_position());
00371         }
00372 
00373         const TargetingEntities& getTargeting () const
00374         {
00375             return m_targeting.get();
00376         }
00377 };
00378 
00379 class RenderableConnectionLines: public Renderable
00380 {
00381         typedef std::set<TargetableInstance*> TargetableInstances;
00382         TargetableInstances m_instances;
00383     public:
00384         void attach (TargetableInstance& instance)
00385         {
00386             ASSERT_MESSAGE(m_instances.find(&instance) == m_instances.end(), "cannot attach instance");
00387             m_instances.insert(&instance);
00388         }
00389         void detach (TargetableInstance& instance)
00390         {
00391             ASSERT_MESSAGE(m_instances.find(&instance) != m_instances.end(), "cannot detach instance");
00392             m_instances.erase(&instance);
00393         }
00394 
00395         void renderSolid (Renderer& renderer, const VolumeTest& volume) const
00396         {
00397             for (TargetableInstances::const_iterator i = m_instances.begin(); i != m_instances.end(); ++i) {
00398                 if ((*i)->path().top().get().visible()) {
00399                     (*i)->render(renderer, volume);
00400                 }
00401             }
00402         }
00403         void renderWireframe (Renderer& renderer, const VolumeTest& volume) const
00404         {
00405             renderSolid(renderer, volume);
00406         }
00407 };
00408 
00409 typedef Static<RenderableConnectionLines> StaticRenderableConnectionLines;
00410 
00411 #endif

Generated by  doxygen 1.6.2