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
23 ///\brief Represents the Quake3 misc_model entity.
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.
29 #include "renderable.h"
32 #include "selectionlib.h"
33 #include "instancelib.h"
34 #include "transformlib.h"
35 #include "traverselib.h"
36 #include "entitylib.h"
37 #include "eclasslib.h"
41 #include "targetable.h"
47 #include "namedentity.h"
48 #include "keyobservers.h"
56 EntityKeyValues m_entity;
57 KeyObserverMap m_keyObservers;
58 MatrixTransform m_transform;
60 OriginKey m_originKey;
62 AnglesKey m_anglesKey;
67 SingletonModel m_model;
69 ClassnameFilter m_filter;
72 RenderablePivot m_renderOrigin;
73 RenderableNamedEntity m_renderName;
75 Callback<void()> m_transformChanged;
76 Callback<void()> m_evaluateTransform;
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 ) );
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 );
95 // vc 2k5 compiler fix
100 void originChanged(){
101 m_origin = m_originKey.m_origin;
104 typedef MemberCaller<MiscModel, void(), &MiscModel::originChanged> OriginChangedCaller;
105 void anglesChanged(){
106 m_angles = m_anglesKey.m_angles;
109 typedef MemberCaller<MiscModel, void(), &MiscModel::anglesChanged> AnglesChangedCaller;
111 m_scale = m_scaleKey.m_scale;
114 typedef MemberCaller<MiscModel, void(), &MiscModel::scaleChanged> ScaleChangedCaller;
117 MiscModel( EntityClass* eclass, scene::Node& node, const Callback<void()>& transformChanged, const Callback<void()>& evaluateTransform ) :
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 ),
127 m_nameKeys( m_entity ),
128 m_renderName( m_named, g_vector3_identity ),
129 m_transformChanged( transformChanged ),
130 m_evaluateTransform( evaluateTransform ){
133 MiscModel( const MiscModel& other, scene::Node& node, const Callback<void()>& transformChanged, const Callback<void()>& 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 ),
143 m_nameKeys( m_entity ),
144 m_renderName( m_named, g_vector3_identity ),
145 m_transformChanged( transformChanged ),
146 m_evaluateTransform( evaluateTransform ){
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 );
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();
166 EntityKeyValues& getEntity(){
169 const EntityKeyValues& getEntity() const {
173 scene::Traversable& getTraversable(){
174 return m_model.getTraversable();
176 Namespaced& getNamespaced(){
179 Nameable& getNameable(){
182 TransformNode& getTransformNode(){
186 void attach( scene::Traversable::Observer* observer ){
187 m_model.attach( observer );
189 void detach( scene::Traversable::Observer* observer ){
190 m_model.detach( observer );
193 void renderSolid( Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld, bool selected ) const {
195 m_renderOrigin.render( renderer, volume, localToWorld );
198 renderer.SetState( m_entity.getEntityClass().m_state_wire, Renderer::eWireframeOnly );
200 void renderWireframe( Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld, bool selected ) const {
201 renderSolid( renderer, volume, localToWorld, selected );
203 renderer.addRenderable( m_renderName, localToWorld );
207 void translate( const Vector3& translation ){
208 m_origin = origin_translated( m_origin, translation );
210 void rotate( const Quaternion& rotation ){
211 m_angles = angles_rotated( m_angles, rotation );
213 void scale( const Vector3& scaling ){
214 m_scale = scale_scaled( m_scale, scaling );
216 void snapto( float snap ){
217 m_originKey.m_origin = origin_snapped( m_originKey.m_origin, snap );
218 m_originKey.write( &m_entity );
220 void revertTransform(){
221 m_origin = m_originKey.m_origin;
222 m_angles = m_anglesKey.m_angles;
223 m_scale = m_scaleKey.m_scale;
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 );
233 void transformChanged(){
235 m_evaluateTransform();
238 typedef MemberCaller<MiscModel, void(), &MiscModel::transformChanged> TransformChangedCaller;
241 class MiscModelInstance : public TargetableInstance, public TransformModifier, public Renderable
245 InstanceTypeCastTable m_casts;
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 );
253 InstanceTypeCastTable& get(){
258 MiscModel& m_contained;
260 typedef LazyStatic<TypeCasts> StaticTypeCasts;
262 STRING_CONSTANT( Name, "MiscModelInstance" );
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 );
271 ~MiscModelInstance(){
272 StaticRenderableConnectionLines::instance().detach( *this );
273 m_contained.instanceDetach( Instance::path() );
275 void renderSolid( Renderer& renderer, const VolumeTest& volume ) const {
276 m_contained.renderSolid( renderer, volume, Instance::localToWorld(), getSelectable().isSelected() );
278 void renderWireframe( Renderer& renderer, const VolumeTest& volume ) const {
279 m_contained.renderWireframe( renderer, volume, Instance::localToWorld(), getSelectable().isSelected() );
281 void evaluateTransform(){
282 if ( getType() == TRANSFORM_PRIMITIVE ) {
283 m_contained.translate( getTranslation() );
284 m_contained.rotate( getRotation() );
285 m_contained.scale( getScale() );
288 void applyTransform(){
289 m_contained.revertTransform();
291 m_contained.freezeTransform();
293 typedef MemberCaller<MiscModelInstance, void(), &MiscModelInstance::applyTransform> ApplyTransformCaller;
296 class MiscModelNode :
297 public scene::Node::Symbiot,
298 public scene::Instantiable,
299 public scene::Cloneable,
300 public scene::Traversable::Observer
304 NodeTypeCastTable m_casts;
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 );
316 NodeTypeCastTable& get(){
323 InstanceSet m_instances;
324 MiscModel m_contained;
327 m_contained.attach( this );
330 m_contained.detach( this );
334 typedef LazyStatic<TypeCasts> StaticTypeCasts;
336 scene::Traversable& get( NullType<scene::Traversable>){
337 return m_contained.getTraversable();
339 Snappable& get( NullType<Snappable>){
342 TransformNode& get( NullType<TransformNode>){
343 return m_contained.getTransformNode();
345 Entity& get( NullType<Entity>){
346 return m_contained.getEntity();
348 Nameable& get( NullType<Nameable>){
349 return m_contained.getNameable();
351 Namespaced& get( NullType<Namespaced>){
352 return m_contained.getNamespaced();
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 ) ){
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 ) ){
380 scene::Node& clone() const {
381 return ( new MiscModelNode( *this ) )->node();
384 void insert( scene::Node& child ){
385 m_instances.insert( child );
387 void erase( scene::Node& child ){
388 m_instances.erase( child );
391 scene::Instance* create( const scene::Path& path, scene::Instance* parent ){
392 return new MiscModelInstance( path, parent, m_contained );
394 void forEachInstance( const scene::Instantiable::Visitor& visitor ){
395 m_instances.forEachInstance( visitor );
397 void insert( scene::Instantiable::Observer* observer, const scene::Path& path, scene::Instance* instance ){
398 m_instances.insert( observer, path, instance );
400 scene::Instance* erase( scene::Instantiable::Observer* observer, const scene::Path& path ){
401 return m_instances.erase( observer, path );
405 scene::Node& New_MiscModel( EntityClass* eclass ){
406 return ( new MiscModelNode( eclass ) )->node();
409 void MiscModel_construct(){
411 void MiscModel_destroy(){