Exemplo n.º 1
0
/**
 * 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;
}
Exemplo n.º 2
0
static bool Entity_create (const std::string& name, const Vector3& origin)
{
	EntityClass* entityClass = GlobalEntityClassManager().findOrInsert(name, true);

	bool revert = false;
	const bool isModel = (name == "misc_model");
	const bool isSound = (name == "misc_sound");
	const bool isParticle = (name == "misc_particle");
	const bool isStartingPositionActor = (name == "info_player_start") || (name == "info_human_start") || (name
			== "info_alien_start") || (name == "info_civilian_start");
	const bool isStartingPositionUGV = (name == "info_2x2_start");
	const bool isStartingPosition = isStartingPositionActor || isStartingPositionUGV;

	const bool brushesSelected = map::countSelectedBrushes() != 0;

	if (!(entityClass->fixedsize || isModel) && !brushesSelected) {
		throw EntityCreationException(std::string("Unable to create entity \"") + name + "\", no brushes selected");
	}
	UndoableCommand undo("entityCreate -class " + name);

	AABB workzone(AABB::createFromMinMax(GlobalSelectionSystem().getWorkZone().min, GlobalSelectionSystem().getWorkZone().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);

	// set all mandatory fields to default values
	// some will be overwritten later
	Entity *entity = Node_getEntity(node);
	entity->addMandatoryKeyValues();

	if (entityClass->fixedsize || (isModel && !brushesSelected)) {
		selection::algorithm::deleteSelection();

		Transformable* transform = Instance_getTransformable(instance);
		if (transform != 0) {
			transform->setType(TRANSFORM_PRIMITIVE);
			if (isStartingPosition) {
				const int sizeX = (int) ((entityClass->maxs[0] - entityClass->mins[0]) / 2.0);
				const int sizeY = (int) ((entityClass->maxs[1] - entityClass->mins[1]) / 2.0);
				const int sizeZ = (int) ((entityClass->maxs[2] - entityClass->mins[2]) / 2.0);
				const int x = ((int) origin.x() / UNIT_SIZE) * UNIT_SIZE - sizeX;
				const int y = ((int) origin.y() / UNIT_SIZE) * UNIT_SIZE - sizeY;
				const int z = ((int) origin.z() / UNIT_HEIGHT) * UNIT_HEIGHT + sizeZ;
				const Vector3 vec(x, y, z);

				transform->setTranslation(vec);
			} else {
				transform->setTranslation(origin);
			}
			transform->freezeTransform();
		}

		GlobalSelectionSystem().setSelectedAll(false);

		Instance_setSelected(instance, true);
	} else {
		// Add selected brushes as children of non-fixed entity
		Scene_parentSelectedBrushesToEntity(GlobalSceneGraph(), node);
		Scene_forEachChildSelectable(SelectableSetSelected(true), instance.path());
	}

	// TODO tweaking: when right click dropping a light entity, ask for light value in a custom dialog box
	if (name == "light" || name == "light_spot") {
		ui::LightDialog dialog;
		dialog.show();
		if (!dialog.isAborted()) {
			std::string intensity = dialog.getIntensity();
			Vector3 color = dialog.getColor();
			entity->setKeyValue("light", intensity);
			entity->setKeyValue("_color", color.toString());
		} else
			revert = true;
	}

	if (isModel) {
		ui::ModelAndSkin modelAndSkin = ui::ModelSelector::chooseModel();
		if (!modelAndSkin.model.empty()) {
			entity->setKeyValue("model", modelAndSkin.model);
			if (modelAndSkin.skin != -1)
				entity->setKeyValue("skin", string::toString(modelAndSkin.skin));
		} else
			revert = true;
	} else if (isSound) {
		// Display the Sound Chooser to get a sound from the user
		ui::SoundChooser sChooser;
		std::string sound = sChooser.chooseSound();
		if (!sound.empty())
			entity->setKeyValue("noise", sound);
		else
			revert = true;
	} else if (isParticle) {
		ui::ParticleSelector pSelector;
		std::string particle = pSelector.chooseParticle();
		if (!particle.empty())
			entity->setKeyValue("particle", particle);
		else
			revert = true;
	}

	return revert;
}