]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - plugins/entity/miscmodel.cpp
Merge remote-tracking branch 'ttimo/master'
[xonotic/netradiant.git] / plugins / entity / miscmodel.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 the Quake3 misc_model entity.
24 ///
25 /// This entity displays the model specified in its "model" key.
26 /// The "origin", "angles" and "modelscale*" keys directly control the entity's local-to-parent transform.
27
28 #include "cullable.h"
29 #include "renderable.h"
30 #include "editable.h"
31
32 #include "selectionlib.h"
33 #include "instancelib.h"
34 #include "transformlib.h"
35 #include "traverselib.h"
36 #include "entitylib.h"
37 #include "eclasslib.h"
38 #include "render.h"
39 #include "pivot.h"
40
41 #include "targetable.h"
42 #include "origin.h"
43 #include "angles.h"
44 #include "scale.h"
45 #include "model.h"
46 #include "filters.h"
47 #include "namedentity.h"
48 #include "keyobservers.h"
49 #include "namekeys.h"
50
51 #include "entity.h"
52
53 class MiscModel :
54         public Snappable
55 {
56 EntityKeyValues m_entity;
57 KeyObserverMap m_keyObservers;
58 MatrixTransform m_transform;
59
60 OriginKey m_originKey;
61 Vector3 m_origin;
62 AnglesKey m_anglesKey;
63 Vector3 m_angles;
64 ScaleKey m_scaleKey;
65 Vector3 m_scale;
66
67 SingletonModel m_model;
68
69 ClassnameFilter m_filter;
70 NamedEntity m_named;
71 NameKeys m_nameKeys;
72 RenderablePivot m_renderOrigin;
73 RenderableNamedEntity m_renderName;
74
75 Callback m_transformChanged;
76 Callback m_evaluateTransform;
77
78 void construct(){
79         m_keyObservers.insert( "classname", ClassnameFilter::ClassnameChangedCaller( m_filter ) );
80         m_keyObservers.insert( Static<KeyIsName>::instance().m_nameKey, NamedEntity::IdentifierChangedCaller( m_named ) );
81         m_keyObservers.insert( "model", SingletonModel::ModelChangedCaller( m_model ) );
82         m_keyObservers.insert( "origin", OriginKey::OriginChangedCaller( m_originKey ) );
83         m_keyObservers.insert( "angle", AnglesKey::AngleChangedCaller( m_anglesKey ) );
84         m_keyObservers.insert( "angles", AnglesKey::AnglesChangedCaller( m_anglesKey ) );
85         m_keyObservers.insert( "modelscale", ScaleKey::UniformScaleChangedCaller( m_scaleKey ) );
86         m_keyObservers.insert( "modelscale_vec", ScaleKey::ScaleChangedCaller( m_scaleKey ) );
87 }
88
89 void updateTransform(){
90         m_transform.localToParent() = g_matrix4_identity;
91         matrix4_transform_by_euler_xyz_degrees( m_transform.localToParent(), m_origin, m_angles, m_scale );
92         m_transformChanged();
93 }
94
95 // vc 2k5 compiler fix
96 #if _MSC_VER >= 1400
97 public:
98 #endif
99
100 void originChanged(){
101         m_origin = m_originKey.m_origin;
102         updateTransform();
103 }
104 typedef MemberCaller<MiscModel, &MiscModel::originChanged> OriginChangedCaller;
105 void anglesChanged(){
106         m_angles = m_anglesKey.m_angles;
107         updateTransform();
108 }
109 typedef MemberCaller<MiscModel, &MiscModel::anglesChanged> AnglesChangedCaller;
110 void scaleChanged(){
111         m_scale = m_scaleKey.m_scale;
112         updateTransform();
113 }
114 typedef MemberCaller<MiscModel, &MiscModel::scaleChanged> ScaleChangedCaller;
115 public:
116
117 MiscModel( EntityClass* eclass, scene::Node& node, const Callback& transformChanged, const Callback& evaluateTransform ) :
118         m_entity( eclass ),
119         m_originKey( OriginChangedCaller( *this ) ),
120         m_origin( ORIGINKEY_IDENTITY ),
121         m_anglesKey( AnglesChangedCaller( *this ) ),
122         m_angles( ANGLESKEY_IDENTITY ),
123         m_scaleKey( ScaleChangedCaller( *this ) ),
124         m_scale( SCALEKEY_IDENTITY ),
125         m_filter( m_entity, node ),
126         m_named( m_entity ),
127         m_nameKeys( m_entity ),
128         m_renderName( m_named, g_vector3_identity ),
129         m_transformChanged( transformChanged ),
130         m_evaluateTransform( evaluateTransform ){
131         construct();
132 }
133 MiscModel( const MiscModel& other, scene::Node& node, const Callback& transformChanged, const Callback& evaluateTransform ) :
134         m_entity( other.m_entity ),
135         m_originKey( OriginChangedCaller( *this ) ),
136         m_origin( ORIGINKEY_IDENTITY ),
137         m_anglesKey( AnglesChangedCaller( *this ) ),
138         m_angles( ANGLESKEY_IDENTITY ),
139         m_scaleKey( ScaleChangedCaller( *this ) ),
140         m_scale( SCALEKEY_IDENTITY ),
141         m_filter( m_entity, node ),
142         m_named( m_entity ),
143         m_nameKeys( m_entity ),
144         m_renderName( m_named, g_vector3_identity ),
145         m_transformChanged( transformChanged ),
146         m_evaluateTransform( evaluateTransform ){
147         construct();
148 }
149
150 InstanceCounter m_instanceCounter;
151 void instanceAttach( const scene::Path& path ){
152         if ( ++m_instanceCounter.m_count == 1 ) {
153                 m_filter.instanceAttach();
154                 m_entity.instanceAttach( path_find_mapfile( path.begin(), path.end() ) );
155                 m_entity.attach( m_keyObservers );
156         }
157 }
158 void instanceDetach( const scene::Path& path ){
159         if ( --m_instanceCounter.m_count == 0 ) {
160                 m_entity.detach( m_keyObservers );
161                 m_entity.instanceDetach( path_find_mapfile( path.begin(), path.end() ) );
162                 m_filter.instanceDetach();
163         }
164 }
165
166 EntityKeyValues& getEntity(){
167         return m_entity;
168 }
169 const EntityKeyValues& getEntity() const {
170         return m_entity;
171 }
172
173 scene::Traversable& getTraversable(){
174         return m_model.getTraversable();
175 }
176 Namespaced& getNamespaced(){
177         return m_nameKeys;
178 }
179 Nameable& getNameable(){
180         return m_named;
181 }
182 TransformNode& getTransformNode(){
183         return m_transform;
184 }
185
186 void attach( scene::Traversable::Observer* observer ){
187         m_model.attach( observer );
188 }
189 void detach( scene::Traversable::Observer* observer ){
190         m_model.detach( observer );
191 }
192
193 void renderSolid( Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld, bool selected ) const {
194         if ( selected ) {
195                 m_renderOrigin.render( renderer, volume, localToWorld );
196         }
197
198         renderer.SetState( m_entity.getEntityClass().m_state_wire, Renderer::eWireframeOnly );
199 }
200 void renderWireframe( Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld, bool selected ) const {
201         renderSolid( renderer, volume, localToWorld, selected );
202         if ( g_showNames ) {
203                 renderer.addRenderable( m_renderName, localToWorld );
204         }
205 }
206
207 void translate( const Vector3& translation ){
208         m_origin = origin_translated( m_origin, translation );
209 }
210 void rotate( const Quaternion& rotation ){
211         m_angles = angles_rotated( m_angles, rotation );
212 }
213 void scale( const Vector3& scaling ){
214         m_scale = scale_scaled( m_scale, scaling );
215 }
216 void snapto( float snap ){
217         m_originKey.m_origin = origin_snapped( m_originKey.m_origin, snap );
218         m_originKey.write( &m_entity );
219 }
220 void revertTransform(){
221         m_origin = m_originKey.m_origin;
222         m_angles = m_anglesKey.m_angles;
223         m_scale = m_scaleKey.m_scale;
224 }
225 void freezeTransform(){
226         m_originKey.m_origin = m_origin;
227         m_originKey.write( &m_entity );
228         m_anglesKey.m_angles = m_angles;
229         m_anglesKey.write( &m_entity );
230         m_scaleKey.m_scale = m_scale;
231         m_scaleKey.write( &m_entity );
232 }
233 void transformChanged(){
234         revertTransform();
235         m_evaluateTransform();
236         updateTransform();
237 }
238 typedef MemberCaller<MiscModel, &MiscModel::transformChanged> TransformChangedCaller;
239 };
240
241 class MiscModelInstance : public TargetableInstance, public TransformModifier, public Renderable
242 {
243 class TypeCasts
244 {
245 InstanceTypeCastTable m_casts;
246 public:
247 TypeCasts(){
248         m_casts = TargetableInstance::StaticTypeCasts::instance().get();
249         InstanceStaticCast<MiscModelInstance, Renderable>::install( m_casts );
250         InstanceStaticCast<MiscModelInstance, Transformable>::install( m_casts );
251         InstanceIdentityCast<MiscModelInstance>::install( m_casts );
252 }
253 InstanceTypeCastTable& get(){
254         return m_casts;
255 }
256 };
257
258 MiscModel& m_contained;
259 public:
260 typedef LazyStatic<TypeCasts> StaticTypeCasts;
261
262 STRING_CONSTANT( Name, "MiscModelInstance" );
263
264 MiscModelInstance( const scene::Path& path, scene::Instance* parent, MiscModel& miscmodel ) :
265         TargetableInstance( path, parent, this, StaticTypeCasts::instance().get(), miscmodel.getEntity(), *this ),
266         TransformModifier( MiscModel::TransformChangedCaller( miscmodel ), ApplyTransformCaller( *this ) ),
267         m_contained( miscmodel ){
268         m_contained.instanceAttach( Instance::path() );
269         StaticRenderableConnectionLines::instance().attach( *this );
270 }
271 ~MiscModelInstance(){
272         StaticRenderableConnectionLines::instance().detach( *this );
273         m_contained.instanceDetach( Instance::path() );
274 }
275 void renderSolid( Renderer& renderer, const VolumeTest& volume ) const {
276         m_contained.renderSolid( renderer, volume, Instance::localToWorld(), getSelectable().isSelected() );
277 }
278 void renderWireframe( Renderer& renderer, const VolumeTest& volume ) const {
279         m_contained.renderWireframe( renderer, volume, Instance::localToWorld(), getSelectable().isSelected() );
280 }
281 void evaluateTransform(){
282         if ( getType() == TRANSFORM_PRIMITIVE ) {
283                 m_contained.translate( getTranslation() );
284                 m_contained.rotate( getRotation() );
285                 m_contained.scale( getScale() );
286         }
287 }
288 void applyTransform(){
289         m_contained.revertTransform();
290         evaluateTransform();
291         m_contained.freezeTransform();
292 }
293 typedef MemberCaller<MiscModelInstance, &MiscModelInstance::applyTransform> ApplyTransformCaller;
294 };
295
296 class MiscModelNode :
297         public scene::Node::Symbiot,
298         public scene::Instantiable,
299         public scene::Cloneable,
300         public scene::Traversable::Observer
301 {
302 class TypeCasts
303 {
304 NodeTypeCastTable m_casts;
305 public:
306 TypeCasts(){
307         NodeStaticCast<MiscModelNode, scene::Instantiable>::install( m_casts );
308         NodeStaticCast<MiscModelNode, scene::Cloneable>::install( m_casts );
309         NodeContainedCast<MiscModelNode, scene::Traversable>::install( m_casts );
310         NodeContainedCast<MiscModelNode, Snappable>::install( m_casts );
311         NodeContainedCast<MiscModelNode, TransformNode>::install( m_casts );
312         NodeContainedCast<MiscModelNode, Entity>::install( m_casts );
313         NodeContainedCast<MiscModelNode, Nameable>::install( m_casts );
314         NodeContainedCast<MiscModelNode, Namespaced>::install( m_casts );
315 }
316 NodeTypeCastTable& get(){
317         return m_casts;
318 }
319 };
320
321
322 scene::Node m_node;
323 InstanceSet m_instances;
324 MiscModel m_contained;
325
326 void construct(){
327         m_contained.attach( this );
328 }
329 void destroy(){
330         m_contained.detach( this );
331 }
332
333 public:
334 typedef LazyStatic<TypeCasts> StaticTypeCasts;
335
336 scene::Traversable& get( NullType<scene::Traversable>){
337         return m_contained.getTraversable();
338 }
339 Snappable& get( NullType<Snappable>){
340         return m_contained;
341 }
342 TransformNode& get( NullType<TransformNode>){
343         return m_contained.getTransformNode();
344 }
345 Entity& get( NullType<Entity>){
346         return m_contained.getEntity();
347 }
348 Nameable& get( NullType<Nameable>){
349         return m_contained.getNameable();
350 }
351 Namespaced& get( NullType<Namespaced>){
352         return m_contained.getNamespaced();
353 }
354
355 MiscModelNode( EntityClass* eclass ) :
356         m_node( this, this, StaticTypeCasts::instance().get() ),
357         m_contained( eclass, m_node, InstanceSet::TransformChangedCaller( m_instances ), InstanceSetEvaluateTransform<MiscModelInstance>::Caller( m_instances ) ){
358         construct();
359 }
360 MiscModelNode( const MiscModelNode& other ) :
361         scene::Node::Symbiot( other ),
362         scene::Instantiable( other ),
363         scene::Cloneable( other ),
364         scene::Traversable::Observer( other ),
365         m_node( this, this, StaticTypeCasts::instance().get() ),
366         m_contained( other.m_contained, m_node, InstanceSet::TransformChangedCaller( m_instances ), InstanceSetEvaluateTransform<MiscModelInstance>::Caller( m_instances ) ){
367         construct();
368 }
369 ~MiscModelNode(){
370         destroy();
371 }
372
373 void release(){
374         delete this;
375 }
376 scene::Node& node(){
377         return m_node;
378 }
379
380 scene::Node& clone() const {
381         return ( new MiscModelNode( *this ) )->node();
382 }
383
384 void insert( scene::Node& child ){
385         m_instances.insert( child );
386 }
387 void erase( scene::Node& child ){
388         m_instances.erase( child );
389 }
390
391 scene::Instance* create( const scene::Path& path, scene::Instance* parent ){
392         return new MiscModelInstance( path, parent, m_contained );
393 }
394 void forEachInstance( const scene::Instantiable::Visitor& visitor ){
395         m_instances.forEachInstance( visitor );
396 }
397 void insert( scene::Instantiable::Observer* observer, const scene::Path& path, scene::Instance* instance ){
398         m_instances.insert( observer, path, instance );
399 }
400 scene::Instance* erase( scene::Instantiable::Observer* observer, const scene::Path& path ){
401         return m_instances.erase( observer, path );
402 }
403 };
404
405 scene::Node& New_MiscModel( EntityClass* eclass ){
406         return ( new MiscModelNode( eclass ) )->node();
407 }
408
409 void MiscModel_construct(){
410 }
411 void MiscModel_destroy(){
412 }