* render direction arrow for group entities, having angle/angles key set or having angle/angles/direction attribute in .ent

draw condition relies on entity.getKeyValue, which also provides default values; thus removed default "0" for all group entities in .def loader
mind to add entity.getOnlySpecifiedKeyValue func or perform by visitor?
This commit is contained in:
Garux 2018-08-16 20:00:58 +03:00
parent 6ad88b42fa
commit c5f2279f4a
8 changed files with 91 additions and 28 deletions

View File

@ -114,6 +114,7 @@ bool fixedsize;
bool unknown; // wasn't found in source
bool miscmodel_is; // also definable via model attribute presence in xml .ent definition
CopiedString m_miscmodel_key;
bool has_angles; // definable via "angle"/"angles"/"direction" attribute presence in xml .ent definition, only affects rendering of group entities angles arrow now
Vector3 mins;
Vector3 maxs;
@ -258,6 +259,7 @@ inline EntityClass* Eclass_Alloc(){
e->unknown = false;
e->miscmodel_is = false;
e->m_miscmodel_key = "model";
e->has_angles = false;
memset( e->flagnames, 0, MAX_FLAGS * 32 );
e->maxs = Vector3( -1,-1,-1 );

View File

@ -83,6 +83,23 @@ inline void arrow_draw( const Vector3& origin, const Vector3& direction_forward,
glEnd();
}
class RenderableArrow : public OpenGLRenderable
{
const Vector3& m_origin;
const Vector3& m_angles;
public:
RenderableArrow( const Vector3& origin, const Vector3& angles )
: m_origin( origin ), m_angles( angles ){
}
void render( RenderStateFlags state ) const {
Matrix4 mat = matrix4_rotation_for_euler_xyz_degrees( m_angles );
arrow_draw( m_origin, matrix4_transformed_direction( mat, Vector3( 1, 0, 0 ) ), matrix4_transformed_direction( mat, Vector3( 0, 1, 0 ) ), matrix4_transformed_direction( mat, Vector3( 0, 0, 1 ) ) );
}
};
class SelectionIntersection;
inline void aabb_testselect( const AABB& aabb, SelectionTest& test, SelectionIntersection& best ){

View File

@ -147,6 +147,17 @@ void angleChanged( const char* value ){
}
typedef MemberCaller1<AnglesKey, const char*, &AnglesKey::angleChanged> AngleChangedCaller;
void groupAngleChanged( const char* value ){
if( strlen( value ) == 2 && value[0] == '-' && value[1] == '1' )
m_angles = Vector3( 0, -90, 0 );
else if( strlen( value ) == 2 && value[0] == '-' && value[1] == '2' )
m_angles = Vector3( 0, 90, 0 );
else
read_angle( m_angles, value );
m_anglesChanged();
}
typedef MemberCaller1<AnglesKey, const char*, &AnglesKey::groupAngleChanged> GroupAngleChangedCaller;
void anglesChanged( const char* value ){
read_angles( m_angles, value );
m_anglesChanged();

View File

@ -51,22 +51,6 @@
#include "entity.h"
class RenderableArrow : public OpenGLRenderable
{
const Vector3& m_origin;
const Vector3& m_angles;
public:
RenderableArrow( const Vector3& origin, const Vector3& angles )
: m_origin( origin ), m_angles( angles ){
}
void render( RenderStateFlags state ) const {
Matrix4 mat = matrix4_rotation_for_euler_xyz_degrees( m_angles );
arrow_draw( m_origin, matrix4_transformed_direction( mat, Vector3( 1, 0, 0 ) ), matrix4_transformed_direction( mat, Vector3( 0, 1, 0 ) ), matrix4_transformed_direction( mat, Vector3( 0, 0, 1 ) ) );
}
};
inline void read_aabb( AABB& aabb, const EntityClass& eclass ){
aabb = aabb_for_minmax( eclass.mins, eclass.maxs );
}

View File

@ -68,6 +68,15 @@ Vector3 m_origin;
mutable Vector3 m_name_origin;
RenderableNamedEntity m_renderName;
AnglesKey m_anglesKey;
RenderableArrow m_arrow;
bool m_anglesDraw;
void updateAnglesDraw(){
m_anglesDraw = m_entity.getEntityClass().has_angles || !string_empty( m_entity.getKeyValue( "angle" ) ) || !string_empty( m_entity.getKeyValue( "angles" ) );
SceneChangeNotify();
}
typedef MemberCaller<Group, &Group::updateAnglesDraw> UpdateAnglesDrawCaller;
Callback m_transformChanged;
Callback m_evaluateTransform;
@ -75,6 +84,9 @@ void construct(){
m_keyObservers.insert( "classname", ClassnameFilter::ClassnameChangedCaller( m_filter ) );
m_keyObservers.insert( Static<KeyIsName>::instance().m_nameKey, NamedEntity::IdentifierChangedCaller( m_named ) );
m_keyObservers.insert( "origin", OriginKey::OriginChangedCaller( m_originKey ) );
m_keyObservers.insert( "angle", AnglesKey::GroupAngleChangedCaller( m_anglesKey ) );
m_keyObservers.insert( "angles", AnglesKey::AnglesChangedCaller( m_anglesKey ) );
updateAnglesDraw();
}
public:
@ -87,6 +99,8 @@ Group( EntityClass* eclass, scene::Node& node, const Callback& transformChanged,
m_origin( ORIGINKEY_IDENTITY ),
m_name_origin( g_vector3_identity ),
m_renderName( m_named, m_name_origin, EXCLUDE_NAME ),
m_anglesKey( UpdateAnglesDrawCaller( *this ) ),
m_arrow( m_name_origin, m_anglesKey.m_angles ),
m_transformChanged( transformChanged ),
m_evaluateTransform( evaluateTransform ){
construct();
@ -100,6 +114,8 @@ Group( const Group& other, scene::Node& node, const Callback& transformChanged,
m_origin( ORIGINKEY_IDENTITY ),
m_name_origin( g_vector3_identity ),
m_renderName( m_named, m_name_origin, EXCLUDE_NAME ),
m_anglesKey( UpdateAnglesDrawCaller( *this ) ),
m_arrow( m_name_origin, m_anglesKey.m_angles ),
m_transformChanged( transformChanged ),
m_evaluateTransform( evaluateTransform ){
construct();
@ -151,23 +167,52 @@ void detach( scene::Traversable::Observer* observer ){
}
void renderSolid( Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld, bool selected, bool childSelected, const AABB& childBounds ) const {
renderer.SetState( m_entity.getEntityClass().m_state_wire, Renderer::eWireframeOnly );
if ( m_renderName.excluded_not()
&& ( selected || childSelected || ( g_showNames && ( volume.fill() || aabb_fits_view( childBounds, volume.GetModelview(), volume.GetViewport(), g_showNamesRatio ) ) ) ) ) {
// don't draw the name for worldspawn
// if ( !strcmp( m_entity.getEntityClass().name(), "worldspawn" ) ) {
// return;
// }
if ( m_renderName.excluded_not() ) {
// place name in the middle of the "children cloud"
m_name_origin = extents_valid( childBounds.extents.x() )? childBounds.origin : vector4_to_vector3( localToWorld.t() );
m_renderName.render( renderer, volume, g_matrix4_identity, selected, childSelected );
if ( selected || childSelected || g_showNames )
m_renderName.render( renderer, volume, g_matrix4_identity, selected, childSelected );
if ( m_anglesDraw && g_showAngles ) {
if( selected || childSelected ){
renderer.PushState();
renderer.Highlight( Renderer::ePrimitive );
renderer.SetState( m_entity.getEntityClass().m_state_fill, Renderer::eFullMaterials );
renderer.addRenderable( m_arrow, localToWorld );
renderer.PopState();
}
else{
renderer.SetState( m_entity.getEntityClass().m_state_fill, Renderer::eFullMaterials );
renderer.addRenderable( m_arrow, localToWorld );
}
}
}
}
void renderWireframe( Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld, bool selected, bool childSelected, const AABB& childBounds ) const {
renderSolid( renderer, volume, localToWorld, selected, childSelected, childBounds );
renderer.SetState( m_entity.getEntityClass().m_state_wire, Renderer::eWireframeOnly );
// don't draw the name for worldspawn
// if ( !strcmp( m_entity.getEntityClass().name(), "worldspawn" ) ) {
// return;
// }
if ( m_renderName.excluded_not() ) {
// place name in the middle of the "children cloud"
m_name_origin = extents_valid( childBounds.extents.x() )? childBounds.origin : vector4_to_vector3( localToWorld.t() );
if ( selected || childSelected || ( g_showNames && aabb_fits_view( childBounds, volume.GetModelview(), volume.GetViewport(), g_showNamesRatio ) ) )
m_renderName.render( renderer, volume, g_matrix4_identity, selected, childSelected );
if ( m_anglesDraw && g_showAngles ) {
if( selected || childSelected ){
renderer.PushState();
renderer.Highlight( Renderer::ePrimitive );
renderer.addRenderable( m_arrow, localToWorld );
renderer.PopState();
}
else{
renderer.addRenderable( m_arrow, localToWorld );
}
}
}
}
void updateTransform(){

View File

@ -280,7 +280,7 @@ EntityClass *Eclass_InitFromText( const char *text ){
e->m_modelpath = buffer.c_str();
if ( !e->fixedsize ) {
EntityClass_insertAttribute( *e, "angle", EntityClassAttribute( "direction", "Direction", "0" ) );
EntityClass_insertAttribute( *e, "angle", EntityClassAttribute( "direction", "Direction" ) );
}
else
{

View File

@ -56,7 +56,7 @@
/// integer3 three integer values //not supported
/// real floating-point value
/// angle specialisation of real - Yaw angle
/// direction specialisation of real - Yaw angle, -1 = down, -2 = up
/// direction specialisation of real - Yaw angle, -1 = up, -2 = down
/// real3 three floating-point values
/// angles specialisation of real3 - Pitch Yaw Roll
/// color specialisation of real3 - RGB floating-point colour
@ -213,6 +213,9 @@ AttributeImporter( StringOutputStream& comment, EntityClass* entityClass, const
entityClass->miscmodel_is = true;
entityClass->m_miscmodel_key = key;
}
else if( string_equal( type, "angle" ) || string_equal( type, "angles" ) || string_equal( type, "direction" ) ){
entityClass->has_angles = true;
}
m_comment << key;
m_comment << " : ";

View File

@ -534,6 +534,7 @@ void update(){
}
else
{
radio_button_set_active_no_signal( m_radio.m_radio, 2 );
gtk_entry_set_text( m_entry, "0" );
}
}