void ConstructRegionBrushes(scene::Node* brushes[6], const Vector3& region_mins, const Vector3& region_maxs) { { // set mins Vector3 mins(region_mins[0]-32, region_mins[1]-32, region_mins[2]-32); // vary maxs for(std::size_t i=0; i<3; i++) { Vector3 maxs(region_maxs[0]+32, region_maxs[1]+32, region_maxs[2]+32); maxs[i] = region_mins[i]; Brush_ConstructCuboid(*Node_getBrush(*brushes[i]), aabb_for_minmax(mins, maxs), texdef_name_default(), TextureProjection()); } } { // set maxs Vector3 maxs(region_maxs[0]+32, region_maxs[1]+32, region_maxs[2]+32); // vary mins for(std::size_t i=0; i<3; i++) { Vector3 mins(region_mins[0]-32, region_mins[1]-32, region_mins[2]-32); mins[i] = region_maxs[i]; Brush_ConstructCuboid(*Node_getBrush(*brushes[i+3]), aabb_for_minmax(mins, maxs), texdef_name_default(), TextureProjection()); } } }
void ConstructRegionBrushes(scene::INodePtr brushes[6], const Vector3& region_mins, const Vector3& region_maxs) { const float THICKNESS = 10; { // set mins Vector3 mins(region_mins[0]-THICKNESS, region_mins[1]-THICKNESS, region_mins[2]-THICKNESS); // vary maxs for(std::size_t i=0; i<3; i++) { Vector3 maxs(region_maxs[0]+THICKNESS, region_maxs[1]+THICKNESS, region_maxs[2]+THICKNESS); maxs[i] = region_mins[i]; Brush_ConstructCuboid(*Node_getBrush(brushes[i]), AABB::createFromMinMax(mins, maxs), texdef_name_default(), TextureProjection()); } } { // set maxs Vector3 maxs(region_maxs[0]+THICKNESS, region_maxs[1]+THICKNESS, region_maxs[2]+THICKNESS); // vary mins for(std::size_t i=0; i<3; i++) { Vector3 mins(region_mins[0]-THICKNESS, region_mins[1]-THICKNESS, region_mins[2]-THICKNESS); mins[i] = region_maxs[i]; Brush_ConstructCuboid(*Node_getBrush(brushes[i+3]), AABB::createFromMinMax(mins, maxs), texdef_name_default(), TextureProjection()); } } }
void mergeSelectedBrushes(const cmd::ArgumentList& args) { // Get the current selection BrushPtrVector brushes = selection::algorithm::getSelectedBrushes(); if (brushes.empty()) { rMessage() << _("CSG Merge: No brushes selected.") << std::endl; wxutil::Messagebox::ShowError(_("CSG Merge: No brushes selected.")); return; } if (brushes.size() < 2) { rMessage() << "CSG Merge: At least two brushes have to be selected.\n"; wxutil::Messagebox::ShowError("CSG Merge: At least two brushes have to be selected."); return; } rMessage() << "CSG Merge: Merging " << brushes.size() << " brushes." << std::endl; UndoableCommand undo("mergeSelectedBrushes"); // Take the last selected node as reference for layers and parent scene::INodePtr merged = GlobalSelectionSystem().ultimateSelected(); scene::INodePtr parent = merged->getParent(); assert(parent != NULL); // Create a new BrushNode scene::INodePtr node = GlobalBrushCreator().createBrush(); // Insert the newly created brush into the (same) parent entity parent->addChildNode(node); // Move the new brush to the same layers as the merged one node->assignToLayers(merged->getLayers()); // Get the contained brush Brush* brush = Node_getBrush(node); // Attempt to merge the selected brushes into the new one if (!Brush_merge(*brush, brushes, true)) { rWarning() << "CSG Merge: Failed - result would not be convex." << std::endl; return; } ASSERT_MESSAGE(!brush->empty(), "brush left with no faces after merge"); // Remove the original brushes for (BrushPtrVector::iterator i = brushes.begin(); i != brushes.end(); ++i) { scene::removeNodeFromParent(*i); } // Select the new brush Node_setSelected(node, true); rMessage() << "CSG Merge: Succeeded." << std::endl; SceneChangeNotify(); }
void surroundWithMonsterclip(const cmd::ArgumentList& args) { UndoableCommand command("addMonsterclip"); // create a ModelFinder and retrieve the modelList selection::algorithm::ModelFinder visitor; GlobalSelectionSystem().foreachSelected(visitor); // Retrieve the list with all the found models from the visitor selection::algorithm::ModelFinder::ModelList list = visitor.getList(); selection::algorithm::ModelFinder::ModelList::iterator iter; for (iter = list.begin(); iter != list.end(); ++iter) { // one of the models in the SelectionStack const scene::INodePtr& node = *iter; // retrieve the AABB AABB brushAABB(node->worldAABB()); // create the brush scene::INodePtr brushNode(GlobalBrushCreator().createBrush()); if (brushNode != NULL) { scene::addNodeToContainer(brushNode, GlobalMap().findOrInsertWorldspawn()); Brush* theBrush = Node_getBrush(brushNode); std::string clipShader = GlobalRegistry().get(RKEY_MONSTERCLIP_SHADER); Scene_BrushResize(*theBrush, brushAABB, clipShader); } } }
bool pre(const scene::Path& path, scene::Instance& instance) const { if(path.top().get().visible()) { Brush* brush = Node_getBrush(path.top()); if(brush != 0 && Brush_hasShader(*brush, m_name)) { Instance_getSelectable(instance)->setSelected(true); } } return true; }
void MapExporter::recalculateBrushWindings() { _root->foreachNode([] (const scene::INodePtr& child)->bool { Brush* brush = Node_getBrush(child); if (brush != NULL) { brush->evaluateBRep(); } return true; }); }
void Scene_BrushResize_Selected(scene::Graph& graph, const AABB& bounds, const std::string& shader) { if(GlobalSelectionSystem().countSelected() != 0) { const scene::INodePtr& node = GlobalSelectionSystem().ultimateSelected(); Brush* brush = Node_getBrush(node); if(brush != 0) { Brush_ConstructCuboid(*brush, bounds, shader, TextureTransform_getDefault()); SceneChangeNotify(); } } }
void Scene_BrushConstructPrefab(scene::Graph& graph, EBrushPrefab type, std::size_t sides, const std::string& shader) { if(GlobalSelectionSystem().countSelected() != 0) { const scene::INodePtr& node = GlobalSelectionSystem().ultimateSelected(); Brush* brush = Node_getBrush(node); if(brush != 0) { AABB bounds = brush->localAABB(); // copy bounds because the brush will be modified Brush_ConstructPrefab(*brush, type, bounds, sides, shader, TextureTransform_getDefault()); SceneChangeNotify(); } } }
bool pre(const scene::INodePtr& node) { if (node->visible()) { Brush* brush = Node_getBrush(node); if (brush != NULL && brush->hasShader(_name)) { Node_setSelected(node, true); return false; // don't traverse brushes } // not a suitable brush, traverse further return true; } else { return false; // don't traverse invisible nodes } }
void Scene_BrushResize_Selected(scene::Graph& graph, const AABB& bounds, const char* shader) { if(GlobalSelectionSystem().countSelected() != 0) { const scene::Path& path = GlobalSelectionSystem().ultimateSelected().path(); Brush* brush = Node_getBrush(path.top()); if(brush != 0) { TextureProjection projection; TexDef_Construct_Default(projection); Brush_ConstructCuboid(*brush, bounds, shader, projection); SceneChangeNotify(); } } }
void Scene_BrushConstructPrefab(scene::Graph& graph, EBrushPrefab type, std::size_t sides, const char* shader) { if(GlobalSelectionSystem().countSelected() != 0) { const scene::Path& path = GlobalSelectionSystem().ultimateSelected().path(); Brush* brush = Node_getBrush(path.top()); if(brush != 0) { AABB bounds = brush->localAABB(); TextureProjection projection; TexDef_Construct_Default(projection); Brush_ConstructPrefab(*brush, type, bounds, sides, shader, projection); SceneChangeNotify(); } } }
// This is called if the selection changes, so that the local list of selected nodes can be updated void RadiantSelectionSystem::onSelectedChanged(const scene::INodePtr& node, const Selectable& selectable) { // Cache the selection state bool isSelected = selectable.isSelected(); int delta = isSelected ? +1 : -1; _countPrimitive += delta; _sigSelectionChanged(selectable); _selectionInfo.totalCount += delta; if (Node_getPatch(node) != NULL) { _selectionInfo.patchCount += delta; } else if (Node_getBrush(node) != NULL) { _selectionInfo.brushCount += delta; } else { _selectionInfo.entityCount += delta; } // If the selectable is selected, add it to the local selection list, otherwise remove it if (isSelected) { _selection.append(node); } else { _selection.erase(node); } // Notify observers, FALSE = primitive selection change notifyObservers(node, false); // Check if the number of selected primitives in the list matches the value of the selection counter ASSERT_MESSAGE(_selection.size() == _countPrimitive, "selection-tracking error"); // Schedule an idle callback requestIdleCallback(); _requestWorkZoneRecalculation = true; _requestSceneGraphChange = true; }
bool Brush_addFace(scene::Node& brush, const _QERFaceData& faceData) { Node_getBrush(brush)->undoSave(); return Node_getBrush(brush)->addPlane(faceData.m_p0, faceData.m_p1, faceData.m_p2, faceData.m_shader, TextureProjection(faceData.m_texdef, brushprimit_texdef_t(), Vector3(0, 0, 0), Vector3(0, 0, 0))) != 0; }
void Brush_forEachFace(scene::Node& brush, const BrushFaceDataCallback& callback) { ::Brush_forEachFace(*Node_getBrush(brush), FaceCallback(BrushFaceDataFromFaceCaller(callback))); }
void BrushByPlaneClipper::split(const BrushPtrVector& brushes) { Plane3 plane(_p0, _p1, _p2); if (!plane.isValid()) { return; } for (BrushPtrVector::const_iterator i = brushes.begin(); i != brushes.end(); ++i) { const BrushNodePtr& node = *i; // Don't clip invisible nodes if (!node->visible()) { continue; } Brush& brush = node->getBrush(); scene::INodePtr parent = node->getParent(); if (!parent) { continue; } // greebo: Analyse the brush to find out which shader is the most used one getMostUsedTexturing(brush); BrushSplitType split = Brush_classifyPlane(brush, _split == eFront ? -plane : plane); if (split.counts[ePlaneBack] && split.counts[ePlaneFront]) { // the plane intersects this brush if (_split == eFrontAndBack) { scene::INodePtr fragmentNode = GlobalBrushCreator().createBrush(); assert(fragmentNode != NULL); // Put the fragment in the same layer as the brush it was clipped from // Do this before adding the fragment to the parent, since there is an // update algorithm setting the visibility of the fragment right there. scene::assignNodeToLayers(fragmentNode, node->getLayers()); // greebo: For copying the texture scale the new node needs to be inserted in the scene // otherwise the shaders cannot be captured and the scale is off // Insert the child into the designated parent scene::addNodeToContainer(fragmentNode, parent); // Select the child Node_setSelected(fragmentNode, true); Brush* fragment = Node_getBrush(fragmentNode); assert(fragment != NULL); fragment->copy(brush); FacePtr newFace = fragment->addPlane(_p0, _p1, _p2, _mostUsedShader, _mostUsedProjection); if (newFace != NULL && _split != eFront) { newFace->flipWinding(); } fragment->removeEmptyFaces(); ASSERT_MESSAGE(!fragment->empty(), "brush left with no faces after split"); } FacePtr newFace = brush.addPlane(_p0, _p1, _p2, _mostUsedShader, _mostUsedProjection); if (newFace != NULL && _split == eFront) { newFace->flipWinding(); } brush.removeEmptyFaces(); ASSERT_MESSAGE(!brush.empty(), "brush left with no faces after split"); } // the plane does not intersect this brush else if (_split != eFrontAndBack && split.counts[ePlaneBack] != 0) { // the brush is "behind" the plane // Remove the node from the scene scene::removeNodeFromParent(node); } } }
void BrushByPlaneClipper::visit(const scene::INodePtr& node) const { // Don't clip invisible nodes if (!node->visible()) { return; } // Try to cast the instance onto a brush Brush* brush = Node_getBrush(node); // Return if not brush if (brush == NULL) { return; } Plane3 plane(_p0, _p1, _p2); if (!plane.isValid()) { return; } // greebo: Analyse the brush to find out which shader is the most used one getMostUsedTexturing(brush); BrushSplitType split = Brush_classifyPlane(*brush, _split == eFront ? -plane : plane); if (split.counts[ePlaneBack] && split.counts[ePlaneFront]) { // the plane intersects this brush if (_split == eFrontAndBack) { scene::INodePtr brushNode = GlobalBrushCreator().createBrush(); assert(brushNode != NULL); Brush* fragment = Node_getBrush(brushNode); assert(fragment != NULL); fragment->copy(*brush); FacePtr newFace = fragment->addPlane(_p0, _p1, _p2, _mostUsedShader, _mostUsedProjection); if (newFace != NULL && _split != eFront) { newFace->flipWinding(); } fragment->removeEmptyFaces(); ASSERT_MESSAGE(!fragment->empty(), "brush left with no faces after split"); // Mark this brush for insertion _insertList.insert(InsertMap::value_type(brushNode, node->getParent())); } FacePtr newFace = brush->addPlane(_p0, _p1, _p2, _mostUsedShader, _mostUsedProjection); if (newFace != NULL && _split == eFront) { newFace->flipWinding(); } brush->removeEmptyFaces(); ASSERT_MESSAGE(!brush->empty(), "brush left with no faces after split"); } // the plane does not intersect this brush else if (_split != eFrontAndBack && split.counts[ePlaneBack] != 0) { // the brush is "behind" the plane _deleteList.insert(node); } }
void post(const scene::INodePtr& node) { if (!node->visible()) { return; } Brush* brush = Node_getBrush(node); if (brush != NULL && !Node_isSelected(node)) { BrushNodePtr brushNode = std::dynamic_pointer_cast<BrushNode>(node); // Get the parent of this brush scene::INodePtr parent = node->getParent(); assert(parent != NULL); // parent should not be NULL BrushPtrVector buffer[2]; std::size_t swap = 0; BrushNodePtr original = std::dynamic_pointer_cast<BrushNode>(brushNode->clone()); //Brush* original = new Brush(*brush); buffer[swap].push_back(original); // Iterate over all selected brushes for (BrushPtrVector::const_iterator i(_brushlist.begin()); i != _brushlist.end(); ++i) { for (BrushPtrVector::iterator j(buffer[swap].begin()); j != buffer[swap].end(); ++j) { if (Brush_subtract(*j, (*i)->getBrush(), buffer[1 - swap])) { // greebo: Delete not necessary, nodes get deleted automatically by clear() below // delete (*j); } else { buffer[1 - swap].push_back(*j); } } buffer[swap].clear(); swap = 1 - swap; } BrushPtrVector& out = buffer[swap]; if (out.size() == 1 && out.back() == original) { // greebo: shared_ptr is taking care of this //delete original; } else { _before++; for (BrushPtrVector::const_iterator i = out.begin(); i != out.end(); ++i) { _after++; scene::INodePtr newBrush = GlobalBrushCreator().createBrush(); parent->addChildNode(newBrush); // Move the new Brush to the same layers as the source node newBrush->assignToLayers(node->getLayers()); (*i)->getBrush().removeEmptyFaces(); ASSERT_MESSAGE(!(*i)->getBrush().empty(), "brush left with no faces after subtract"); Node_getBrush(newBrush)->copy((*i)->getBrush()); } _deleteList.push_back(node); } } }