2 Copyright (C) 2001-2006, William Joseph.
5 This file is part of GtkRadiant.
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.
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.
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
22 #if !defined(INCLUDED_TARGETABLE_H)
23 #define INCLUDED_TARGETABLE_H
29 #include "renderable.h"
31 #include "math/line.h"
33 #include "generic/callback.h"
34 #include "selectionlib.h"
35 #include "entitylib.h"
36 #include "eclasslib.h"
42 virtual const Vector3& world_position() const = 0;
45 typedef std::set<Targetable*> targetables_t;
47 extern const char* g_targetable_nameKey;
49 targetables_t* getTargetables(const char* targetname);
51 class EntityConnectionLine : public OpenGLRenderable
57 void render(RenderStateFlags state) const
60 Vector3 dir(vector3_subtracted(end, start));
61 double len = vector3_length(dir);
62 vector3_scale(dir, 8.0 * (1.0 / len));
63 s1[0] = dir[0] - dir[1];
64 s1[1] = dir[0] + dir[1];
65 s2[0] = dir[0] + dir[1];
66 s2[1] = -dir[0] + dir[1];
70 glVertex3fv(vector3_to_array(start));
71 glVertex3fv(vector3_to_array(end));
73 len*=0.0625; // half / 8
76 for (unsigned int i = 0, count = (len<32)? 1 : static_cast<unsigned int>(len*0.0625); i < count; i++)
78 vector3_add(arrow, vector3_scaled(dir, (len<32)?len:32));
79 glVertex3fv(vector3_to_array(arrow));
80 glVertex3f(arrow[0]+s1[0], arrow[1]+s1[1], arrow[2]+dir[2]);
81 glVertex3fv(vector3_to_array(arrow));
82 glVertex3f(arrow[0]+s2[0], arrow[1]+s2[1], arrow[2]+dir[2]);
91 Targetable& m_targetable;
92 targetables_t* m_targets;
97 m_targets->insert(&m_targetable);
102 m_targets->erase(&m_targetable);
105 TargetedEntity(Targetable& targetable)
106 : m_targetable(targetable), m_targets(getTargetables(""))
114 void targetnameChanged(const char* name)
117 m_targets = getTargetables(name);
120 typedef MemberCaller1<TargetedEntity, const char*, &TargetedEntity::targetnameChanged> TargetnameChangedCaller;
124 class TargetingEntity
126 targetables_t* m_targets;
129 m_targets(getTargetables(""))
132 void targetChanged(const char* target)
134 m_targets = getTargetables(target);
136 typedef MemberCaller1<TargetingEntity, const char*, &TargetingEntity::targetChanged> TargetChangedCaller;
138 typedef targetables_t::iterator iterator;
140 iterator begin() const
146 return m_targets->begin();
154 return m_targets->end();
162 return m_targets->size();
166 return m_targets == 0 || m_targets->empty();
172 template<typename Functor>
173 void TargetingEntity_forEach(const TargetingEntity& targets, const Functor& functor)
175 for(TargetingEntity::iterator i = targets.begin(); i != targets.end(); ++i)
177 functor((*i)->world_position());
181 typedef std::map<std::size_t, TargetingEntity> TargetingEntities;
183 template<typename Functor>
184 void TargetingEntities_forEach(const TargetingEntities& targetingEntities, const Functor& functor)
186 for(TargetingEntities::const_iterator i = targetingEntities.begin(); i != targetingEntities.end(); ++i)
188 TargetingEntity_forEach((*i).second, functor);
192 class TargetLinesPushBack
194 RenderablePointVector& m_targetLines;
195 const Vector3& m_worldPosition;
196 const VolumeTest& m_volume;
198 TargetLinesPushBack(RenderablePointVector& targetLines, const Vector3& worldPosition, const VolumeTest& volume) :
199 m_targetLines(targetLines), m_worldPosition(worldPosition), m_volume(volume)
202 void operator()(const Vector3& worldPosition) const
204 if(m_volume.TestLine(segment_for_startend(m_worldPosition, worldPosition)))
206 m_targetLines.push_back(PointVertex(reinterpret_cast<const Vertex3f&>(m_worldPosition)));
207 m_targetLines.push_back(PointVertex(reinterpret_cast<const Vertex3f&>(worldPosition)));
212 class TargetKeys : public Entity::Observer
214 TargetingEntities m_targetingEntities;
215 Callback m_targetsChanged;
217 bool readTargetKey(const char* key, std::size_t& index)
219 if(string_equal_n(key, "target", 6))
222 if(string_empty(key + 6) || string_parse_size(key + 6, index))
230 void setTargetsChanged(const Callback& targetsChanged)
232 m_targetsChanged = targetsChanged;
234 void targetsChanged()
239 void insert(const char* key, EntityKeyValue& value)
242 if(readTargetKey(key, index))
244 TargetingEntities::iterator i = m_targetingEntities.insert(TargetingEntities::value_type(index, TargetingEntity())).first;
245 value.attach(TargetingEntity::TargetChangedCaller((*i).second));
249 void erase(const char* key, EntityKeyValue& value)
252 if(readTargetKey(key, index))
254 TargetingEntities::iterator i = m_targetingEntities.find(index);
255 value.detach(TargetingEntity::TargetChangedCaller((*i).second));
256 m_targetingEntities.erase(i);
260 const TargetingEntities& get() const
262 return m_targetingEntities;
268 class RenderableTargetingEntity
270 TargetingEntity& m_targets;
271 mutable RenderablePointVector m_target_lines;
273 static Shader* m_state;
275 RenderableTargetingEntity(TargetingEntity& targets)
276 : m_targets(targets), m_target_lines(GL_LINES)
279 void compile(const VolumeTest& volume, const Vector3& world_position) const
281 m_target_lines.clear();
282 m_target_lines.reserve(m_targets.size() * 2);
283 TargetingEntity_forEach(m_targets, TargetLinesPushBack(m_target_lines, world_position, volume));
285 void render(Renderer& renderer, const VolumeTest& volume, const Vector3& world_position) const
287 if(!m_targets.empty())
289 compile(volume, world_position);
290 if(!m_target_lines.empty())
292 renderer.addRenderable(m_target_lines, g_matrix4_identity);
298 class RenderableTargetingEntities
300 const TargetingEntities& m_targets;
301 mutable RenderablePointVector m_target_lines;
303 static Shader* m_state;
305 RenderableTargetingEntities(const TargetingEntities& targets)
306 : m_targets(targets), m_target_lines(GL_LINES)
309 void compile(const VolumeTest& volume, const Vector3& world_position) const
311 m_target_lines.clear();
312 TargetingEntities_forEach(m_targets, TargetLinesPushBack(m_target_lines, world_position, volume));
314 void render(Renderer& renderer, const VolumeTest& volume, const Vector3& world_position) const
316 if(!m_targets.empty())
318 compile(volume, world_position);
319 if(!m_target_lines.empty())
321 renderer.addRenderable(m_target_lines, g_matrix4_identity);
328 class TargetableInstance :
329 public SelectableInstance,
331 public Entity::Observer
333 mutable Vertex3f m_position;
334 EntityKeyValues& m_entity;
335 TargetKeys m_targeting;
336 TargetedEntity m_targeted;
337 RenderableTargetingEntities m_renderable;
341 const scene::Path& path,
342 scene::Instance* parent,
344 InstanceTypeCastTable& casts,
345 EntityKeyValues& entity,
346 Targetable& targetable
348 SelectableInstance(path, parent, instance, casts),
350 m_targeted(targetable),
351 m_renderable(m_targeting.get())
353 m_entity.attach(*this);
354 m_entity.attach(m_targeting);
356 ~TargetableInstance()
358 m_entity.detach(m_targeting);
359 m_entity.detach(*this);
362 void setTargetsChanged(const Callback& targetsChanged)
364 m_targeting.setTargetsChanged(targetsChanged);
366 void targetsChanged()
368 m_targeting.targetsChanged();
371 void insert(const char* key, EntityKeyValue& value)
373 if(string_equal(key, g_targetable_nameKey))
375 value.attach(TargetedEntity::TargetnameChangedCaller(m_targeted));
378 void erase(const char* key, EntityKeyValue& value)
380 if(string_equal(key, g_targetable_nameKey))
382 value.detach(TargetedEntity::TargetnameChangedCaller(m_targeted));
386 const Vector3& world_position() const
389 const AABB& bounds = Instance::worldAABB();
390 if(aabb_valid(bounds))
392 return bounds.origin;
395 const AABB& childBounds = Instance::childBounds();
396 if(aabb_valid(childBounds))
398 return childBounds.origin;
401 return vector4_to_vector3(localToWorld().t());
404 void render(Renderer& renderer, const VolumeTest& volume) const
406 renderer.SetState(m_entity.getEntityClass().m_state_wire, Renderer::eWireframeOnly);
407 renderer.SetState(m_entity.getEntityClass().m_state_wire, Renderer::eFullMaterials);
408 m_renderable.render(renderer, volume, world_position());
411 const TargetingEntities& getTargeting() const
413 return m_targeting.get();
418 class RenderableConnectionLines : public Renderable
420 typedef std::set<TargetableInstance*> TargetableInstances;
421 TargetableInstances m_instances;
423 void attach(TargetableInstance& instance)
425 ASSERT_MESSAGE(m_instances.find(&instance) == m_instances.end(), "cannot attach instance");
426 m_instances.insert(&instance);
428 void detach(TargetableInstance& instance)
430 ASSERT_MESSAGE(m_instances.find(&instance) != m_instances.end(), "cannot detach instance");
431 m_instances.erase(&instance);
434 void renderSolid(Renderer& renderer, const VolumeTest& volume) const
436 for(TargetableInstances::const_iterator i = m_instances.begin(); i != m_instances.end(); ++i)
438 if((*i)->path().top().get().visible())
440 (*i)->render(renderer, volume);
444 void renderWireframe(Renderer& renderer, const VolumeTest& volume) const
446 renderSolid(renderer, volume);
450 typedef Static<RenderableConnectionLines> StaticRenderableConnectionLines;