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 any entity which has a fixed size specified in its entity-definition and displays a model (e.g. ammo_bfg).
25 /// This entity displays the model specified in its entity-definition.
26 /// The "origin" and "angle" keys directly control the entity's local-to-parent transform.
27 /// The "rotation" key directly controls the entity's local-to-parent transform for Doom3 only.
29 #include "eclassmodel.h"
32 #include "renderable.h"
35 #include "selectionlib.h"
36 #include "instancelib.h"
37 #include "transformlib.h"
38 #include "traverselib.h"
39 #include "entitylib.h"
41 #include "eclasslib.h"
44 #include "targetable.h"
50 #include "namedentity.h"
51 #include "keyobservers.h"
53 #include "modelskinkey.h"
60 MatrixTransform m_transform;
61 EntityKeyValues m_entity;
62 KeyObserverMap m_keyObservers;
64 OriginKey m_originKey;
68 RotationKey m_rotationKey;
70 SingletonModel m_model;
72 ClassnameFilter m_filter;
75 RenderablePivot m_renderOrigin;
76 RenderableNamedEntity m_renderName;
79 Callback<void()> m_transformChanged;
80 Callback<void()> m_evaluateTransform;
83 default_rotation( m_rotation );
85 m_keyObservers.insert( "classname", ClassnameFilter::ClassnameChangedCaller( m_filter ) );
86 m_keyObservers.insert( Static<KeyIsName>::instance().m_nameKey, NamedEntity::IdentifierChangedCaller( m_named ) );
87 if ( g_gameType == eGameTypeDoom3 ) {
88 m_keyObservers.insert( "angle", RotationKey::AngleChangedCaller( m_rotationKey ) );
89 m_keyObservers.insert( "rotation", RotationKey::RotationChangedCaller( m_rotationKey ) );
93 m_keyObservers.insert( "angle", AngleKey::AngleChangedCaller( m_angleKey ) );
95 m_keyObservers.insert( "origin", OriginKey::OriginChangedCaller( m_originKey ) );
98 // vc 2k5 compiler fix
103 void updateTransform(){
104 m_transform.localToParent() = g_matrix4_identity;
105 matrix4_translate_by_vec3( m_transform.localToParent(), m_origin );
107 if ( g_gameType == eGameTypeDoom3 ) {
108 matrix4_multiply_by_matrix4( m_transform.localToParent(), rotation_toMatrix( m_rotation ) );
112 matrix4_multiply_by_matrix4( m_transform.localToParent(), matrix4_rotation_for_z_degrees( m_angle ) );
115 m_transformChanged();
117 typedef MemberCaller<EclassModel, void(), &EclassModel::updateTransform> UpdateTransformCaller;
119 void originChanged(){
120 m_origin = m_originKey.m_origin;
123 typedef MemberCaller<EclassModel, void(), &EclassModel::originChanged> OriginChangedCaller;
125 m_angle = m_angleKey.m_angle;
128 typedef MemberCaller<EclassModel, void(), &EclassModel::angleChanged> AngleChangedCaller;
129 void rotationChanged(){
130 rotation_assign( m_rotation, m_rotationKey.m_rotation );
133 typedef MemberCaller<EclassModel, void(), &EclassModel::rotationChanged> RotationChangedCaller;
136 scene::Node* node = m_model.getNode();
138 Node_modelSkinChanged( *node );
141 typedef MemberCaller<EclassModel, void(), &EclassModel::skinChanged> SkinChangedCaller;
145 EclassModel( EntityClass* eclass, scene::Node& node, const Callback<void()>& transformChanged, const Callback<void()>& evaluateTransform ) :
147 m_originKey( OriginChangedCaller( *this ) ),
148 m_origin( ORIGINKEY_IDENTITY ),
149 m_angleKey( AngleChangedCaller( *this ) ),
150 m_angle( ANGLEKEY_IDENTITY ),
151 m_rotationKey( RotationChangedCaller( *this ) ),
152 m_filter( m_entity, node ),
154 m_nameKeys( m_entity ),
155 m_renderName( m_named, g_vector3_identity ),
156 m_skin( SkinChangedCaller( *this ) ),
157 m_transformChanged( transformChanged ),
158 m_evaluateTransform( evaluateTransform ){
161 EclassModel( const EclassModel& other, scene::Node& node, const Callback<void()>& transformChanged, const Callback<void()>& evaluateTransform ) :
162 m_entity( other.m_entity ),
163 m_originKey( OriginChangedCaller( *this ) ),
164 m_origin( ORIGINKEY_IDENTITY ),
165 m_angleKey( AngleChangedCaller( *this ) ),
166 m_angle( ANGLEKEY_IDENTITY ),
167 m_rotationKey( RotationChangedCaller( *this ) ),
168 m_filter( m_entity, node ),
170 m_nameKeys( m_entity ),
171 m_renderName( m_named, g_vector3_identity ),
172 m_skin( SkinChangedCaller( *this ) ),
173 m_transformChanged( transformChanged ),
174 m_evaluateTransform( evaluateTransform ){
178 InstanceCounter m_instanceCounter;
179 void instanceAttach( const scene::Path& path ){
180 if ( ++m_instanceCounter.m_count == 1 ) {
181 m_filter.instanceAttach();
182 m_entity.instanceAttach( path_find_mapfile( path.begin(), path.end() ) );
183 m_entity.attach( m_keyObservers );
184 m_model.modelChanged( m_entity.getEntityClass().modelpath() );
185 m_skin.skinChanged( m_entity.getEntityClass().skin() );
188 void instanceDetach( const scene::Path& path ){
189 if ( --m_instanceCounter.m_count == 0 ) {
190 m_skin.skinChanged( "" );
191 m_model.modelChanged( "" );
192 m_entity.detach( m_keyObservers );
193 m_entity.instanceDetach( path_find_mapfile( path.begin(), path.end() ) );
194 m_filter.instanceDetach();
198 EntityKeyValues& getEntity(){
201 const EntityKeyValues& getEntity() const {
205 scene::Traversable& getTraversable(){
206 return m_model.getTraversable();
208 Namespaced& getNamespaced(){
211 Nameable& getNameable(){
214 TransformNode& getTransformNode(){
217 ModelSkin& getModelSkin(){
221 void attach( scene::Traversable::Observer* observer ){
222 m_model.attach( observer );
224 void detach( scene::Traversable::Observer* observer ){
225 m_model.detach( observer );
228 void renderSolid( Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld, bool selected ) const {
230 m_renderOrigin.render( renderer, volume, localToWorld );
233 renderer.SetState( m_entity.getEntityClass().m_state_wire, Renderer::eWireframeOnly );
235 void renderWireframe( Renderer& renderer, const VolumeTest& volume, const Matrix4& localToWorld, bool selected ) const {
236 renderSolid( renderer, volume, localToWorld, selected );
238 renderer.addRenderable( m_renderName, localToWorld );
242 void translate( const Vector3& translation ){
243 m_origin = origin_translated( m_origin, translation );
245 void rotate( const Quaternion& rotation ){
246 if ( g_gameType == eGameTypeDoom3 ) {
247 rotation_rotate( m_rotation, rotation );
251 m_angle = angle_rotated( m_angle, rotation );
254 void snapto( float snap ){
255 m_originKey.m_origin = origin_snapped( m_originKey.m_origin, snap );
256 m_originKey.write( &m_entity );
258 void revertTransform(){
259 m_origin = m_originKey.m_origin;
260 if ( g_gameType == eGameTypeDoom3 ) {
261 rotation_assign( m_rotation, m_rotationKey.m_rotation );
265 m_angle = m_angleKey.m_angle;
268 void freezeTransform(){
269 m_originKey.m_origin = m_origin;
270 m_originKey.write( &m_entity );
271 if ( g_gameType == eGameTypeDoom3 ) {
272 rotation_assign( m_rotationKey.m_rotation, m_rotation );
273 m_rotationKey.write( &m_entity );
277 m_angleKey.m_angle = m_angle;
278 m_angleKey.write( &m_entity );
281 void transformChanged(){
283 m_evaluateTransform();
286 typedef MemberCaller<EclassModel, void(), &EclassModel::transformChanged> TransformChangedCaller;
289 class EclassModelInstance : public TargetableInstance, public TransformModifier, public Renderable
293 InstanceTypeCastTable m_casts;
296 m_casts = TargetableInstance::StaticTypeCasts::instance().get();
297 InstanceStaticCast<EclassModelInstance, Renderable>::install( m_casts );
298 InstanceStaticCast<EclassModelInstance, Transformable>::install( m_casts );
299 InstanceIdentityCast<EclassModelInstance>::install( m_casts );
301 InstanceTypeCastTable& get(){
306 EclassModel& m_contained;
308 typedef LazyStatic<TypeCasts> StaticTypeCasts;
310 STRING_CONSTANT( Name, "EclassModelInstance" );
312 EclassModelInstance( const scene::Path& path, scene::Instance* parent, EclassModel& contained ) :
313 TargetableInstance( path, parent, this, StaticTypeCasts::instance().get(), contained.getEntity(), *this ),
314 TransformModifier( EclassModel::TransformChangedCaller( contained ), ApplyTransformCaller( *this ) ),
315 m_contained( contained ){
316 m_contained.instanceAttach( Instance::path() );
318 StaticRenderableConnectionLines::instance().attach( *this );
320 ~EclassModelInstance(){
321 StaticRenderableConnectionLines::instance().detach( *this );
323 m_contained.instanceDetach( Instance::path() );
325 void renderSolid( Renderer& renderer, const VolumeTest& volume ) const {
326 m_contained.renderSolid( renderer, volume, Instance::localToWorld(), getSelectable().isSelected() );
328 void renderWireframe( Renderer& renderer, const VolumeTest& volume ) const {
329 m_contained.renderWireframe( renderer, volume, Instance::localToWorld(), getSelectable().isSelected() );
332 void evaluateTransform(){
333 if ( getType() == TRANSFORM_PRIMITIVE ) {
334 m_contained.translate( getTranslation() );
335 m_contained.rotate( getRotation() );
338 void applyTransform(){
339 m_contained.revertTransform();
341 m_contained.freezeTransform();
343 typedef MemberCaller<EclassModelInstance, void(), &EclassModelInstance::applyTransform> ApplyTransformCaller;
346 class EclassModelNode :
347 public scene::Node::Symbiot,
348 public scene::Instantiable,
349 public scene::Cloneable,
350 public scene::Traversable::Observer
354 NodeTypeCastTable m_casts;
357 NodeStaticCast<EclassModelNode, scene::Instantiable>::install( m_casts );
358 NodeStaticCast<EclassModelNode, scene::Cloneable>::install( m_casts );
359 NodeContainedCast<EclassModelNode, scene::Traversable>::install( m_casts );
360 NodeContainedCast<EclassModelNode, Snappable>::install( m_casts );
361 NodeContainedCast<EclassModelNode, TransformNode>::install( m_casts );
362 NodeContainedCast<EclassModelNode, Entity>::install( m_casts );
363 NodeContainedCast<EclassModelNode, Nameable>::install( m_casts );
364 NodeContainedCast<EclassModelNode, Namespaced>::install( m_casts );
365 NodeContainedCast<EclassModelNode, ModelSkin>::install( m_casts );
367 NodeTypeCastTable& get(){
374 InstanceSet m_instances;
375 EclassModel m_contained;
378 m_contained.attach( this );
381 m_contained.detach( this );
385 typedef LazyStatic<TypeCasts> StaticTypeCasts;
387 scene::Traversable& get( NullType<scene::Traversable>){
388 return m_contained.getTraversable();
390 Snappable& get( NullType<Snappable>){
393 TransformNode& get( NullType<TransformNode>){
394 return m_contained.getTransformNode();
396 Entity& get( NullType<Entity>){
397 return m_contained.getEntity();
399 Nameable& get( NullType<Nameable>){
400 return m_contained.getNameable();
402 Namespaced& get( NullType<Namespaced>){
403 return m_contained.getNamespaced();
405 ModelSkin& get( NullType<ModelSkin>){
406 return m_contained.getModelSkin();
409 EclassModelNode( EntityClass* eclass ) :
410 m_node( this, this, StaticTypeCasts::instance().get() ),
411 m_contained( eclass, m_node, InstanceSet::TransformChangedCaller( m_instances ), InstanceSetEvaluateTransform<EclassModelInstance>::Caller( m_instances ) ){
414 EclassModelNode( const EclassModelNode& other ) :
415 scene::Node::Symbiot( other ),
416 scene::Instantiable( other ),
417 scene::Cloneable( other ),
418 scene::Traversable::Observer( other ),
419 m_node( this, this, StaticTypeCasts::instance().get() ),
420 m_contained( other.m_contained, m_node, InstanceSet::TransformChangedCaller( m_instances ), InstanceSetEvaluateTransform<EclassModelInstance>::Caller( m_instances ) ){
433 void insert( scene::Node& child ){
434 m_instances.insert( child );
436 void erase( scene::Node& child ){
437 m_instances.erase( child );
440 scene::Node& clone() const {
441 return ( new EclassModelNode( *this ) )->node();
444 scene::Instance* create( const scene::Path& path, scene::Instance* parent ){
445 return new EclassModelInstance( path, parent, m_contained );
447 void forEachInstance( const scene::Instantiable::Visitor& visitor ){
448 m_instances.forEachInstance( visitor );
450 void insert( scene::Instantiable::Observer* observer, const scene::Path& path, scene::Instance* instance ){
451 m_instances.insert( observer, path, instance );
453 scene::Instance* erase( scene::Instantiable::Observer* observer, const scene::Path& path ){
454 return m_instances.erase( observer, path );
458 scene::Node& New_EclassModel( EntityClass* eclass ){
459 return ( new EclassModelNode( eclass ) )->node();