00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
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;
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