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
25 #include "selectable.h"
26 #include "namespace.h"
29 #include "entitylib.h"
30 #include "eclasslib.h"
33 #include "targetable.h"
34 #include "uniquenames.h"
36 #include "stream/stringstream.h"
40 #include "miscmodel.h"
43 #include "eclassmodel.h"
45 #include "doom3group.h"
51 inline scene::Node& entity_for_eclass( EntityClass* eclass ){
52 if ( ( string_compare_nocase_n( eclass->name(), "misc_", 5 ) == 0 && string_equal_nocase( eclass->name() + string_length( eclass->name() ) - 5, "model" ) ) // misc_*model (also misc_model) // TODO make classname_* wrapper functions for this
53 || classname_equal( eclass->name(), "model_static" ) ) {
54 return New_MiscModel( eclass );
56 else if ( classname_equal( eclass->name(), "light" )
57 || classname_equal( eclass->name(), "lightJunior" ) ) {
58 return New_Light( eclass );
60 if ( !eclass->fixedsize ) {
61 if ( g_gameType == eGameTypeDoom3 ) {
62 return New_Doom3Group( eclass );
66 return New_Group( eclass );
69 else if ( !string_empty( eclass->modelpath() ) ) {
70 return New_EclassModel( eclass );
74 return New_GenericEntity( eclass );
78 void Entity_setName( Entity& entity, const char* name ){
79 entity.setKeyValue( "name", name );
81 typedef ReferenceCaller<Entity, void(const char*), Entity_setName> EntitySetNameCaller;
83 inline Namespaced* Node_getNamespaced( scene::Node& node ){
84 return NodeTypeCast<Namespaced>::cast( node );
87 inline scene::Node& node_for_eclass( EntityClass* eclass ){
88 scene::Node& node = entity_for_eclass( eclass );
89 Node_getEntity( node )->setKeyValue( "classname", eclass->name() );
91 if ( g_gameType == eGameTypeDoom3
92 && string_not_empty( eclass->name() )
93 && !string_equal( eclass->name(), "worldspawn" )
94 && !string_equal( eclass->name(), "UNKNOWN_CLASS" ) ) {
96 strcpy( buffer, eclass->name() );
97 strcat( buffer, "_1" );
98 GlobalNamespace().makeUnique( buffer, EntitySetNameCaller( *Node_getEntity( node ) ) );
101 Namespaced* namespaced = Node_getNamespaced( node );
102 if ( namespaced != 0 ) {
103 namespaced->setNamespace( GlobalNamespace() );
109 EntityCreator::KeyValueChangedFunc EntityKeyValues::m_entityKeyValueChanged = 0;
110 EntityCreator::KeyValueChangedFunc KeyValue::m_entityKeyValueChanged = 0;
111 Counter* EntityKeyValues::m_counter = 0;
113 bool g_showNames = true;
114 bool g_showAngles = true;
115 bool g_newLightDraw = true;
116 bool g_lightRadii = false;
118 class ConnectEntities
124 ConnectEntities( Entity* e1, Entity* e2, int index ) : m_e1( e1 ), m_e2( e2 ), m_index( index ){
126 const char *keyname(){
127 StringOutputStream key( 16 );
128 if ( m_index <= 0 ) {
131 if ( m_index == 1 ) {
134 key << "target" << m_index;
137 void connect( const char* name ){
138 m_e1->setKeyValue( keyname(), name );
139 m_e2->setKeyValue( "targetname", name );
141 typedef MemberCaller<ConnectEntities, void(const char*), &ConnectEntities::connect> ConnectCaller;
144 inline Entity* ScenePath_getEntity( const scene::Path& path ){
145 Entity* entity = Node_getEntity( path.top() );
147 entity = Node_getEntity( path.parent() );
152 class Quake3EntityCreator : public EntityCreator
155 scene::Node& createEntity( EntityClass* eclass ){
156 return node_for_eclass( eclass );
158 void setKeyValueChangedFunc( KeyValueChangedFunc func ){
159 EntityKeyValues::setKeyValueChangedFunc( func );
161 void setCounter( Counter* counter ){
162 EntityKeyValues::setCounter( counter );
164 void connectEntities( const scene::Path& path, const scene::Path& targetPath, int index ){
165 Entity* e1 = ScenePath_getEntity( path );
166 Entity* e2 = ScenePath_getEntity( targetPath );
168 if ( e1 == 0 || e2 == 0 ) {
169 globalErrorStream() << "entityConnectSelected: both of the selected instances must be an entity\n";
174 globalErrorStream() << "entityConnectSelected: the selected instances must not both be from the same entity\n";
179 UndoableCommand undo( "entityConnectSelected" );
181 if ( g_gameType == eGameTypeDoom3 ) {
182 StringOutputStream key( 16 );
188 e1->setKeyValue( key.c_str(), e2->getKeyValue( "name" ) );
193 for ( unsigned int i = 0; ; ++i )
199 const char* value = e1->getKeyValue( key.c_str() );
200 if ( string_empty( value ) ) {
201 e1->setKeyValue( key.c_str(), e2->getKeyValue( "name" ) );
210 ConnectEntities connector( e1, e2, index );
211 const char* value = e2->getKeyValue( "targetname" );
212 if ( !string_empty( value ) ) {
213 connector.connect( value );
217 const char* type = e2->getKeyValue( "classname" );
218 if ( string_empty( type ) ) {
221 StringOutputStream key( 64 );
223 GlobalNamespace().makeUnique( key.c_str(), ConnectEntities::ConnectCaller( connector ) );
229 void setLightRadii( bool lightRadii ){
230 g_lightRadii = lightRadii;
232 bool getLightRadii() const {
235 void setShowNames( bool showNames ){
236 g_showNames = showNames;
241 void setShowAngles( bool showAngles ){
242 g_showAngles = showAngles;
244 bool getShowAngles(){
248 void printStatistics() const {
249 StringPool_analyse( EntityKeyValues::getPool() );
253 Quake3EntityCreator g_Quake3EntityCreator;
255 EntityCreator& GetEntityCreator(){
256 return g_Quake3EntityCreator;
261 class filter_entity_classname : public EntityFilter
263 const char* m_classname;
265 filter_entity_classname( const char* classname ) : m_classname( classname ){
267 bool filter( const Entity& entity ) const {
268 return string_equal( entity.getKeyValue( "classname" ), m_classname );
272 class filter_entity_classgroup : public EntityFilter
274 const char* m_classgroup;
275 std::size_t m_length;
277 filter_entity_classgroup( const char* classgroup ) : m_classgroup( classgroup ), m_length( string_length( m_classgroup ) ){
279 bool filter( const Entity& entity ) const {
280 return string_equal_n( entity.getKeyValue( "classname" ), m_classgroup, m_length );
284 filter_entity_classname g_filter_entity_world( "worldspawn" );
285 filter_entity_classname g_filter_entity_func_group( "func_group" );
286 filter_entity_classname g_filter_entity_light( "light" );
287 filter_entity_classname g_filter_entity_misc_model( "misc_model" );
288 filter_entity_classname g_filter_entity_misc_gamemodel( "misc_gamemodel" );
289 filter_entity_classgroup g_filter_entity_trigger( "trigger_" );
290 filter_entity_classgroup g_filter_entity_path( "path_" );
292 class filter_entity_doom3model : public EntityFilter
295 bool filter( const Entity& entity ) const {
296 return string_equal( entity.getKeyValue( "classname" ), "func_static" )
297 && !string_equal( entity.getKeyValue( "model" ), entity.getKeyValue( "name" ) );
301 filter_entity_doom3model g_filter_entity_doom3model;
304 void Entity_InitFilters(){
305 add_entity_filter( g_filter_entity_world, EXCLUDE_WORLD );
306 add_entity_filter( g_filter_entity_func_group, EXCLUDE_WORLD );
307 add_entity_filter( g_filter_entity_world, EXCLUDE_ENT, true );
308 add_entity_filter( g_filter_entity_trigger, EXCLUDE_TRIGGERS );
309 add_entity_filter( g_filter_entity_misc_model, EXCLUDE_MODELS );
310 add_entity_filter( g_filter_entity_misc_gamemodel, EXCLUDE_MODELS );
311 add_entity_filter( g_filter_entity_doom3model, EXCLUDE_MODELS );
312 add_entity_filter( g_filter_entity_light, EXCLUDE_LIGHTS );
313 add_entity_filter( g_filter_entity_path, EXCLUDE_PATHS );
317 #include "preferencesystem.h"
319 void Entity_Construct( EGameType gameType ){
320 g_gameType = gameType;
321 if ( g_gameType == eGameTypeDoom3 ) {
322 g_targetable_nameKey = "name";
324 Static<KeyIsName>::instance().m_keyIsName = keyIsNameDoom3;
325 Static<KeyIsName>::instance().m_nameKey = "name";
329 Static<KeyIsName>::instance().m_keyIsName = keyIsNameQuake3;
330 Static<KeyIsName>::instance().m_nameKey = "targetname";
333 GlobalPreferenceSystem().registerPreference( "SI_ShowNames", make_property_string( g_showNames ) );
334 GlobalPreferenceSystem().registerPreference( "SI_ShowAngles", make_property_string( g_showAngles ) );
335 GlobalPreferenceSystem().registerPreference( "NewLightStyle", make_property_string( g_newLightDraw ) );
336 GlobalPreferenceSystem().registerPreference( "LightRadiuses", make_property_string( g_lightRadii ) );
338 Entity_InitFilters();
339 LightType lightType = LIGHTTYPE_DEFAULT;
340 if ( g_gameType == eGameTypeRTCW ) {
341 lightType = LIGHTTYPE_RTCW;
343 else if ( g_gameType == eGameTypeDoom3 ) {
344 lightType = LIGHTTYPE_DOOM3;
346 Light_Construct( lightType );
347 MiscModel_construct();
348 Doom3Group_construct();
350 RenderablePivot::StaticShader::instance() = GlobalShaderCache().capture( "$PIVOT" );
352 GlobalShaderCache().attachRenderable( StaticRenderableConnectionLines::instance() );
355 void Entity_Destroy(){
356 GlobalShaderCache().detachRenderable( StaticRenderableConnectionLines::instance() );
358 GlobalShaderCache().release( "$PIVOT" );
360 Doom3Group_destroy();