Skip to content

Commit

Permalink
#5231: Extract IShaderClipboard interface to be used by the mouse too…
Browse files Browse the repository at this point in the history
…ls to pick/copy/paste shaders.

Move Map classes to core module.
  • Loading branch information
codereader committed May 30, 2020
1 parent 4369d2e commit ec46d4e
Show file tree
Hide file tree
Showing 88 changed files with 424 additions and 373 deletions.
69 changes: 69 additions & 0 deletions include/ishaderclipboard.h
@@ -0,0 +1,69 @@
#pragma once

#include "imodule.h"
#include "iselectiontest.h"

namespace selection
{

enum class PasteMode
{
// Shader is projected using the texdef matrix in the source
Projected,

// If a patch is hit, the algorithm will take the surface
// topology of the patch into account, to avoid distortions.
Natural,
};

/**
* Public interface of the shader clipboard which is able
* to pick/copy/paste shaders from and to Texturable objects.
*/
class IShaderClipboard :
public RegisterableModule
{
public:
virtual ~IShaderClipboard() {}

virtual void pickFromSelectionTest(SelectionTest& test) = 0;

/**
* Pastes the shader from the source in the clipboard to the object
* located by the given selection test.
*
* @pasteToAllFaces: if a brush is hit, the source shader will be pasted
* to all its faces, not just the one hit by the selection test.
*
* Might throw a cmd::ExecutionFailure.
*/
virtual void pasteShader(SelectionTest& test, PasteMode mode, bool pasteToAllFaces) = 0;

/**
* Will attempt to apply the texture coordinates of the source patch to the
* target patch located by the given SelectionTest.
* Will throw a cmd::ExecutionFailure if the source or target objects are not matching up.
*/
virtual void pasteTextureCoords(SelectionTest& test) = 0;

/**
* Applies the material only to the object hit by the given selection test.
* Will leave the rest of the surface properties unchanged, if possible.
*/
virtual void pasteMaterialName(SelectionTest& test) = 0;
};

} // namespace

const char* const MODULE_SHADERCLIPBOARD("ShaderClipboard");

inline selection::IShaderClipboard& GlobalShaderClipboard()
{
// Cache the reference locally
static selection::IShaderClipboard& _clipboard(
*std::static_pointer_cast<selection::IShaderClipboard>(
module::GlobalModuleRegistry().getModule(MODULE_SHADERCLIPBOARD)
)
);
return _clipboard;
}
1 change: 1 addition & 0 deletions include/precompiled_interfaces.h
Expand Up @@ -83,6 +83,7 @@
#include "iselectiongroup.h"
#include "iselectionset.h"
#include "iselectiontest.h"
#include "ishaderclipboard.h"
#include "ishaderexpression.h"
#include "ishaders.h"
#include "isound.h"
Expand Down
File renamed without changes.
33 changes: 16 additions & 17 deletions radiant/map/algorithm/Clone.h → libs/scene/Clone.h
Expand Up @@ -4,59 +4,59 @@
#include "iscenegraph.h"
#include <functional>

namespace map
namespace scene
{

inline scene::CloneablePtr Node_getCloneable(const scene::INodePtr& node)
inline CloneablePtr Node_getCloneable(const INodePtr& node)
{
return std::dynamic_pointer_cast<scene::Cloneable>(node);
return std::dynamic_pointer_cast<Cloneable>(node);
}

/**
* greebo: Attempts to clone the given node. Returns the cloned node
* on success or an empty INodePtr if the node is not cloneable.
*/
inline scene::INodePtr cloneSingleNode(const scene::INodePtr& node)
inline INodePtr cloneSingleNode(const INodePtr& node)
{
scene::CloneablePtr cloneable = Node_getCloneable(node);
CloneablePtr cloneable = Node_getCloneable(node);

// Return an empty node if not cloneable
return cloneable ? cloneable->clone() : scene::INodePtr();
return cloneable ? cloneable->clone() : INodePtr();
}

// Function that is invoked after a node has been cloned, called with <sourceNode, clonedNode>
typedef std::function<void(const scene::INodePtr&, const scene::INodePtr&)> PostCloneCallback;
typedef std::function<void(const INodePtr&, const INodePtr&)> PostCloneCallback;

class CloneAll :
public scene::NodeVisitor
public NodeVisitor
{
private:
scene::Path _path;
Path _path;

PostCloneCallback _postCloneCallback;

public:
CloneAll(const scene::INodePtr& root, const PostCloneCallback& callback) :
CloneAll(const INodePtr& root, const PostCloneCallback& callback) :
_path(root),
_postCloneCallback(callback)
{}

bool pre(const scene::INodePtr& node) override
bool pre(const INodePtr& node) override
{
if (node->isRoot())
{
return false;
}

scene::INodePtr cloned = cloneSingleNode(node);
INodePtr cloned = cloneSingleNode(node);

// Insert the cloned node or an empty ptr if not cloneable
_path.push(cloned);

return true;
}

void post(const scene::INodePtr& node) override
void post(const INodePtr& node) override
{
if (node->isRoot())
{
Expand Down Expand Up @@ -85,10 +85,9 @@ class CloneAll :
*
* @returns: the cloned node (which might own cloned children).
*/
inline scene::INodePtr cloneNodeIncludingDescendants(const scene::INodePtr& node,
const PostCloneCallback& callback)
inline INodePtr cloneNodeIncludingDescendants(const INodePtr& node, const PostCloneCallback& callback)
{
scene::INodePtr clone = cloneSingleNode(node);
INodePtr clone = cloneSingleNode(node);

CloneAll visitor(clone, callback);
node->traverseChildren(visitor);
Expand All @@ -101,4 +100,4 @@ inline scene::INodePtr cloneNodeIncludingDescendants(const scene::INodePtr& node
return clone;
}

} // namespace map
} // namespace
2 changes: 1 addition & 1 deletion radiant/camera/CamWnd.h
Expand Up @@ -19,7 +19,7 @@
#include "RadiantCameraView.h"
#include "Camera.h"

#include "selection/Rectangle.h"
#include "Rectangle.h"
#include <memory>
#include "util/Noncopyable.h"
#include <sigc++/connection.h>
Expand Down
32 changes: 16 additions & 16 deletions radiant/camera/tools/ShaderClipboardTools.h
@@ -1,9 +1,9 @@
#pragma once

#include "imousetool.h"
#include "ishaderclipboard.h"
#include "i18n.h"
#include "selection/shaderclipboard/ShaderClipboard.h"
#include "selection/algorithm/Shader.h"
#include "command/ExecutionFailure.h"
#include "CameraMouseToolEvent.h"
#include <functional>
#include "wxutil/dialog/MessageBox.h"
Expand Down Expand Up @@ -53,7 +53,7 @@ class ShaderMouseToolBase :

return Result::Activated;
}
catch (selection::algorithm::InvalidOperationException& ex)
catch (const cmd::ExecutionFailure& ex)
{
// Some operations fail and want to notify the user
// we do this here to not steal the focus from our window
Expand Down Expand Up @@ -85,7 +85,7 @@ class ShaderMouseToolBase :

return Result::Continued;
}
catch (selection::algorithm::InvalidOperationException& ex)
catch (const cmd::ExecutionFailure& ex)
{
// Some operations fail and want to notify the user
// we do this here to not steal the focus from our window
Expand Down Expand Up @@ -126,7 +126,7 @@ class PickShaderTool :
void onAction(SelectionTest& selectionTest)
{
// Set the source texturable from the given test
GlobalShaderClipboard().setSource(selectionTest);
GlobalShaderClipboard().pickFromSelectionTest(selectionTest);
}
};

Expand All @@ -143,9 +143,9 @@ class PasteShaderProjectedTool :
private:
void onAction(SelectionTest& selectionTest)
{
// Paste the shader projected (TRUE), but not to an entire brush (FALSE)
// The InvalidOperationExceptions are handled by the calling code in the base class
selection::algorithm::pasteShader(selectionTest, true, false);
// Paste the shader projected, but not to an entire brush (FALSE)
// The ExecutionFailure exceptions are handled by the calling code in the base class
GlobalShaderClipboard().pasteShader(selectionTest, selection::PasteMode::Projected, false);
}
};

Expand All @@ -163,8 +163,8 @@ class PasteShaderNaturalTool :
void onAction(SelectionTest& selectionTest)
{
// Paste the shader naturally (FALSE), but not to an entire brush (FALSE)
// The InvalidOperationExceptions are handled by the calling code in the base class
selection::algorithm::pasteShader(selectionTest, false, false);
// The ExecutionFailure exceptions are handled by the calling code in the base class
GlobalShaderClipboard().pasteShader(selectionTest, selection::PasteMode::Natural, false);
}
};

Expand All @@ -182,8 +182,8 @@ class PasteShaderCoordsTool :
void onAction(SelectionTest& selectionTest)
{
// Clone the texture coordinates from the patch in the clipboard
// The InvalidOperationExceptions are handled by the calling code in the base class
selection::algorithm::pasteTextureCoords(selectionTest);
// The ExecutionFailure exceptions are handled by the calling code in the base class
GlobalShaderClipboard().pasteTextureCoords(selectionTest);
}
};

Expand All @@ -201,8 +201,8 @@ class PasteShaderToBrushTool :
void onAction(SelectionTest& selectionTest)
{
// Paste the shader projected (TRUE), and to the entire brush (TRUE)
// The InvalidOperationExceptions are handled by the calling code in the base class
selection::algorithm::pasteShader(selectionTest, true, true);
// The ExecutionFailure exceptions are handled by the calling code in the base class
GlobalShaderClipboard().pasteShader(selectionTest, selection::PasteMode::Projected, true);
}
};

Expand All @@ -220,8 +220,8 @@ class PasteShaderNameTool :
void onAction(SelectionTest& selectionTest)
{
// Paste the shader name only
// The InvalidOperationExceptions are handled by the calling code in the base class
selection::algorithm::pasteShaderName(selectionTest);
// The ExecutionFailure exceptions are handled by the calling code in the base class
GlobalShaderClipboard().pasteMaterialName(selectionTest);
}
};

Expand Down
6 changes: 3 additions & 3 deletions radiantcore/brush/BrushNode.cpp
Expand Up @@ -188,7 +188,7 @@ const AABB& BrushNode::getSelectedComponentsBounds() const {
void BrushNode::selectPlanes(Selector& selector, SelectionTest& test, const PlaneCallback& selectedPlaneCallback) {
test.BeginMesh(localToWorld());

PlanePointer brushPlanes[c_brush_maxFaces];
PlanePointer brushPlanes[brush::c_brush_maxFaces];
PlanesIterator j = brushPlanes;

for (Brush::const_iterator i = m_brush.begin(); i != m_brush.end(); ++i) {
Expand Down Expand Up @@ -400,10 +400,10 @@ void BrushNode::evaluateViewDependent(const VolumeTest& volume, const Matrix4& l
m_viewChanged = false;

// Array of booleans to indicate which faces are visible
static bool faces_visible[c_brush_maxFaces];
static bool faces_visible[brush::c_brush_maxFaces];

// Will hold the indices of all visible faces (from the current viewpoint)
static std::size_t visibleFaceIndices[c_brush_maxFaces];
static std::size_t visibleFaceIndices[brush::c_brush_maxFaces];

std::size_t numVisibleFaces(0);
bool* j = faces_visible;
Expand Down
2 changes: 1 addition & 1 deletion radiantcore/brush/Face.cpp
Expand Up @@ -578,7 +578,7 @@ bool Face::contributes() const {

bool Face::is_bounded() const {
for (Winding::const_iterator i = m_winding.begin(); i != m_winding.end(); ++i) {
if (i->adjacent == c_brush_maxFaces) {
if (i->adjacent == brush::c_brush_maxFaces) {
return false;
}
}
Expand Down
9 changes: 5 additions & 4 deletions radiantcore/brush/FaceInstance.cpp
@@ -1,6 +1,7 @@
#include "FaceInstance.h"

#include "ifilter.h"
#include "ibrush.h"
#include "irenderable.h"
#include "iscenegraph.h"

Expand Down Expand Up @@ -356,16 +357,16 @@ void FaceInstance::update_selection_vertex() {
if (m_vertexSelection.size() == 1) {
std::size_t index = getFace().getWinding().findAdjacent(*m_vertexSelection.begin());

if (index != c_brush_maxFaces) {
if (index != brush::c_brush_maxFaces) {
update_move_planepts_vertex(index);
}
}
else if (m_vertexSelection.size() == 2) {
std::size_t index = getFace().getWinding().findAdjacent(*m_vertexSelection.begin());
std::size_t other = getFace().getWinding().findAdjacent(*(++m_vertexSelection.begin()));

if (index != c_brush_maxFaces
&& other != c_brush_maxFaces) {
if (index != brush::c_brush_maxFaces
&& other != brush::c_brush_maxFaces) {
update_move_planepts_vertex2(index, other);
}
}
Expand Down Expand Up @@ -410,7 +411,7 @@ void FaceInstance::update_selection_edge() {
if (m_edgeSelection.size() == 1) {
std::size_t index = getFace().getWinding().findAdjacent(*m_edgeSelection.begin());

if (index != c_brush_maxFaces) {
if (index != brush::c_brush_maxFaces) {
update_move_planepts_edge(index);
}
}
Expand Down
4 changes: 2 additions & 2 deletions radiantcore/brush/FaceInstance.h
Expand Up @@ -61,7 +61,7 @@ class FaceInstance
void SelectedVertices_foreach(Functor functor) const {
for (VertexSelection::const_iterator i = m_vertexSelection.begin(); i != m_vertexSelection.end(); ++i) {
std::size_t index = getFace().getWinding().findAdjacent(*i);
if (index != c_brush_maxFaces) {
if (index != brush::c_brush_maxFaces) {
functor(getFace().getWinding()[index].vertex);
}
}
Expand All @@ -71,7 +71,7 @@ class FaceInstance
void SelectedEdges_foreach(Functor functor) const {
for (VertexSelection::const_iterator i = m_edgeSelection.begin(); i != m_edgeSelection.end(); ++i) {
std::size_t index = getFace().getWinding().findAdjacent(*i);
if (index != c_brush_maxFaces) {
if (index != brush::c_brush_maxFaces) {
const Winding& winding = getFace().getWinding();
std::size_t adjacent = winding.next(index);
functor(winding[index].vertex.mid(winding[adjacent].vertex));
Expand Down
8 changes: 4 additions & 4 deletions radiantcore/brush/FixedWinding.cpp
Expand Up @@ -107,19 +107,19 @@ void FixedWinding::createInfinite(const Plane3& plane, double infinity) {
DoubleLine r1, r2, r3, r4;
r1.origin = (org - vright) + vup;
r1.direction = vright.getNormalised();
push_back(FixedWindingVertex(r1.origin, r1, c_brush_maxFaces));
push_back(FixedWindingVertex(r1.origin, r1, brush::c_brush_maxFaces));

r2.origin = org + vright + vup;
r2.direction = (-vup).getNormalised();
push_back(FixedWindingVertex(r2.origin, r2, c_brush_maxFaces));
push_back(FixedWindingVertex(r2.origin, r2, brush::c_brush_maxFaces));

r3.origin = (org + vright) - vup;
r3.direction = (-vright).getNormalised();
push_back(FixedWindingVertex(r3.origin, r3, c_brush_maxFaces));
push_back(FixedWindingVertex(r3.origin, r3, brush::c_brush_maxFaces));

r4.origin = (org - vright) - vup;
r4.direction = vup.getNormalised();
push_back(FixedWindingVertex(r4.origin, r4, c_brush_maxFaces));
push_back(FixedWindingVertex(r4.origin, r4, brush::c_brush_maxFaces));
}

/// \brief Clip \p winding which lies on \p plane by \p clipPlane, resulting in \p clipped.
Expand Down

0 comments on commit ec46d4e

Please sign in to comment.