void Entity_createFromSelection( const char* name, const Vector3& origin ){ #if 0 if ( string_equal_nocase( name, "worldspawn" ) ) { ui::alert( MainFrame_getWindow( ), "Can't create an entity with worldspawn.", "info" ); return; } #endif EntityClass* entityClass = GlobalEntityClassManager().findOrInsert( name, true ); bool isModel = ( string_compare_nocase_n( name, "misc_", 5 ) == 0 && string_equal_nocase( name + string_length( name ) - 5, "model" ) ) // misc_*model (also misc_model) || string_equal_nocase( name, "model_static" ) || ( GlobalSelectionSystem().countSelected() == 0 && string_equal_nocase( name, "func_static" ) ); bool brushesSelected = Scene_countSelectedBrushes( GlobalSceneGraph() ) != 0; if ( !( entityClass->fixedsize || isModel ) && !brushesSelected ) { globalErrorStream() << "failed to create a group entity - no brushes are selected\n"; return; } AABB workzone( aabb_for_minmax( Select_getWorkZone().d_work_min, Select_getWorkZone().d_work_max ) ); NodeSmartReference node( GlobalEntityCreator().createEntity( entityClass ) ); Node_getTraversable( GlobalSceneGraph().root() )->insert( node ); scene::Path entitypath( makeReference( GlobalSceneGraph().root() ) ); entitypath.push( makeReference( node.get() ) ); scene::Instance& instance = findInstance( entitypath ); if ( entityClass->fixedsize || ( isModel && !brushesSelected ) ) { Select_Delete(); Transformable* transform = Instance_getTransformable( instance ); if ( transform != 0 ) { transform->setType( TRANSFORM_PRIMITIVE ); transform->setTranslation( origin ); transform->freezeTransform(); } GlobalSelectionSystem().setSelectedAll( false ); Instance_setSelected( instance, true ); } else { if ( g_pGameDescription->mGameType == "doom3" ) { Node_getEntity( node )->setKeyValue( "model", Node_getEntity( node )->getKeyValue( "name" ) ); } Scene_parentSelectedBrushesToEntity( GlobalSceneGraph(), node ); Scene_forEachChildSelectable( SelectableSetSelected( true ), instance.path() ); } // tweaking: when right clic dropping a light entity, ask for light value in a custom dialog box // see SF bug 105383 if ( g_pGameDescription->mGameType == "hl" ) { // FIXME - Hydra: really we need a combined light AND color dialog for halflife. if ( string_equal_nocase( name, "light" ) || string_equal_nocase( name, "light_environment" ) || string_equal_nocase( name, "light_spot" ) ) { int intensity = g_iLastLightIntensity; if ( DoLightIntensityDlg( &intensity ) == eIDOK ) { g_iLastLightIntensity = intensity; char buf[30]; sprintf( buf, "255 255 255 %d", intensity ); Node_getEntity( node )->setKeyValue( "_light", buf ); } } } else if ( string_equal_nocase( name, "light" ) ) { if ( g_pGameDescription->mGameType != "doom3" ) { int intensity = g_iLastLightIntensity; if ( DoLightIntensityDlg( &intensity ) == eIDOK ) { g_iLastLightIntensity = intensity; char buf[10]; sprintf( buf, "%d", intensity ); Node_getEntity( node )->setKeyValue( "light", buf ); } } else if ( brushesSelected ) { // use workzone to set light position/size for doom3 lights, if there are brushes selected AABB bounds( Doom3Light_getBounds( workzone ) ); StringOutputStream key( 64 ); key << bounds.origin[0] << " " << bounds.origin[1] << " " << bounds.origin[2]; Node_getEntity( node )->setKeyValue( "origin", key.c_str() ); key.clear(); key << bounds.extents[0] << " " << bounds.extents[1] << " " << bounds.extents[2]; Node_getEntity( node )->setKeyValue( "light_radius", key.c_str() ); } } if ( isModel ) { const char* model = misc_model_dialog(MainFrame_getWindow()); if ( model != 0 ) { Node_getEntity( node )->setKeyValue( "model", model ); } } }
/** * Create an instance of the given entity at the given position, and return * the Node containing the new entity. * * @returns: the scene::INodePtr referring to the new entity. */ scene::INodePtr createEntityFromSelection(const std::string& name, const Vector3& origin) { // Obtain the structure containing the selection counts const SelectionInfo& info = GlobalSelectionSystem().getSelectionInfo(); IEntityClassPtr entityClass = GlobalEntityClassManager().findOrInsert(name, true); // TODO: to be replaced by inheritance-based class detection bool isModel = (info.totalCount == 0 && name == "func_static"); // Some entities are based on the size of the currently-selected primitive(s) bool primitivesSelected = info.brushCount > 0 || info.patchCount > 0; if (!(entityClass->isFixedSize() || isModel) && !primitivesSelected) { throw EntityCreationException( (boost::format(_("Unable to create entity %s, no brushes selected.")) % name).str() ); } // Get the selection workzone bounds AABB workzone = GlobalSelectionSystem().getWorkZone().bounds; // Create the new node for the entity IEntityNodePtr node(GlobalEntityCreator().createEntity(entityClass)); GlobalSceneGraph().root()->addChildNode(node); // The layer list we're moving the newly created node/subgraph into scene::LayerList targetLayers; if (entityClass->isFixedSize() || (isModel && !primitivesSelected)) { selection::algorithm::deleteSelection(); ITransformablePtr transform = Node_getTransformable(node); if (transform != 0) { transform->setType(TRANSFORM_PRIMITIVE); transform->setTranslation(origin); transform->freezeTransform(); } GlobalSelectionSystem().setSelectedAll(false); // Move the item to the active layer targetLayers.insert(GlobalLayerSystem().getActiveLayer()); Node_setSelected(node, true); } else // brush-based entity { // Add selected brushes as children of non-fixed entity node->getEntity().setKeyValue("model", node->getEntity().getKeyValue("name")); // Take the selection center as new origin Vector3 newOrigin = selection::algorithm::getCurrentSelectionCenter(); node->getEntity().setKeyValue("origin", string::to_string(newOrigin)); // If there is an "editor_material" class attribute, apply this shader // to all of the selected primitives before parenting them std::string material = node->getEntity().getEntityClass()->getAttribute("editor_material").getValue(); if (!material.empty()) { selection::algorithm::applyShaderToSelection(material); } // If we had primitives to reparent, the new entity should inherit the layer info from them if (primitivesSelected) { scene::INodePtr primitive = GlobalSelectionSystem().ultimateSelected(); targetLayers = primitive->getLayers(); } else { // Otherwise move the item to the active layer targetLayers.insert(GlobalLayerSystem().getActiveLayer()); } // Parent the selected primitives to the new node selection::algorithm::ParentPrimitivesToEntityWalker walker(node); GlobalSelectionSystem().foreachSelected(walker); walker.reparent(); // De-select the children and select the newly created parent entity GlobalSelectionSystem().setSelectedAll(false); Node_setSelected(node, true); } // Assign the layers - including all child nodes (#2864) scene::AssignNodeToLayersWalker layerWalker(targetLayers); Node_traverseSubgraph(node, layerWalker); // Set the light radius and origin if (entityClass->isLight() && primitivesSelected) { AABB bounds(Doom3Light_getBounds(workzone)); node->getEntity().setKeyValue("origin", string::to_string(bounds.getOrigin())); node->getEntity().setKeyValue("light_radius", string::to_string(bounds.getExtents())); } // Flag the map as unsaved after creating the entity GlobalMap().setModified(true); // Check for auto-setting key values. TODO: use forEachClassAttribute // directly here. eclass::AttributeList list = eclass::getSpawnargsWithPrefix( *entityClass, "editor_setKeyValue" ); if (!list.empty()) { for (eclass::AttributeList::const_iterator i = list.begin(); i != list.end(); ++i) { // Cut off the "editor_setKeyValueN " string from the key to get the spawnarg name std::string key = i->getName().substr(i->getName().find_first_of(' ') + 1); node->getEntity().setKeyValue(key, i->getValue()); } } // Return the new node return node; }
void Entity_createFromSelection( const char* name, const Vector3& origin ){ #if 0 if ( string_equal_nocase( name, "worldspawn" ) ) { gtk_MessageBox( GTK_WIDGET( MainFrame_getWindow() ), "Can't create an entity with worldspawn.", "info" ); return; } #else const scene::Node* world_node = Map_FindWorldspawn( g_map ); if ( world_node && string_equal( name, "worldspawn" ) ) { // GlobalRadiant().m_pfnMessageBox( GTK_WIDGET( MainFrame_getWindow() ), "There's already a worldspawn in your map!", "Info", eMB_OK, eMB_ICONDEFAULT ); UndoableCommand undo( "ungroupSelectedPrimitives" ); Scene_parentSelectedBrushesToEntity( GlobalSceneGraph(), Map_FindOrInsertWorldspawn( g_map ) ); //=no action, if no worldspawn (but one inserted) (since insertion deselects everything) //Scene_parentSelectedBrushesToEntity( GlobalSceneGraph(), *Map_FindWorldspawn( g_map ) ); = crash, if no worldspawn return; } #endif StringOutputStream command; command << "entityCreate -class " << name; UndoableCommand undo( command.c_str() ); EntityClass* entityClass = GlobalEntityClassManager().findOrInsert( name, true ); const bool isModel = entityClass->miscmodel_is || ( GlobalSelectionSystem().countSelected() == 0 && classname_equal( name, "func_static" ) && g_pGameDescription->mGameType == "doom3" ); const bool brushesSelected = Scene_countSelectedBrushes( GlobalSceneGraph() ) != 0; //is important to have retexturing here; if doing in the end, undo doesn't succeed; if ( string_compare_nocase_n( name, "trigger_", 8 ) == 0 && brushesSelected && !entityClass->fixedsize ){ //const char* shader = GetCommonShader( "trigger" ).c_str(); Scene_PatchSetShader_Selected( GlobalSceneGraph(), GetCommonShader( "trigger" ).c_str() ); Scene_BrushSetShader_Selected( GlobalSceneGraph(), GetCommonShader( "trigger" ).c_str() ); } if ( !( entityClass->fixedsize || isModel ) && !brushesSelected ) { globalErrorStream() << "failed to create a group entity - no brushes are selected\n"; return; } AABB workzone( aabb_for_minmax( Select_getWorkZone().d_work_min, Select_getWorkZone().d_work_max ) ); NodeSmartReference node( GlobalEntityCreator().createEntity( entityClass ) ); Node_getTraversable( GlobalSceneGraph().root() )->insert( node ); scene::Path entitypath( makeReference( GlobalSceneGraph().root() ) ); entitypath.push( makeReference( node.get() ) ); scene::Instance& instance = findInstance( entitypath ); if ( entityClass->fixedsize || ( isModel && !brushesSelected ) ) { //Select_Delete(); Transformable* transform = Instance_getTransformable( instance ); if ( transform != 0 ) { transform->setType( TRANSFORM_PRIMITIVE ); transform->setTranslation( origin ); transform->freezeTransform(); } GlobalSelectionSystem().setSelectedAll( false ); Instance_setSelected( instance, true ); } else { if ( g_pGameDescription->mGameType == "doom3" ) { Node_getEntity( node )->setKeyValue( "model", Node_getEntity( node )->getKeyValue( "name" ) ); } Scene_parentSelectedBrushesToEntity( GlobalSceneGraph(), node ); Scene_forEachChildSelectable( SelectableSetSelected( true ), instance.path() ); } // tweaking: when right click dropping a light entity, ask for light value in a custom dialog box // see SF bug 105383 if ( g_pGameDescription->mGameType == "hl" ) { // FIXME - Hydra: really we need a combined light AND color dialog for halflife. if ( string_equal_nocase( name, "light" ) || string_equal_nocase( name, "light_environment" ) || string_equal_nocase( name, "light_spot" ) ) { int intensity = g_iLastLightIntensity; if ( DoLightIntensityDlg( &intensity ) == eIDOK ) { g_iLastLightIntensity = intensity; char buf[30]; sprintf( buf, "255 255 255 %d", intensity ); Node_getEntity( node )->setKeyValue( "_light", buf ); } } } else if ( string_equal_nocase( name, "light" ) ) { if ( g_pGameDescription->mGameType != "doom3" ) { int intensity = g_iLastLightIntensity; if ( DoLightIntensityDlg( &intensity ) == eIDOK ) { g_iLastLightIntensity = intensity; char buf[10]; sprintf( buf, "%d", intensity ); Node_getEntity( node )->setKeyValue( "light", buf ); } } else if ( brushesSelected ) { // use workzone to set light position/size for doom3 lights, if there are brushes selected AABB bounds( Doom3Light_getBounds( workzone ) ); StringOutputStream key( 64 ); key << bounds.origin[0] << " " << bounds.origin[1] << " " << bounds.origin[2]; Node_getEntity( node )->setKeyValue( "origin", key.c_str() ); key.clear(); key << bounds.extents[0] << " " << bounds.extents[1] << " " << bounds.extents[2]; Node_getEntity( node )->setKeyValue( "light_radius", key.c_str() ); } } if ( isModel ) { const char* model = misc_model_dialog( GTK_WIDGET( MainFrame_getWindow() ) ); if ( model != 0 ) { Node_getEntity( node )->setKeyValue( entityClass->miscmodel_key() , model ); } } }