X-Git-Url: https://de.git.xonotic.org/?p=xonotic%2Fnetradiant.git;a=blobdiff_plain;f=plugins%2Fentity%2Ftargetable.h;h=dc0270f67c726ef1eed1cfddf4abfe5f85c240d1;hp=99046a508f2af58aa491ce95f59d2ba70437ccd9;hb=9dfae1c9b270ee369c6362903a9205b30751b95f;hpb=0a6d5683b0cfa1a0bd7ef64bada105dbe4ddd6e1;ds=sidebyside diff --git a/plugins/entity/targetable.h b/plugins/entity/targetable.h index 99046a50..dc0270f6 100644 --- a/plugins/entity/targetable.h +++ b/plugins/entity/targetable.h @@ -36,363 +36,414 @@ #include "eclasslib.h" #include "stringio.h" -class Targetable -{ +class Targetable { public: -virtual const Vector3& world_position() const = 0; + virtual const Vector3 &world_position() const = 0; }; -typedef std::set targetables_t; +typedef std::set targetables_t; -extern const char* g_targetable_nameKey; +extern const char *g_targetable_nameKey; -targetables_t* getTargetables( const char* targetname ); +targetables_t *getTargetables(const char *targetname); -class EntityConnectionLine : public OpenGLRenderable -{ +class EntityConnectionLine : public OpenGLRenderable { public: -Vector3 start; -Vector3 end; - -void render( RenderStateFlags state ) const { - float s1[2], s2[2]; - Vector3 dir( vector3_subtracted( end, start ) ); - double len = vector3_length( dir ); - vector3_scale( dir, 8.0 * ( 1.0 / len ) ); - s1[0] = dir[0] - dir[1]; - s1[1] = dir[0] + dir[1]; - s2[0] = dir[0] + dir[1]; - s2[1] = -dir[0] + dir[1]; - - glBegin( GL_LINES ); - - glVertex3fv( vector3_to_array( start ) ); - glVertex3fv( vector3_to_array( end ) ); - - len *= 0.0625; // half / 8 - - Vector3 arrow( start ); - for ( unsigned int i = 0, count = ( len < 32 ) ? 1 : static_cast( len * 0.0625 ); i < count; i++ ) - { - vector3_add( arrow, vector3_scaled( dir, ( len < 32 ) ? len : 32 ) ); - glVertex3fv( vector3_to_array( arrow ) ); - glVertex3f( arrow[0] + s1[0], arrow[1] + s1[1], arrow[2] + dir[2] ); - glVertex3fv( vector3_to_array( arrow ) ); - glVertex3f( arrow[0] + s2[0], arrow[1] + s2[1], arrow[2] + dir[2] ); - } - - glEnd(); -} + Vector3 start; + Vector3 end; + + void render(RenderStateFlags state) const + { + float s1[2], s2[2]; + Vector3 dir(vector3_subtracted(end, start)); + double len = vector3_length(dir); + vector3_scale(dir, 8.0 * (1.0 / len)); + s1[0] = dir[0] - dir[1]; + s1[1] = dir[0] + dir[1]; + s2[0] = dir[0] + dir[1]; + s2[1] = -dir[0] + dir[1]; + + glBegin(GL_LINES); + + glVertex3fv(vector3_to_array(start)); + glVertex3fv(vector3_to_array(end)); + + len *= 0.0625; // half / 8 + + Vector3 arrow(start); + for (unsigned int i = 0, count = (len < 32) ? 1 : static_cast( len * 0.0625 ); i < count; i++) { + vector3_add(arrow, vector3_scaled(dir, (len < 32) ? len : 32)); + glVertex3fv(vector3_to_array(arrow)); + glVertex3f(arrow[0] + s1[0], arrow[1] + s1[1], arrow[2] + dir[2]); + glVertex3fv(vector3_to_array(arrow)); + glVertex3f(arrow[0] + s2[0], arrow[1] + s2[1], arrow[2] + dir[2]); + } + + glEnd(); + } }; -class TargetedEntity -{ -Targetable& m_targetable; -targetables_t* m_targets; +class TargetedEntity { + Targetable &m_targetable; + targetables_t *m_targets; -void construct(){ - if ( m_targets != 0 ) { - m_targets->insert( &m_targetable ); - } -} -void destroy(){ - if ( m_targets != 0 ) { - m_targets->erase( &m_targetable ); - } -} -public: -TargetedEntity( Targetable& targetable ) - : m_targetable( targetable ), m_targets( getTargetables( "" ) ){ - construct(); -} -~TargetedEntity(){ - destroy(); -} -void targetnameChanged( const char* name ){ - destroy(); - m_targets = getTargetables( name ); - construct(); -} -typedef MemberCaller TargetnameChangedCaller; -}; + void construct() + { + if (m_targets != 0) { + m_targets->insert(&m_targetable); + } + } + void destroy() + { + if (m_targets != 0) { + m_targets->erase(&m_targetable); + } + } -class TargetingEntity -{ -targetables_t* m_targets; public: -TargetingEntity() : - m_targets( getTargetables( "" ) ){ -} -void targetChanged( const char* target ){ - m_targets = getTargetables( target ); -} -typedef MemberCaller TargetChangedCaller; + TargetedEntity(Targetable &targetable) + : m_targetable(targetable), m_targets(getTargetables("")) + { + construct(); + } + + ~TargetedEntity() + { + destroy(); + } + + void targetnameChanged(const char *name) + { + destroy(); + m_targets = getTargetables(name); + construct(); + } + + typedef MemberCaller TargetnameChangedCaller; +}; -typedef targetables_t::iterator iterator; -iterator begin() const { - if ( m_targets == 0 ) { - return iterator(); - } - return m_targets->begin(); -} -iterator end() const { - if ( m_targets == 0 ) { - return iterator(); - } - return m_targets->end(); -} -size_t size() const { - if ( m_targets == 0 ) { - return 0; - } - return m_targets->size(); -} -bool empty() const { - return m_targets == 0 || m_targets->empty(); -} +class TargetingEntity { + targetables_t *m_targets; +public: + TargetingEntity() : + m_targets(getTargetables("")) + { + } + + void targetChanged(const char *target) + { + m_targets = getTargetables(target); + } + + typedef MemberCaller TargetChangedCaller; + + typedef targetables_t::iterator iterator; + + iterator begin() const + { + if (m_targets == 0) { + return iterator(); + } + return m_targets->begin(); + } + + iterator end() const + { + if (m_targets == 0) { + return iterator(); + } + return m_targets->end(); + } + + size_t size() const + { + if (m_targets == 0) { + return 0; + } + return m_targets->size(); + } + + bool empty() const + { + return m_targets == 0 || m_targets->empty(); + } }; - template -void TargetingEntity_forEach( const TargetingEntity& targets, const Functor& functor ){ - for ( TargetingEntity::iterator i = targets.begin(); i != targets.end(); ++i ) - { - functor( ( *i )->world_position() ); - } +void TargetingEntity_forEach(const TargetingEntity &targets, const Functor &functor) +{ + for (TargetingEntity::iterator i = targets.begin(); i != targets.end(); ++i) { + functor((*i)->world_position()); + } } typedef std::map TargetingEntities; template -void TargetingEntities_forEach( const TargetingEntities& targetingEntities, const Functor& functor ){ - for ( TargetingEntities::const_iterator i = targetingEntities.begin(); i != targetingEntities.end(); ++i ) - { - TargetingEntity_forEach( ( *i ).second, functor ); - } +void TargetingEntities_forEach(const TargetingEntities &targetingEntities, const Functor &functor) +{ + for (TargetingEntities::const_iterator i = targetingEntities.begin(); i != targetingEntities.end(); ++i) { + TargetingEntity_forEach((*i).second, functor); + } } -class TargetLinesPushBack -{ -RenderablePointVector& m_targetLines; -const Vector3& m_worldPosition; -const VolumeTest& m_volume; +class TargetLinesPushBack { + RenderablePointVector &m_targetLines; + const Vector3 &m_worldPosition; + const VolumeTest &m_volume; public: -TargetLinesPushBack( RenderablePointVector& targetLines, const Vector3& worldPosition, const VolumeTest& volume ) : - m_targetLines( targetLines ), m_worldPosition( worldPosition ), m_volume( volume ){ -} -void operator()( const Vector3& worldPosition ) const { - if ( m_volume.TestLine( segment_for_startend( m_worldPosition, worldPosition ) ) ) { - m_targetLines.push_back( PointVertex( reinterpret_cast( m_worldPosition ) ) ); - m_targetLines.push_back( PointVertex( reinterpret_cast( worldPosition ) ) ); - } -} + TargetLinesPushBack(RenderablePointVector &targetLines, const Vector3 &worldPosition, const VolumeTest &volume) : + m_targetLines(targetLines), m_worldPosition(worldPosition), m_volume(volume) + { + } + + void operator()(const Vector3 &worldPosition) const + { + if (m_volume.TestLine(segment_for_startend(m_worldPosition, worldPosition))) { + m_targetLines.push_back(PointVertex(reinterpret_cast( m_worldPosition ))); + m_targetLines.push_back(PointVertex(reinterpret_cast( worldPosition ))); + } + } }; -class TargetKeys : public Entity::Observer -{ -TargetingEntities m_targetingEntities; -Callback m_targetsChanged; - -bool readTargetKey( const char* key, std::size_t& index ){ - if ( string_equal_n( key, "target", 6 ) ) { - index = 0; - if ( string_empty( key + 6 ) || string_parse_size( key + 6, index ) ) { - return true; - } - } - if ( string_equal( key, "killtarget" ) ) { - index = -1; - return true; - } - return false; -} -public: -void setTargetsChanged( const Callback& targetsChanged ){ - m_targetsChanged = targetsChanged; -} -void targetsChanged(){ - m_targetsChanged(); -} +class TargetKeys : public Entity::Observer { + TargetingEntities m_targetingEntities; + Callback m_targetsChanged; + + bool readTargetKey(const char *key, std::size_t &index) + { + if (string_equal_n(key, "target", 6)) { + index = 0; + if (string_empty(key + 6) || string_parse_size(key + 6, index)) { + return true; + } + } + if (string_equal(key, "killtarget")) { + index = -1; + return true; + } + return false; + } -void insert( const char* key, EntityKeyValue& value ){ - std::size_t index; - if ( readTargetKey( key, index ) ) { - TargetingEntities::iterator i = m_targetingEntities.insert( TargetingEntities::value_type( index, TargetingEntity() ) ).first; - value.attach( TargetingEntity::TargetChangedCaller( ( *i ).second ) ); - targetsChanged(); - } -} -void erase( const char* key, EntityKeyValue& value ){ - std::size_t index; - if ( readTargetKey( key, index ) ) { - TargetingEntities::iterator i = m_targetingEntities.find( index ); - value.detach( TargetingEntity::TargetChangedCaller( ( *i ).second ) ); - m_targetingEntities.erase( i ); - targetsChanged(); - } -} -const TargetingEntities& get() const { - return m_targetingEntities; -} +public: + void setTargetsChanged(const Callback &targetsChanged) + { + m_targetsChanged = targetsChanged; + } + + void targetsChanged() + { + m_targetsChanged(); + } + + void insert(const char *key, EntityKeyValue &value) + { + std::size_t index; + if (readTargetKey(key, index)) { + TargetingEntities::iterator i = m_targetingEntities.insert( + TargetingEntities::value_type(index, TargetingEntity())).first; + value.attach(TargetingEntity::TargetChangedCaller((*i).second)); + targetsChanged(); + } + } + + void erase(const char *key, EntityKeyValue &value) + { + std::size_t index; + if (readTargetKey(key, index)) { + TargetingEntities::iterator i = m_targetingEntities.find(index); + value.detach(TargetingEntity::TargetChangedCaller((*i).second)); + m_targetingEntities.erase(i); + targetsChanged(); + } + } + + const TargetingEntities &get() const + { + return m_targetingEntities; + } }; - -class RenderableTargetingEntity -{ -TargetingEntity& m_targets; -mutable RenderablePointVector m_target_lines; +class RenderableTargetingEntity { + TargetingEntity &m_targets; + mutable RenderablePointVector m_target_lines; public: -static Shader* m_state; - -RenderableTargetingEntity( TargetingEntity& targets ) - : m_targets( targets ), m_target_lines( GL_LINES ){ -} -void compile( const VolumeTest& volume, const Vector3& world_position ) const { - m_target_lines.clear(); - m_target_lines.reserve( m_targets.size() * 2 ); - TargetingEntity_forEach( m_targets, TargetLinesPushBack( m_target_lines, world_position, volume ) ); -} -void render( Renderer& renderer, const VolumeTest& volume, const Vector3& world_position ) const { - if ( !m_targets.empty() ) { - compile( volume, world_position ); - if ( !m_target_lines.empty() ) { - renderer.addRenderable( m_target_lines, g_matrix4_identity ); - } - } -} + static Shader *m_state; + + RenderableTargetingEntity(TargetingEntity &targets) + : m_targets(targets), m_target_lines(GL_LINES) + { + } + + void compile(const VolumeTest &volume, const Vector3 &world_position) const + { + m_target_lines.clear(); + m_target_lines.reserve(m_targets.size() * 2); + TargetingEntity_forEach(m_targets, TargetLinesPushBack(m_target_lines, world_position, volume)); + } + + void render(Renderer &renderer, const VolumeTest &volume, const Vector3 &world_position) const + { + if (!m_targets.empty()) { + compile(volume, world_position); + if (!m_target_lines.empty()) { + renderer.addRenderable(m_target_lines, g_matrix4_identity); + } + } + } }; -class RenderableTargetingEntities -{ -const TargetingEntities& m_targets; -mutable RenderablePointVector m_target_lines; +class RenderableTargetingEntities { + const TargetingEntities &m_targets; + mutable RenderablePointVector m_target_lines; public: -static Shader* m_state; - -RenderableTargetingEntities( const TargetingEntities& targets ) - : m_targets( targets ), m_target_lines( GL_LINES ){ -} -void compile( const VolumeTest& volume, const Vector3& world_position ) const { - m_target_lines.clear(); - TargetingEntities_forEach( m_targets, TargetLinesPushBack( m_target_lines, world_position, volume ) ); -} -void render( Renderer& renderer, const VolumeTest& volume, const Vector3& world_position ) const { - if ( !m_targets.empty() ) { - compile( volume, world_position ); - if ( !m_target_lines.empty() ) { - renderer.addRenderable( m_target_lines, g_matrix4_identity ); - } - } -} + static Shader *m_state; + + RenderableTargetingEntities(const TargetingEntities &targets) + : m_targets(targets), m_target_lines(GL_LINES) + { + } + + void compile(const VolumeTest &volume, const Vector3 &world_position) const + { + m_target_lines.clear(); + TargetingEntities_forEach(m_targets, TargetLinesPushBack(m_target_lines, world_position, volume)); + } + + void render(Renderer &renderer, const VolumeTest &volume, const Vector3 &world_position) const + { + if (!m_targets.empty()) { + compile(volume, world_position); + if (!m_target_lines.empty()) { + renderer.addRenderable(m_target_lines, g_matrix4_identity); + } + } + } }; class TargetableInstance : - public SelectableInstance, - public Targetable, - public Entity::Observer -{ -mutable Vertex3f m_position; -EntityKeyValues& m_entity; -TargetKeys m_targeting; -TargetedEntity m_targeted; -RenderableTargetingEntities m_renderable; + public SelectableInstance, + public Targetable, + public Entity::Observer { + mutable Vertex3f m_position; + EntityKeyValues &m_entity; + TargetKeys m_targeting; + TargetedEntity m_targeted; + RenderableTargetingEntities m_renderable; public: -TargetableInstance( - const scene::Path& path, - scene::Instance* parent, - void* instance, - InstanceTypeCastTable& casts, - EntityKeyValues& entity, - Targetable& targetable - ) : - SelectableInstance( path, parent, instance, casts ), - m_entity( entity ), - m_targeted( targetable ), - m_renderable( m_targeting.get() ){ - m_entity.attach( *this ); - m_entity.attach( m_targeting ); -} -~TargetableInstance(){ - m_entity.detach( m_targeting ); - m_entity.detach( *this ); -} - -void setTargetsChanged( const Callback& targetsChanged ){ - m_targeting.setTargetsChanged( targetsChanged ); -} -void targetsChanged(){ - m_targeting.targetsChanged(); -} - -void insert( const char* key, EntityKeyValue& value ){ - if ( string_equal( key, g_targetable_nameKey ) ) { - value.attach( TargetedEntity::TargetnameChangedCaller( m_targeted ) ); - } -} -void erase( const char* key, EntityKeyValue& value ){ - if ( string_equal( key, g_targetable_nameKey ) ) { - value.detach( TargetedEntity::TargetnameChangedCaller( m_targeted ) ); - } -} - -const Vector3& world_position() const { + TargetableInstance( + const scene::Path &path, + scene::Instance *parent, + void *instance, + InstanceTypeCastTable &casts, + EntityKeyValues &entity, + Targetable &targetable + ) : + SelectableInstance(path, parent, instance, casts), + m_entity(entity), + m_targeted(targetable), + m_renderable(m_targeting.get()) + { + m_entity.attach(*this); + m_entity.attach(m_targeting); + } + + ~TargetableInstance() + { + m_entity.detach(m_targeting); + m_entity.detach(*this); + } + + void setTargetsChanged(const Callback &targetsChanged) + { + m_targeting.setTargetsChanged(targetsChanged); + } + + void targetsChanged() + { + m_targeting.targetsChanged(); + } + + void insert(const char *key, EntityKeyValue &value) + { + if (string_equal(key, g_targetable_nameKey)) { + value.attach(TargetedEntity::TargetnameChangedCaller(m_targeted)); + } + } + + void erase(const char *key, EntityKeyValue &value) + { + if (string_equal(key, g_targetable_nameKey)) { + value.detach(TargetedEntity::TargetnameChangedCaller(m_targeted)); + } + } + + const Vector3 &world_position() const + { #if 1 - const AABB& bounds = Instance::worldAABB(); - if ( aabb_valid( bounds ) ) { - return bounds.origin; - } + const AABB &bounds = Instance::worldAABB(); + if (aabb_valid(bounds)) { + return bounds.origin; + } #else - const AABB& childBounds = Instance::childBounds(); - if ( aabb_valid( childBounds ) ) { - return childBounds.origin; - } + const AABB& childBounds = Instance::childBounds(); + if ( aabb_valid( childBounds ) ) { + return childBounds.origin; + } #endif - return vector4_to_vector3( localToWorld().t() ); -} - -void render( Renderer& renderer, const VolumeTest& volume ) const { - renderer.SetState( m_entity.getEntityClass().m_state_wire, Renderer::eWireframeOnly ); - renderer.SetState( m_entity.getEntityClass().m_state_wire, Renderer::eFullMaterials ); - m_renderable.render( renderer, volume, world_position() ); -} - -const TargetingEntities& getTargeting() const { - return m_targeting.get(); -} + return vector4_to_vector3(localToWorld().t()); + } + + void render(Renderer &renderer, const VolumeTest &volume) const + { + renderer.SetState(m_entity.getEntityClass().m_state_wire, Renderer::eWireframeOnly); + renderer.SetState(m_entity.getEntityClass().m_state_wire, Renderer::eFullMaterials); + m_renderable.render(renderer, volume, world_position()); + } + + const TargetingEntities &getTargeting() const + { + return m_targeting.get(); + } }; -class RenderableConnectionLines : public Renderable -{ -typedef std::set TargetableInstances; -TargetableInstances m_instances; +class RenderableConnectionLines : public Renderable { + typedef std::set TargetableInstances; + TargetableInstances m_instances; public: -void attach( TargetableInstance& instance ){ - ASSERT_MESSAGE( m_instances.find( &instance ) == m_instances.end(), "cannot attach instance" ); - m_instances.insert( &instance ); -} -void detach( TargetableInstance& instance ){ - ASSERT_MESSAGE( m_instances.find( &instance ) != m_instances.end(), "cannot detach instance" ); - m_instances.erase( &instance ); -} - -void renderSolid( Renderer& renderer, const VolumeTest& volume ) const { - for ( TargetableInstances::const_iterator i = m_instances.begin(); i != m_instances.end(); ++i ) - { - if ( ( *i )->path().top().get().visible() ) { - ( *i )->render( renderer, volume ); - } - } -} -void renderWireframe( Renderer& renderer, const VolumeTest& volume ) const { - renderSolid( renderer, volume ); -} + void attach(TargetableInstance &instance) + { + ASSERT_MESSAGE(m_instances.find(&instance) == m_instances.end(), "cannot attach instance"); + m_instances.insert(&instance); + } + + void detach(TargetableInstance &instance) + { + ASSERT_MESSAGE(m_instances.find(&instance) != m_instances.end(), "cannot detach instance"); + m_instances.erase(&instance); + } + + void renderSolid(Renderer &renderer, const VolumeTest &volume) const + { + for (TargetableInstances::const_iterator i = m_instances.begin(); i != m_instances.end(); ++i) { + if ((*i)->path().top().get().visible()) { + (*i)->render(renderer, volume); + } + } + } + + void renderWireframe(Renderer &renderer, const VolumeTest &volume) const + { + renderSolid(renderer, volume); + } }; typedef Static StaticRenderableConnectionLines;