ShowFlag.BuilderBrush
ShowFlag.BuilderBrush
#Overview
name: ShowFlag.BuilderBrush
This variable is created as a Console Variable (cvar).
- type:
Var
- help:
Allows to override a specific showflag (works in editor and game, \
It is referenced in 22
C++ source files.
#Summary
#Usage in the C++ source code
The purpose of ShowFlag.BuilderBrush is to control the rendering of the builder brush in the Unreal Engine editor. The builder brush is a special brush used for level editing and geometry creation.
This setting variable is primarily used by the rendering system and the editor’s geometry manipulation tools. Based on the callsites, it is utilized in the following subsystems and modules:
- GeometryMode plugin
- UnrealEd module
- Engine’s rendering system
The value of this variable is set in the engine’s show flags system, as evident from the SHOWFLAG_FIXED_IN_SHIPPING
macro used in the Engine/Source/Runtime/Engine/Public/ShowFlagsValues.inl file.
The associated variable BuilderBrush interacts closely with ShowFlag.BuilderBrush. It represents the actual builder brush object in the level editor.
Developers should be aware of the following when using this variable:
- It’s specifically for editor use and is not accessible in shipping builds.
- It controls the visibility of the builder brush in the editor viewports.
- It’s used in conjunction with other editor tools for geometry manipulation and level editing.
Best practices when using this variable include:
- Only modify it in editor-specific code.
- Use it in conjunction with other relevant show flags for consistent editor behavior.
- Be mindful of its impact on editor performance, especially when dealing with complex geometry.
Regarding the associated variable BuilderBrush:
The purpose of BuilderBrush is to represent the actual builder brush actor in the level. It’s used extensively in geometry editing operations, such as adding, subtracting, or modifying level geometry.
This variable is primarily used in the GeometryMode plugin and the UnrealEd module. It’s typically accessed through the world’s default brush or the current level’s actor list.
The value of BuilderBrush is usually set when the level is created or when performing specific geometry operations in the editor.
Developers should be aware that:
- BuilderBrush is a crucial part of the level editing process.
- It’s used in various geometry operations, including lathing, pen tool operations, and CSG (Constructive Solid Geometry) operations.
- It interacts closely with the level’s world settings.
Best practices for using BuilderBrush include:
- Always check for null before using it, as it might not always be available.
- Use it in conjunction with appropriate transaction systems for undo/redo support.
- Be cautious when modifying its properties, as it can affect the entire level geometry.
#References in C++ code
#Callsites
This variable is referenced in the following C++ source code:
#Loc: <Workspace>/Engine/Source/Runtime/Engine/Public/ShowFlagsValues.inl:197
Scope: file
Source code excerpt:
SHOWFLAG_ALWAYS_ACCESSIBLE(SkeletalMeshes, SFG_Normal, NSLOCTEXT("UnrealEd", "SkeletalMeshesSF", "Skeletal Meshes"))
/** if the builder brush (editor) is getting rendered */
SHOWFLAG_FIXED_IN_SHIPPING(0, BuilderBrush, SFG_Hidden, NSLOCTEXT("UnrealEd", "BuilderBrushSF", "Builder Brush"))
/** Render translucency, for now SHOWFLAG_ALWAYS_ACCESSIBLE because it's exposed in SceneCapture */
SHOWFLAG_ALWAYS_ACCESSIBLE(Translucency, SFG_Normal, NSLOCTEXT("UnrealEd", "TranslucencySF", "Translucency"))
/** Draw billboard components */
SHOWFLAG_FIXED_IN_SHIPPING(1, BillboardSprites, SFG_Advanced, NSLOCTEXT("UnrealEd", "BillboardSpritesSF", "Billboard Sprites"))
/** Use LOD parenting, MinDrawDistance, etc. If disabled, will show LOD parenting lines */
SHOWFLAG_ALWAYS_ACCESSIBLE(LOD, SFG_Advanced, NSLOCTEXT("UnrealEd", "LODSF", "LOD Parenting"))
#Associated Variable and Callsites
This variable is associated with another variable named BuilderBrush
. They share the same value. See the following C++ source code.
#Loc: <Workspace>/Engine/Plugins/Editor/GeometryMode/Source/GeometryMode/Private/GeometryModifiers.cpp:157
Scope (from outer to inner):
file
function void UGeomModifier::CacheBrushState
Source code excerpt:
{
FEdModeGeometry* GeomMode = (FEdModeGeometry*)GLevelEditorModeTools().GetActiveMode(FGeometryEditingModes::EM_Geometry);
ABrush* BuilderBrush = GeomMode->GetWorld()->GetDefaultBrush();
if( !CachedPolys )
{
//Create the list of polys
CachedPolys = NewObject<UPolys>(this);
}
CachedPolys->Element.Empty();
//Create duplicates of all of the polys in the brush
for( int32 polyIndex = 0 ; polyIndex < BuilderBrush->Brush->Polys->Element.Num() ; ++polyIndex )
{
FPoly currentPoly = BuilderBrush->Brush->Polys->Element[polyIndex];
FPoly newPoly;
newPoly.Init();
newPoly.Base = currentPoly.Base;
//Add all of the verts to the new poly
for( int32 vertIndex = 0; vertIndex < currentPoly.Vertices.Num(); ++vertIndex )
#Loc: <Workspace>/Engine/Plugins/Editor/GeometryMode/Source/GeometryMode/Private/GeometryModifiers.cpp:187
Scope (from outer to inner):
file
function void UGeomModifier::RestoreBrushState
Source code excerpt:
{
FEdModeGeometry* GeomMode = (FEdModeGeometry*)GLevelEditorModeTools().GetActiveMode(FGeometryEditingModes::EM_Geometry);
ABrush* BuilderBrush = GeomMode->GetWorld()->GetDefaultBrush();
//Remove all of the current polys
BuilderBrush->Brush->Polys->Element.Empty();
//Add all of the cached polys
for( int32 polyIndex = 0 ; polyIndex < CachedPolys->Element.Num() ; polyIndex++ )
{
BuilderBrush->Brush->Polys->Element.Push(CachedPolys->Element[polyIndex]);
}
BuilderBrush->Brush->BuildBound();
BuilderBrush->ReregisterAllComponents();
GeomMode->FinalizeSourceData();
GeomMode->GetFromSource();
GEditor->SelectNone( true, true );
#Loc: <Workspace>/Engine/Plugins/Editor/GeometryMode/Source/GeometryMode/Private/GeometryModifiers.cpp:1012
Scope (from outer to inner):
file
function void UGeomModifier_Lathe::Apply
Source code excerpt:
// We will be replacing the builder brush, so get it prepped.
ABrush* BuilderBrush = GeomMode->GetWorld()->GetDefaultBrush();
BuilderBrush->SetActorLocation(GeomMode->GetWidgetLocation(), false);
BuilderBrush->SetPivotOffset(FVector::ZeroVector);
BuilderBrush->SetFlags( RF_Transactional );
BuilderBrush->Brush->Polys->Element.Empty();
// Ensure the builder brush is unhidden.
BuilderBrush->SetHidden(false);
BuilderBrush->bHiddenEdLayer = false;
BuilderBrush->SetIsTemporarilyHiddenInEditor( false );
// Some convenience flags
bool bNeedCaps = (InSegments < InTotalSegments);
// Lathe every selected ABrushShape actor into the builder brush
#Loc: <Workspace>/Engine/Plugins/Editor/GeometryMode/Source/GeometryMode/Private/GeometryModifiers.cpp:1110
Scope (from outer to inner):
file
function void UGeomModifier_Lathe::Apply
Source code excerpt:
FPoly NewPoly;
NewPoly.Init();
NewPoly.Base = (FVector3f)BuilderBrush->GetActorLocation();
NewPoly.Vertices.Add( (FVector3f)vtx0 );
NewPoly.Vertices.Add( (FVector3f)vtx1 );
NewPoly.Vertices.Add( (FVector3f)vtx2 );
NewPoly.Vertices.Add( (FVector3f)vtx3 );
if( NewPoly.Finalize( BuilderBrush, 1 ) == 0 )
{
BuilderBrush->Brush->Polys->Element.Add( NewPoly );
}
}
}
}
#Loc: <Workspace>/Engine/Plugins/Editor/GeometryMode/Source/GeometryMode/Private/GeometryModifiers.cpp:1149
Scope (from outer to inner):
file
function void UGeomModifier_Lathe::Apply
Source code excerpt:
}
Poly.Finalize( BuilderBrush, 1 );
// Break the shape down into convex shapes.
TArray<FPoly> Polygons;
Poly.Triangulate( BuilderBrush, Polygons );
FPoly::OptimizeIntoConvexPolys( BuilderBrush, Polygons );
// Add the resulting convex polygons into the brush
for( int32 p = 0 ; p < Polygons.Num() ; ++p )
{
FPoly Polygon = Polygons[p];
if (Polygon.Finalize(BuilderBrush, 1) == 0)
{
BuilderBrush->Brush->Polys->Element.Add(Polygon);
}
}
//
// Create the end cap
//
#Loc: <Workspace>/Engine/Plugins/Editor/GeometryMode/Source/GeometryMode/Private/GeometryModifiers.cpp:1195
Scope (from outer to inner):
file
function void UGeomModifier_Lathe::Apply
Source code excerpt:
}
Poly.Finalize( BuilderBrush, 1 );
// Break the shape down into convex shapes.
Polygons.Empty();
Poly.Triangulate( BuilderBrush, Polygons );
FPoly::OptimizeIntoConvexPolys( BuilderBrush, Polygons );
// Add the resulting convex polygons into the brush
for( int32 p = 0 ; p < Polygons.Num() ; ++p )
{
FPoly Polygon = Polygons[p];
Polygon.Reverse();
if (Polygon.Finalize(BuilderBrush, 1) == 0)
{
BuilderBrush->Brush->Polys->Element.Add(Polygon);
}
}
}
}
}
}
#Loc: <Workspace>/Engine/Plugins/Editor/GeometryMode/Source/GeometryMode/Private/GeometryModifiers.cpp:1222
Scope (from outer to inner):
file
function void UGeomModifier_Lathe::Apply
Source code excerpt:
// Finalize the builder brush
BuilderBrush->Brush->BuildBound();
BuilderBrush->ReregisterAllComponents();
GeomMode->FinalizeSourceData();
GeomMode->GetFromSource();
GEditor->SelectNone( true, true );
GEditor->SelectActor( BuilderBrush, true, true );
if( DoEdgesOverlap() )
{//Overlapping edges yielded an invalid brush state
RestoreBrushState();
}
else
#Loc: <Workspace>/Engine/Plugins/Editor/GeometryMode/Source/GeometryMode/Private/GeometryModifiers.cpp:1245
Scope (from outer to inner):
file
function void UGeomModifier_Lathe::Apply
Source code excerpt:
// Deselect & hide builder brush
BuilderBrush->SetIsTemporarilyHiddenInEditor(true);
GEditor->SelectActor(BuilderBrush, false, false);
}
/*------------------------------------------------------------------------------
UGeomModifier_Pen
------------------------------------------------------------------------------*/
UGeomModifier_Pen::UGeomModifier_Pen(const FObjectInitializer& ObjectInitializer)
#Loc: <Workspace>/Engine/Plugins/Editor/GeometryMode/Source/GeometryMode/Private/GeometryModifiers.cpp:1298
Scope (from outer to inner):
file
function void UGeomModifier_Pen::Apply
Source code excerpt:
FEdModeGeometry* GeomMode = (FEdModeGeometry*)GLevelEditorModeTools().GetActiveMode(FGeometryEditingModes::EM_Geometry);
ABrush* ResultingBrush = GeomMode->GetWorld()->GetDefaultBrush();
ABrush* BuilderBrush = GeomMode->GetWorld()->GetDefaultBrush();
// Move all the vertices that the user placed to the same "height" as the builder brush, based on
// viewport orientation. This is preferable to always creating the new builder brush at height zero.
for( int32 v = 0 ; v < ShapeVertices.Num() ; ++v )
{
#Loc: <Workspace>/Engine/Plugins/Editor/GeometryMode/Source/GeometryMode/Private/GeometryModifiers.cpp:1310
Scope (from outer to inner):
file
function void UGeomModifier_Pen::Apply
Source code excerpt:
{
case LVT_OrthoXY:
vtx->Z = BuilderBrush->GetActorLocation().Z;
break;
case LVT_OrthoXZ:
vtx->Y = BuilderBrush->GetActorLocation().Y;
break;
case LVT_OrthoYZ:
vtx->X = BuilderBrush->GetActorLocation().X;
break;
}
}
// Generate center location from the shape's center
FBox WorldBounds(ShapeVertices.GetData(), ShapeVertices.Num());
#Loc: <Workspace>/Engine/Plugins/Editor/GeometryMode/Source/GeometryMode/Private/GeometryModifiers.cpp:1334
Scope (from outer to inner):
file
function void UGeomModifier_Pen::Apply
Source code excerpt:
{
// Create a shape brush instead of modifying the builder brush
ResultingBrush = BuilderBrush->GetWorld()->SpawnActor<ABrushShape>(BaseLocation, FRotator::ZeroRotator);
ResultingBrush->PreEditChange(NULL);
// It's OK to create an empty brush here as we are going to re-create the polys anyway.
FBSPOps::csgCopyBrush( ResultingBrush, BuilderBrush, PF_DefaultFlags, BuilderBrush->GetFlags(), true, true, true );
ResultingBrush->PostEditChange();
}
else
{
ResultingBrush = FBSPOps::csgAddOperation( BuilderBrush, PF_DefaultFlags, Brush_Add );
if (ResultingBrush == nullptr)
{
return;
}
if (ResultingBrush->GetBrushBuilder())
#Loc: <Workspace>/Engine/Plugins/Editor/GeometryMode/Source/GeometryMode/Private/GeometryModifiers.cpp:2045
Scope (from outer to inner):
file
namespace GeometryClipping
function static ABrush* ClipBrushAgainstPlane
Source code excerpt:
// Move the new brush to where the new brush was to preserve brush ordering.
ABrush* BuilderBrush = World->GetDefaultBrush();
if( InBrush == BuilderBrush )
{
// Special-case behavior for the builder brush.
// Copy the temporary brush back over onto the builder brush (keeping object flags)
BuilderBrush->Modify(false);
FBSPOps::csgCopyBrush( BuilderBrush, ClippedBrush, BuilderBrush->PolyFlags, BuilderBrush->GetFlags(), 0, true );
ULayersSubsystem* Layers = GEditor->GetEditorSubsystem<ULayersSubsystem>();
Layers->DisassociateActorFromLayers( ClippedBrush );
World->EditorDestroyActor( ClippedBrush, false );
// Note that we're purposefully returning non-NULL here to report that the clip was successful,
// even though the ClippedBrush has been destroyed!
}
#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Private/EditorBrushBuilder.cpp:57
Scope (from outer to inner):
file
function bool UEditorBrushBuilder::EndBrush
Source code excerpt:
check( InWorld != nullptr );
ABrush* BuilderBrush = (InBrush != nullptr) ? InBrush : InWorld->GetDefaultBrush();
// Ensure the builder brush is unhidden.
BuilderBrush->SetHidden(false);
BuilderBrush->bHiddenEdLayer = false;
AActor* Actor = GEditor->GetSelectedActors()->GetTop<AActor>();
FVector Location;
if ( InBrush == nullptr )
{
Location = Actor ? Actor->GetActorLocation() : BuilderBrush->GetActorLocation();
}
else
{
Location = InBrush->GetActorLocation();
}
UModel* Brush = BuilderBrush->Brush;
if (Brush == nullptr)
{
return true;
}
Brush->Modify(false);
BuilderBrush->Modify(false);
FRotator Temp(0.0f,0.0f,0.0f);
FSnappingUtils::SnapToBSPVertex( Location, FVector::ZeroVector, Temp );
BuilderBrush->SetActorLocation(Location, false);
BuilderBrush->SetPivotOffset( FVector::ZeroVector );
// Try and maintain the materials assigned to the surfaces.
TArray<FPoly> CachedPolys;
UMaterialInterface* CachedMaterial = nullptr;
if( Brush->Polys->Element.Num() == Polys.Num() )
{
#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Private/EditorBrushBuilder.cpp:141
Scope (from outer to inner):
file
function bool UEditorBrushBuilder::EndBrush
Source code excerpt:
Poly.Vertices.Emplace(Vertices[It->VertexIndices[j]]);
}
if( Poly.Finalize( BuilderBrush, 1 ) == 0 )
{
Brush->Polys->Element.Add(Poly);
}
}
if( MergeCoplanars )
#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Private/EditorBrushBuilder.cpp:158
Scope (from outer to inner):
file
function bool UEditorBrushBuilder::EndBrush
Source code excerpt:
GEditor->RedrawLevelEditingViewports();
GEditor->SetPivot(BuilderBrush->GetActorLocation(), false, true);
BuilderBrush->ReregisterAllComponents();
return true;
}
int32 UEditorBrushBuilder::GetVertexCount() const
{
#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Private/EditorModeManager.cpp:1600
Scope (from outer to inner):
file
function void FEditorModeTools::DrawHUD
Source code excerpt:
const bool bShowBrushes = View->Family->EngineShowFlags.Brushes;
const bool bShowBSP = View->Family->EngineShowFlags.BSP;
const bool bShowBuilderBrush = View->Family->EngineShowFlags.BuilderBrush != 0;
UTexture2D* VertexTexture = GetVertexTexture();
const float TextureSizeX = VertexTexture->GetSizeX() * (bLargeVertices ? 1.0f : 0.5f);
const float TextureSizeY = VertexTexture->GetSizeY() * (bLargeVertices ? 1.0f : 0.5f);
GetEditorSelectionSet()->ForEachSelectedObject<AStaticMeshActor>([View, Canvas, VertexTexture, TextureSizeX, TextureSizeY, bIsHitTesting](AStaticMeshActor* Actor)
#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Private/Factories/EditorFactories.cpp:778
Scope (from outer to inner):
file
function UObject* ULevelFactory::FactoryCreateText
Source code excerpt:
// We need to detect if the .t3d file is the entire level or just selected actors, because we
// don't want to replace the WorldSettings and BuildBrush if they already exist. To know if we
// can skip the WorldSettings and BuilderBrush (which will always be the first two actors if the entire
// level was exported), we make sure the first actor is a WorldSettings, if it is, and we already had
// a WorldSettings, then we skip the builder brush
// In other words, if we are importing a full level into a full level, we don't want to import
// the WorldSettings and BuildBrush
bool bShouldSkipImportSpecialActors = false;
bool bHitLevelToken = false;
#Loc: <Workspace>/Engine/Source/Editor/UnrealEd/Private/Factories/EditorFactories.cpp:970
Scope (from outer to inner):
file
function UObject* ULevelFactory::FactoryCreateText
Source code excerpt:
}
// If we need to skip the WorldSettings and BuilderBrush, skip the first two actors. Note that
// at this point, we already know that we have a WorldSettings and BuilderBrush in the .t3d.
if ( FLevelUtils::IsLevelLocked(World->GetCurrentLevel()) )
{
UE_LOG(LogEditorFactories, Warning, TEXT("Import actor: The requested operation could not be completed because the level is locked."));
GEditor->GetEditorSubsystem<UImportSubsystem>()->BroadcastAssetPostImport(this, nullptr );
return nullptr;
}
#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/ActorEditorUtils.cpp:25
Scope (from outer to inner):
file
namespace FActorEditorUtils
function bool IsABuilderBrush
Source code excerpt:
{
// If the builder brush exists then it will be the 2nd actor in the actors array.
ABrush* BuilderBrush = Cast<ABrush>(ActorLevel->Actors[1]);
// If the second actor is not a brush then it certainly cannot be the builder brush.
if ((BuilderBrush != nullptr) && (BuilderBrush->GetBrushComponent() != nullptr) && (BuilderBrush->Brush != nullptr))
{
bIsBuilder = (BuilderBrush == InActor);
}
}
}
#endif
return bIsBuilder;
}
#Loc: <Workspace>/Engine/Source/Runtime/Engine/Private/Components/BrushComponent.cpp:307
Scope (from outer to inner):
file
class class FBrushSceneProxy final : public FPrimitiveSceneProxy
function virtual FPrimitiveViewRelevance GetViewRelevance
Source code excerpt:
if( GIsEditor )
{
const bool bShowBuilderBrush = View->Family->EngineShowFlags.BuilderBrush != 0;
// Only render builder brush and only if the show flags indicate that we should render builder brushes.
if( bBuilder && (!bShowBuilderBrush) )
{
bNeverShow = true;
}
#Loc: <Workspace>/Engine/Source/Runtime/Engine/Public/ShowFlagsValues.inl:197
Scope: file
Source code excerpt:
SHOWFLAG_ALWAYS_ACCESSIBLE(SkeletalMeshes, SFG_Normal, NSLOCTEXT("UnrealEd", "SkeletalMeshesSF", "Skeletal Meshes"))
/** if the builder brush (editor) is getting rendered */
SHOWFLAG_FIXED_IN_SHIPPING(0, BuilderBrush, SFG_Hidden, NSLOCTEXT("UnrealEd", "BuilderBrushSF", "Builder Brush"))
/** Render translucency, for now SHOWFLAG_ALWAYS_ACCESSIBLE because it's exposed in SceneCapture */
SHOWFLAG_ALWAYS_ACCESSIBLE(Translucency, SFG_Normal, NSLOCTEXT("UnrealEd", "TranslucencySF", "Translucency"))
/** Draw billboard components */
SHOWFLAG_FIXED_IN_SHIPPING(1, BillboardSprites, SFG_Advanced, NSLOCTEXT("UnrealEd", "BillboardSpritesSF", "Billboard Sprites"))
/** Use LOD parenting, MinDrawDistance, etc. If disabled, will show LOD parenting lines */
SHOWFLAG_ALWAYS_ACCESSIBLE(LOD, SFG_Advanced, NSLOCTEXT("UnrealEd", "LODSF", "LOD Parenting"))