]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - plugins/entity/generic.cpp
Merge remote-tracking branch 'ttimo/master'
[xonotic/netradiant.git] / plugins / entity / generic.cpp
1 /*
2    Copyright (C) 2001-2006, William Joseph.
3    All Rights Reserved.
4
5    This file is part of GtkRadiant.
6
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.
11
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.
16
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
20  */
21
22 ///\file
23 ///\brief Represents any entity which has a fixed size specified in its entity-definition and does not display a model (e.g. info_player_start).
24 ///
25 /// This entity displays an axis-aligned bounding box of the size and colour specified in its entity-definition.
26 /// The "origin" key directly controls the entity's local-to-parent transform.
27 /// An arrow is drawn to visualise the "angle" key.
28
29 #include "cullable.h"
30 #include "renderable.h"
31 #include "editable.h"
32
33 #include "math/frustum.h"
34 #include "selectionlib.h"
35 #include "instancelib.h"
36 #include "transformlib.h"
37 #include "entitylib.h"
38 #include "render.h"
39 #include "eclasslib.h"
40 #include "math/line.h"
41
42 #include "targetable.h"
43 #include "origin.h"
44 #include "angles.h"
45 #include "filters.h"
46 #include "namedentity.h"
47 #include "keyobservers.h"
48 #include "namekeys.h"
49 #include "rotation.h"
50
51 #include "entity.h"
52
53
54 class RenderableArrow : public OpenGLRenderable
55 {
56 const Vector3& m_origin;
57 const Vector3& m_angles;
58
59 public:
60 RenderableArrow( const Vector3& origin, const Vector3& angles )
61         : m_origin( origin ), m_angles( angles ){
62 }
63
64 void render( RenderStateFlags state ) const {
65         Matrix4 mat = matrix4_rotation_for_euler_xyz_degrees( m_angles );
66         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 ) ) );
67 }
68 };
69
70 inline void read_aabb( AABB& aabb, const EntityClass& eclass ){
71         aabb = aabb_for_minmax( eclass.mins, eclass.maxs );
72 }
73
74
75 class GenericEntity :
76         public Cullable,
77         public Bounded,
78         public Snappable
79 {
80 EntityKeyValues m_entity;
81 KeyObserverMap m_keyObservers;
82 MatrixTransform m_transform;
83
84 OriginKey m_originKey;
85 Vector3 m_origin;
86 AnglesKey m_anglesKey;
87 Vector3 m_angles;
88
89 ClassnameFilter m_filter;
90 NamedEntity m_named;
91 NameKeys m_nameKeys;
92
93 AABB m_aabb_local;
94
95 RenderableArrow m_arrow;
96 RenderableSolidAABB m_aabb_solid;
97 RenderableWireframeAABB m_aabb_wire;
98 RenderableNamedEntity m_renderName;
99
100 Callback m_transformChanged;
101 Callback m_evaluateTransform;
102
103 void construct(){
104         read_aabb( m_aabb_local, m_entity.getEntityClass() );
105
106         m_keyObservers.insert( "classname", ClassnameFilter::ClassnameChangedCaller( m_filter ) );
107         m_keyObservers.insert( Static<KeyIsName>::instance().m_nameKey, NamedEntity::IdentifierChangedCaller( m_named ) );
108         m_keyObservers.insert( "angle", AnglesKey::AngleChangedCaller( m_anglesKey ) );
109         m_keyObservers.insert( "angles", AnglesKey::AnglesChangedCaller( m_anglesKey ) );
110         m_keyObservers.insert( "origin", OriginKey::OriginChangedCaller( m_originKey ) );
111 }
112
113 // vc 2k5 compiler fix
114 #if _MSC_VER >= 1400
115 public:
116 #endif
117
118 void updateTransform(){
119         m_transform.localToParent() = g_matrix4_identity;
120         matrix4_translate_by_vec3( m_transform.localToParent(), m_origin );
121         m_transformChanged();
122 }
123 typedef MemberCaller<GenericEntity, &GenericEntity::updateTransform> UpdateTransformCaller;
124 void originChanged(){
125         m_origin = m_originKey.m_origin;
126         updateTransform();
127 }
128 typedef MemberCaller<GenericEntity, &GenericEntity::originChanged> OriginChangedCaller;
129 void anglesChanged(){
130         m_angles = m_anglesKey.m_angles;
131         updateTransform();
132 }
133 typedef MemberCaller<GenericEntity, &GenericEntity::anglesChanged> AnglesChangedCaller;
134 public:
135
136 GenericEntity( EntityClass* eclass, scene::Node& node, const Callback& transformChanged, const Callback& evaluateTransform ) :
137         m_entity( eclass ),
138         m_originKey( OriginChangedCaller( *this ) ),
139         m_origin( ORIGINKEY_IDENTITY ),
140         m_anglesKey( AnglesChangedCaller( *this ) ),
141         m_angles( ANGLESKEY_IDENTITY ),
142         m_filter( m_entity, node ),
143         m_named( m_entity ),
144         m_nameKeys( m_entity ),
145         m_arrow( m_aabb_local.origin, m_angles ),
146         m_aabb_solid( m_aabb_local ),
147         m_aabb_wire( m_aabb_local ),
148         m_renderName( m_named, g_vector3_identity ),
149         m_transformChanged( transformChanged ),
150         m_evaluateTransform( evaluateTransform ){
151         construct();
152 }
153 GenericEntity( const GenericEntity& other, scene::Node& node, const Callback& transformChanged, const Callback& evaluateTransform ) :
154         m_entity( other.m_entity ),
155         m_originKey( OriginChangedCaller( *this ) ),
156         m_origin( ORIGINKEY_IDENTITY ),
157         m_anglesKey( AnglesChangedCaller( *this ) ),
158         m_angles( ANGLESKEY_IDENTITY ),
159         m_filter( m_entity, node ),
160         m_named( m_entity ),
161         m_nameKeys( m_entity ),
162         m_arrow( m_aabb_local.origin, m_angles ),
163         m_aabb_solid( m_aabb_local ),
164         m_aabb_wire( m_aabb_local ),
165         m_renderName( m_named, g_vector3_identity ),
166         m_transformChanged( transformChanged ),
167         m_evaluateTransform( evaluateTransform ){
168         construct();
169 }
170
171 InstanceCounter m_instanceCounter;
172 void instanceAttach( const scene::Path& path ){
173         if ( ++m_instanceCounter.m_count == 1 ) {
174                 m_filter.instanceAttach();
175                 m_entity.instanceAttach( path_find_mapfile( path.begin(), path.end() ) );
176                 m_entity.attach( m_keyObservers );
177         }
178 }
179 void instanceDetach( const scene::Path& path ){
180         if ( --m_instanceCounter.m_count == 0 ) {
181                 m_entity.detach( m_keyObservers );
182                 m_entity.instanceDetach( path_find_mapfile( path.begin(), path.end() ) );
183                 m_filter.instanceDetach();
184         }
185 }
186
187 EntityKeyValues& getEntity(){
188         return m_entity;
189 }
190 const EntityKeyValues& getEntity() const {
191         return m_entity;
192 }
193
194 Namespaced& getNamespaced(){
195         return m_nameKeys;
196 }
197 Nameable& getNameable(){
198         return m_named;
199 }
200 TransformNode& getTransformNode(){
201         return m_transform;
202 }
203
204 const AABB& localAABB() const {
205         return m_aabb_local;
206 }
207
208 VolumeIntersectionValue intersectVolume( const VolumeTest& volume, const Matrix4& localToWorld ) const {
209         return volume.TestAABB( localAABB(), localToWorld );
210 }
211
212 void renderArrow( Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld ) const {
213         if ( g_showAngles ) {
214                 renderer.addRenderable( m_arrow, localToWorld );
215         }
216 }
217 void renderSolid( Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld ) const {
218         renderer.SetState( m_entity.getEntityClass().m_state_fill, Renderer::eFullMaterials );
219         renderer.addRenderable( m_aabb_solid, localToWorld );
220         renderArrow( renderer, volume, localToWorld );
221 }
222 void renderWireframe( Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld ) const {
223         renderer.SetState( m_entity.getEntityClass().m_state_wire, Renderer::eWireframeOnly );
224         renderer.addRenderable( m_aabb_wire, localToWorld );
225         renderArrow( renderer, volume, localToWorld );
226         if ( g_showNames ) {
227                 renderer.addRenderable( m_renderName, localToWorld );
228         }
229 }
230
231
232 void testSelect( Selector& selector, SelectionTest& test, const Matrix4& localToWorld ){
233         test.BeginMesh( localToWorld );
234
235         SelectionIntersection best;
236         aabb_testselect( m_aabb_local, test, best );
237         if ( best.valid() ) {
238                 selector.addIntersection( best );
239         }
240 }
241
242 void translate( const Vector3& translation ){
243         m_origin = origin_translated( m_origin, translation );
244 }
245 void rotate( const Quaternion& rotation ){
246         m_angles = angles_rotated( m_angles, rotation );
247 }
248 void snapto( float snap ){
249         m_originKey.m_origin = origin_snapped( m_originKey.m_origin, snap );
250         m_originKey.write( &m_entity );
251 }
252 void revertTransform(){
253         m_origin = m_originKey.m_origin;
254         m_angles = m_anglesKey.m_angles;
255 }
256 void freezeTransform(){
257         m_originKey.m_origin = m_origin;
258         m_originKey.write( &m_entity );
259         m_anglesKey.m_angles = m_angles;
260         m_anglesKey.write( &m_entity );
261 }
262 void transformChanged(){
263         revertTransform();
264         m_evaluateTransform();
265         updateTransform();
266 }
267 typedef MemberCaller<GenericEntity, &GenericEntity::transformChanged> TransformChangedCaller;
268 };
269
270 class GenericEntityInstance :
271         public TargetableInstance,
272         public TransformModifier,
273         public Renderable,
274         public SelectionTestable
275 {
276 class TypeCasts
277 {
278 InstanceTypeCastTable m_casts;
279 public:
280 TypeCasts(){
281         m_casts = TargetableInstance::StaticTypeCasts::instance().get();
282         InstanceContainedCast<GenericEntityInstance, Bounded>::install( m_casts );
283         InstanceContainedCast<GenericEntityInstance, Cullable>::install( m_casts );
284         InstanceStaticCast<GenericEntityInstance, Renderable>::install( m_casts );
285         InstanceStaticCast<GenericEntityInstance, SelectionTestable>::install( m_casts );
286         InstanceStaticCast<GenericEntityInstance, Transformable>::install( m_casts );
287         InstanceIdentityCast<GenericEntityInstance>::install( m_casts );
288 }
289 InstanceTypeCastTable& get(){
290         return m_casts;
291 }
292 };
293
294 GenericEntity& m_contained;
295 mutable AABB m_bounds;
296 public:
297
298 typedef LazyStatic<TypeCasts> StaticTypeCasts;
299
300 Bounded& get( NullType<Bounded>){
301         return m_contained;
302 }
303 Cullable& get( NullType<Cullable>){
304         return m_contained;
305 }
306
307 STRING_CONSTANT( Name, "GenericEntityInstance" );
308
309 GenericEntityInstance( const scene::Path& path, scene::Instance* parent, GenericEntity& contained ) :
310         TargetableInstance( path, parent, this, StaticTypeCasts::instance().get(), contained.getEntity(), *this ),
311         TransformModifier( GenericEntity::TransformChangedCaller( contained ), ApplyTransformCaller( *this ) ),
312         m_contained( contained ){
313         m_contained.instanceAttach( Instance::path() );
314
315         StaticRenderableConnectionLines::instance().attach( *this );
316 }
317 ~GenericEntityInstance(){
318         StaticRenderableConnectionLines::instance().detach( *this );
319
320         m_contained.instanceDetach( Instance::path() );
321 }
322
323 void renderSolid( Renderer& renderer, const VolumeTest& volume ) const {
324         m_contained.renderSolid( renderer, volume, Instance::localToWorld() );
325 }
326 void renderWireframe( Renderer& renderer, const VolumeTest& volume ) const {
327         m_contained.renderWireframe( renderer, volume, Instance::localToWorld() );
328 }
329
330 void testSelect( Selector& selector, SelectionTest& test ){
331         m_contained.testSelect( selector, test, Instance::localToWorld() );
332 }
333
334 void evaluateTransform(){
335         if ( getType() == TRANSFORM_PRIMITIVE ) {
336                 m_contained.translate( getTranslation() );
337                 m_contained.rotate( getRotation() );
338         }
339 }
340 void applyTransform(){
341         m_contained.revertTransform();
342         evaluateTransform();
343         m_contained.freezeTransform();
344 }
345 typedef MemberCaller<GenericEntityInstance, &GenericEntityInstance::applyTransform> ApplyTransformCaller;
346 };
347
348 class GenericEntityNode :
349         public scene::Node::Symbiot,
350         public scene::Instantiable,
351         public scene::Cloneable
352 {
353 class TypeCasts
354 {
355 NodeTypeCastTable m_casts;
356 public:
357 TypeCasts(){
358         NodeStaticCast<GenericEntityNode, scene::Instantiable>::install( m_casts );
359         NodeStaticCast<GenericEntityNode, scene::Cloneable>::install( m_casts );
360         NodeContainedCast<GenericEntityNode, Snappable>::install( m_casts );
361         NodeContainedCast<GenericEntityNode, TransformNode>::install( m_casts );
362         NodeContainedCast<GenericEntityNode, Entity>::install( m_casts );
363         NodeContainedCast<GenericEntityNode, Nameable>::install( m_casts );
364         NodeContainedCast<GenericEntityNode, Namespaced>::install( m_casts );
365 }
366 NodeTypeCastTable& get(){
367         return m_casts;
368 }
369 };
370
371
372 InstanceSet m_instances;
373
374 scene::Node m_node;
375 GenericEntity m_contained;
376
377 public:
378 typedef LazyStatic<TypeCasts> StaticTypeCasts;
379
380 Snappable& get( NullType<Snappable>){
381         return m_contained;
382 }
383 TransformNode& get( NullType<TransformNode>){
384         return m_contained.getTransformNode();
385 }
386 Entity& get( NullType<Entity>){
387         return m_contained.getEntity();
388 }
389 Nameable& get( NullType<Nameable>){
390         return m_contained.getNameable();
391 }
392 Namespaced& get( NullType<Namespaced>){
393         return m_contained.getNamespaced();
394 }
395
396 GenericEntityNode( EntityClass* eclass ) :
397         m_node( this, this, StaticTypeCasts::instance().get() ),
398         m_contained( eclass, m_node, InstanceSet::TransformChangedCaller( m_instances ), InstanceSetEvaluateTransform<GenericEntityInstance>::Caller( m_instances ) ){
399 }
400 GenericEntityNode( const GenericEntityNode& other ) :
401         scene::Node::Symbiot( other ),
402         scene::Instantiable( other ),
403         scene::Cloneable( other ),
404         m_node( this, this, StaticTypeCasts::instance().get() ),
405         m_contained( other.m_contained, m_node, InstanceSet::TransformChangedCaller( m_instances ), InstanceSetEvaluateTransform<GenericEntityInstance>::Caller( m_instances ) ){
406 }
407 void release(){
408         delete this;
409 }
410 scene::Node& node(){
411         return m_node;
412 }
413
414 scene::Node& clone() const {
415         return ( new GenericEntityNode( *this ) )->node();
416 }
417
418 scene::Instance* create( const scene::Path& path, scene::Instance* parent ){
419         return new GenericEntityInstance( path, parent, m_contained );
420 }
421 void forEachInstance( const scene::Instantiable::Visitor& visitor ){
422         m_instances.forEachInstance( visitor );
423 }
424 void insert( scene::Instantiable::Observer* observer, const scene::Path& path, scene::Instance* instance ){
425         m_instances.insert( observer, path, instance );
426 }
427 scene::Instance* erase( scene::Instantiable::Observer* observer, const scene::Path& path ){
428         return m_instances.erase( observer, path );
429 }
430 };
431
432 scene::Node& New_GenericEntity( EntityClass* eclass ){
433         return ( new GenericEntityNode( eclass ) )->node();
434 }