void stitchTextures(const cmd::ArgumentList& args) { // Get all the selected patches PatchPtrVector patchList = selection::algorithm::getSelectedPatches(); if (patchList.size() == 2) { UndoableCommand undo("patchStitchTexture"); // Fetch the instances from the selectionsystem const scene::INodePtr& targetNode = GlobalSelectionSystem().ultimateSelected(); const scene::INodePtr& sourceNode = GlobalSelectionSystem().penultimateSelected(); // Cast the instances onto a patch Patch* source = Node_getPatch(sourceNode); Patch* target = Node_getPatch(targetNode); if (source != NULL && target != NULL) { // Stitch the texture leaving the source patch intact target->stitchTextureFrom(*source); } else { gtkutil::MessageBox::ShowError(_("Cannot stitch textures. \nCould not cast nodes to patches."), GlobalMainFrame().getTopLevelWindow()); } SceneChangeNotify(); // Update the Texture Tools ui::SurfaceInspector::update(); } else { gtkutil::MessageBox::ShowError(_("Cannot stitch patch textures. \nExactly 2 patches must be selected."), GlobalMainFrame().getTopLevelWindow()); } }
void constructPrefab(const AABB& aabb, const std::string& shader, EPatchPrefab eType, EViewType viewType, std::size_t width, std::size_t height) { GlobalSelectionSystem().setSelectedAll(false); scene::INodePtr node(GlobalPatchCreator(DEF2).createPatch()); GlobalMap().findOrInsertWorldspawn()->addChildNode(node); Patch* patch = Node_getPatch(node); patch->setShader(shader); patch->ConstructPrefab(aabb, eType, viewType, width, height); patch->controlPointsChanged(); Node_setSelected(node, true); }
// 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; }
Patch& getLastSelectedPatch() { if (GlobalSelectionSystem().getSelectionInfo().totalCount > 0 && GlobalSelectionSystem().getSelectionInfo().patchCount > 0) { // Retrieve the last selected instance const scene::INodePtr& node = GlobalSelectionSystem().ultimateSelected(); // Try to cast it onto a patch Patch* patch = Node_getPatch(node); // Return or throw if (patch != NULL) { return *patch; } else { throw selection::InvalidSelectionException(_("No patches selected.")); } } else { throw selection::InvalidSelectionException(_("No patches selected.")); } }
void createCaps(Patch& patch, const scene::INodePtr& parent, EPatchCap type, const std::string& shader) { if ((type == eCapEndCap || type == eCapIEndCap) && patch.getWidth() != 5) { rError() << "cannot create end-cap - patch width != 5" << std::endl; gtkutil::MessageBox::ShowError(_("Cannot create end-cap, patch must have a width of 5."), GlobalMainFrame().getTopLevelWindow()); return; } if ((type == eCapBevel || type == eCapIBevel) && patch.getWidth() != 3) { gtkutil::MessageBox::ShowError(_("Cannot create bevel-cap, patch must have a width of 3."), GlobalMainFrame().getTopLevelWindow()); rError() << "cannot create bevel-cap - patch width != 3" << std::endl; return; } if (type == eCapCylinder && patch.getWidth() != 9) { gtkutil::MessageBox::ShowError(_("Cannot create cylinder-cap, patch must have a width of 9."), GlobalMainFrame().getTopLevelWindow()); rError() << "cannot create cylinder-cap - patch width != 9" << std::endl; return; } assert(parent != NULL); { scene::INodePtr cap(GlobalPatchCreator(DEF2).createPatch()); parent->addChildNode(cap); Patch* capPatch = Node_getPatch(cap); assert(capPatch != NULL); patch.MakeCap(capPatch, type, ROW, true); capPatch->setShader(shader); // greebo: Avoid creating "degenerate" patches (all vertices merged in one 3D point) if (!capPatch->isDegenerate()) { Node_setSelected(cap, true); } else { parent->removeChildNode(cap); rWarning() << "Prevented insertion of degenerate patch." << std::endl; } } { scene::INodePtr cap(GlobalPatchCreator(DEF2).createPatch()); parent->addChildNode(cap); Patch* capPatch = Node_getPatch(cap); assert(capPatch != NULL); patch.MakeCap(capPatch, type, ROW, false); capPatch->setShader(shader); // greebo: Avoid creating "degenerate" patches (all vertices merged in one 3D point) if (!capPatch->isDegenerate()) { Node_setSelected(cap, true); } else { parent->removeChildNode(cap); rWarning() << "Prevented insertion of degenerate patch." << std::endl; } } }
void thicken(const PatchNodePtr& sourcePatch, float thickness, bool createSeams, int axis) { // Get a shortcut to the patchcreator PatchCreator& patchCreator = GlobalPatchCreator(DEF2); // Create a new patch node scene::INodePtr node(patchCreator.createPatch()); scene::INodePtr parent = sourcePatch->getParent(); assert(parent != NULL); // Insert the node into the same parent as the existing patch parent->addChildNode(node); // Retrieve the contained patch from the node Patch* targetPatch = Node_getPatch(node); // Create the opposite patch with the given thickness = distance targetPatch->createThickenedOpposite(sourcePatch->getPatchInternal(), thickness, axis); // Select the newly created patch Node_setSelected(node, true); if (createSeams && thickness > 0.0f) { // Allocate four new patches scene::INodePtr nodes[4] = { patchCreator.createPatch(), patchCreator.createPatch(), patchCreator.createPatch(), patchCreator.createPatch() }; // Now create the four walls for (int i = 0; i < 4; i++) { // Insert each node into the same parent as the existing patch // It's vital to do this first, otherwise these patches won't have valid shaders parent->addChildNode(nodes[i]); // Retrieve the contained patch from the node Patch* wallPatch = Node_getPatch(nodes[i]); // Create the wall patch by passing i as wallIndex wallPatch->createThickenedWall(sourcePatch->getPatchInternal(), *targetPatch, i); if (!wallPatch->isDegenerate()) { // Now select the newly created patch Node_setSelected(nodes[i], true); } else { rMessage() << "Thicken: Discarding degenerate patch." << std::endl; // Remove again parent->removeChildNode(nodes[i]); } } } // Invert the target patch so that it faces the opposite direction targetPatch->InvertMatrix(); }
void createDecals() { for (FaceInstanceList::iterator i = _faceInstances.begin(); i != _faceInstances.end(); ++i) { // Get the winding const Winding& winding = (*i)->getFace().getWinding(); // Create a new decal patch scene::INodePtr patchNode = GlobalPatchCreator(DEF3).createPatch(); if (patchNode == NULL) { gtkutil::errorDialog(_("Could not create patch."), GlobalMainFrame().getTopLevelWindow()); return; } Patch* patch = Node_getPatch(patchNode); assert(patch != NULL); // must not fail // Set the tesselation of that 3x3 patch patch->setDims(3,3); patch->setFixedSubdivisions(true, Subdivisions(1,1)); // Set the coordinates patch->ctrlAt(0,0).vertex = winding[0].vertex; patch->ctrlAt(2,0).vertex = winding[1].vertex; patch->ctrlAt(1,0).vertex = (patch->ctrlAt(0,0).vertex + patch->ctrlAt(2,0).vertex)/2; patch->ctrlAt(0,1).vertex = (winding[0].vertex + winding[3].vertex)/2; patch->ctrlAt(2,1).vertex = (winding[1].vertex + winding[2].vertex)/2; patch->ctrlAt(1,1).vertex = (patch->ctrlAt(0,1).vertex + patch->ctrlAt(2,1).vertex)/2; patch->ctrlAt(2,2).vertex = winding[2].vertex; patch->ctrlAt(0,2).vertex = winding[3].vertex; patch->ctrlAt(1,2).vertex = (patch->ctrlAt(2,2).vertex + patch->ctrlAt(0,2).vertex)/2; // Use the texture in the clipboard, if it's a decal texture Texturable& clipboard = GlobalShaderClipboard().getSource(); if (!clipboard.empty()) { if (clipboard.getShader().find("decals") != std::string::npos) { patch->setShader(clipboard.getShader()); } } // Fit the texture on it patch->SetTextureRepeat(1,1); patch->FlipTexture(1); // Insert the patch into worldspawn scene::INodePtr worldSpawnNode = GlobalMap().getWorldspawn(); assert(worldSpawnNode != NULL); // This must be non-NULL, otherwise we won't have faces worldSpawnNode->addChildNode(patchNode); // Deselect the face instance (*i)->setSelected(SelectionSystem::eFace, false); // Select the patch Node_setSelected(patchNode, true); } }
void Patch_setShader(scene::Node& patch, const char* shader) const { Node_getPatch(patch)->SetShader(shader); }
const char* Patch_getShader(scene::Node& patch) const { return Node_getPatch(patch)->GetShader(); }
void Patch_controlPointsChanged(scene::Node& patch) const { return Node_getPatch(patch)->controlPointsChanged(); }
PatchControlMatrix Patch_getControlPoints(scene::Node& node) const { Patch& patch = *Node_getPatch(node); return PatchControlMatrix(patch.getHeight(), patch.getWidth(), patch.getControlPoints().data()); }
void Patch_resize(scene::Node& patch, std::size_t width, std::size_t height) const { Node_getPatch(patch)->setDims(width, height); }
void Patch_undoSave(scene::Node& patch) const { Node_getPatch(patch)->undoSave(); }