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))
227 if(string_equal(key, "killtarget"))
235 void setTargetsChanged(const Callback& targetsChanged)
237 m_targetsChanged = targetsChanged;
239 void targetsChanged()
244 void insert(const char* key, EntityKeyValue& value)
247 if(readTargetKey(key, index))
249 TargetingEntities::iterator i = m_targetingEntities.insert(TargetingEntities::value_type(index, TargetingEntity())).first;
250 value.attach(TargetingEntity::TargetChangedCaller((*i).second));
254 void erase(const char* key, EntityKeyValue& value)
257 if(readTargetKey(key, index))
259 TargetingEntities::iterator i = m_targetingEntities.find(index);
260 value.detach(TargetingEntity::TargetChangedCaller((*i).second));
261 m_targetingEntities.erase(i);
265 const TargetingEntities& get() const
267 return m_targetingEntities;
273 class RenderableTargetingEntity
275 TargetingEntity& m_targets;
276 mutable RenderablePointVector m_target_lines;
278 static Shader* m_state;
280 RenderableTargetingEntity(TargetingEntity& targets)
281 : m_targets(targets), m_target_lines(GL_LINES)
284 void compile(const VolumeTest& volume, const Vector3& world_position) const
286 m_target_lines.clear();
287 m_target_lines.reserve(m_targets.size() * 2);
288 TargetingEntity_forEach(m_targets, TargetLinesPushBack(m_target_lines, world_position, volume));
290 void render(Renderer& renderer, const VolumeTest& volume, const Vector3& world_position) const
292 if(!m_targets.empty())
294 compile(volume, world_position);
295 if(!m_target_lines.empty())
297 renderer.addRenderable(m_target_lines, g_matrix4_identity);
303 class RenderableTargetingEntities
305 const TargetingEntities& m_targets;
306 mutable RenderablePointVector m_target_lines;
308 static Shader* m_state;
310 RenderableTargetingEntities(const TargetingEntities& targets)
311 : m_targets(targets), m_target_lines(GL_LINES)
314 void compile(const VolumeTest& volume, const Vector3& world_position) const
316 m_target_lines.clear();
317 TargetingEntities_forEach(m_targets, TargetLinesPushBack(m_target_lines, world_position, volume));
319 void render(Renderer& renderer, const VolumeTest& volume, const Vector3& world_position) const
321 if(!m_targets.empty())
323 compile(volume, world_position);
324 if(!m_target_lines.empty())
326 renderer.addRenderable(m_target_lines, g_matrix4_identity);
333 class TargetableInstance :
334 public SelectableInstance,
336 public Entity::Observer
338 mutable Vertex3f m_position;
339 EntityKeyValues& m_entity;
340 TargetKeys m_targeting;
341 TargetedEntity m_targeted;
342 RenderableTargetingEntities m_renderable;
346 const scene::Path& path,
347 scene::Instance* parent,
349 InstanceTypeCastTable& casts,
350 EntityKeyValues& entity,
351 Targetable& targetable
353 SelectableInstance(path, parent, instance, casts),
355 m_targeted(targetable),
356 m_renderable(m_targeting.get())
358 m_entity.attach(*this);
359 m_entity.attach(m_targeting);
361 ~TargetableInstance()
363 m_entity.detach(m_targeting);
364 m_entity.detach(*this);
367 void setTargetsChanged(const Callback& targetsChanged)
369 m_targeting.setTargetsChanged(targetsChanged);
371 void targetsChanged()
373 m_targeting.targetsChanged();
376 void insert(const char* key, EntityKeyValue& value)
378 if(string_equal(key, g_targetable_nameKey))
380 value.attach(TargetedEntity::TargetnameChangedCaller(m_targeted));
383 void erase(const char* key, EntityKeyValue& value)
385 if(string_equal(key, g_targetable_nameKey))
387 value.detach(TargetedEntity::TargetnameChangedCaller(m_targeted));
391 const Vector3& world_position() const
394 const AABB& bounds = Instance::worldAABB();
395 if(aabb_valid(bounds))
397 return bounds.origin;
400 const AABB& childBounds = Instance::childBounds();
401 if(aabb_valid(childBounds))
403 return childBounds.origin;
406 return vector4_to_vector3(localToWorld().t());
409 void render(Renderer& renderer, const VolumeTest& volume) const
411 renderer.SetState(m_entity.getEntityClass().m_state_wire, Renderer::eWireframeOnly);
412 renderer.SetState(m_entity.getEntityClass().m_state_wire, Renderer::eFullMaterials);
413 m_renderable.render(renderer, volume, world_position());
416 const TargetingEntities& getTargeting() const
418 return m_targeting.get();
423 class RenderableConnectionLines : public Renderable
425 typedef std::set<TargetableInstance*> TargetableInstances;
426 TargetableInstances m_instances;
428 void attach(TargetableInstance& instance)
430 ASSERT_MESSAGE(m_instances.find(&instance) == m_instances.end(), "cannot attach instance");
431 m_instances.insert(&instance);
433 void detach(TargetableInstance& instance)
435 ASSERT_MESSAGE(m_instances.find(&instance) != m_instances.end(), "cannot detach instance");
436 m_instances.erase(&instance);
439 void renderSolid(Renderer& renderer, const VolumeTest& volume) const
441 for(TargetableInstances::const_iterator i = m_instances.begin(); i != m_instances.end(); ++i)
443 if((*i)->path().top().get().visible())
445 (*i)->render(renderer, volume);
449 void renderWireframe(Renderer& renderer, const VolumeTest& volume) const
451 renderSolid(renderer, volume);
455 typedef Static<RenderableConnectionLines> StaticRenderableConnectionLines;