File size: 4,120 Bytes
b6a38d7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122

DefineClass.XSmoothHeightBrush = {
	__parents = { "XEditorBrushTool" },
	properties = {
		editor = "number", slider = true, persisted_setting = true, auto_select_all = true,
		{ id = "Strength", default = 50,        scale = "%", min = 10,       max = 100,        step = 10 },
		{ id = "RegardWalkables", name = "Limit to walkables", editor = "bool", default = false },
	},
	
	ToolSection = "Height",
	ToolTitle = "Smooth height",
	Description = {
		"Removes jagged edges and softens terrain features."
	},
	ActionSortKey = "12",
	ActionIcon = "CommonAssets/UI/Editor/Tools/Smooth.tga", 
	ActionShortcut = "S",
	
	blurred_grid = false,
	mask_grid = false,
}

function XSmoothHeightBrush:Init()
	local w, h = terrain.HeightMapSize()
	self.blurred_grid = NewComputeGrid(w, h, "F")
	self.mask_grid = NewComputeGrid(w, h, "F")
	self:InitBlurredGrid()
end

function XSmoothHeightBrush:Done()
	editor.ClearOriginalHeightGrid()
	self.blurred_grid:free()
	self.mask_grid:free()
end

function XSmoothHeightBrush:InitBlurredGrid()
	editor.StoreOriginalHeightGrid(false) -- false = don't use for GetTerrainCursor
	editor.CopyFromOriginalHeight(self.blurred_grid)

	local blur_size = MulDivRound(self:GetStrength(), self:GetSize(), guim * const.HeightTileSize * 3)
	AsyncBlurGrid(self.blurred_grid, Max(blur_size, 1))
end

-- called via Msg when height is changed via this brush, or via undo
function XSmoothHeightBrush:UpdateBlurredGrid(bbox)
	bbox = terrain.ClampBox(GrowBox(bbox, 512 * guim)) -- TODO: make updating the blurred grid in the changed area only not produce sharp changes at the edges

	local grid_box = bbox / const.HeightTileSize
	
	-- copy the changed area back into blurred grid, and blur only that area to update it
	local height_part = editor.GetGrid("height", bbox)
	self.blurred_grid:copyrect(height_part, grid_box - grid_box:min(), grid_box:min())
	height_part:free()
	
	local blur_size = MulDivRound(self:GetStrength(), self:GetSize(), guim * const.HeightTileSize * 3)
	AsyncBlurGrid(self.blurred_grid, grid_box, Max(blur_size, 1)) -- update the blurred version of the terrain grid in the edited box
end

function OnMsg.EditorHeightChangedFinal(bbox)
	local brush = XEditorGetCurrentTool()
	if IsKindOf(brush, "XSmoothHeightBrush") then
		brush:UpdateBlurredGrid(bbox)
	end
end

function XSmoothHeightBrush:OnEditorSetProperty(prop_id, old_value, ged)
	if prop_id == "Strength" or prop_id == "Size" then
		self:InitBlurredGrid()
	end
end

function XSmoothHeightBrush:StartDraw(pt)
	XEditorUndo:BeginOp{ height = true , name = "Changed height" }
	editor.StoreOriginalHeightGrid(false) -- false = don't use for GetTerrainCursor
	self.mask_grid:clear()
end

function XSmoothHeightBrush:Draw(pt1, pt2)
	local _, outer_radius = self:GetCursorRadius()
	local bbox = editor.DrawMaskSegment(self.mask_grid, pt1, pt2, self:GetSize() / 4, self:GetSize(), "max", self:GetStrength() * 1.0 / 100.0)
	editor.SetHeightWithMask(self.blurred_grid, self.mask_grid, bbox)
	
	if self:GetRegardWalkables() then
		editor.ClampHeightToWalkables(bbox)
	end
	Msg("EditorHeightChanged", false, bbox)
end

function XSmoothHeightBrush:EndDraw(pt1, pt2, invalid_box)
	local bbox = editor.GetSegmentBoundingBox(pt1, pt2, self:GetSize(), self:IsCursorSquare())
	Msg("EditorHeightChanged", true, bbox)
	XEditorUndo:EndOp(nil, invalid_box)
end

function XSmoothHeightBrush:OnShortcut(shortcut, source, ...)
	if XEditorBrushTool.OnShortcut(self, shortcut, source, ...) then
		return "break"
	end
	
	local key = string.gsub(shortcut, "^Shift%-", "") -- ignore Shift, use it to decrease step size
	local divisor = terminal.IsKeyPressed(const.vkShift) and 10 or 1
	if key == "+" or key == "Numpad +" then
		self:SetStrength(self:GetStrength() + 10)
		return "break"
	elseif key == "-" or key == "Numpad -" then
		self:SetStrength(self:GetStrength() - 10)
		return "break"
	end
end

function XSmoothHeightBrush:GetCursorHeight()
	return self:GetStrength() / 3 * guim
end

function XSmoothHeightBrush:GetCursorRadius()
	return self:GetSize() / 2, self:GetSize() / 2
end

function XSmoothHeightBrush:GetAffectedRadius()
	return self:GetSize()
end