Download CommonLua/Editor/XEditor/XEditorBrushTool.lua from sirnii/myspace: direct link, hf CLI and curl.
- Browser
- Download file 7.66 kB
-
https://huggingface.co/spaces/sirnii/myspace/resolve/main/CommonLua/Editor/XEditor/XEditorBrushTool.lua
- Command line
-
hf download hf://spaces/sirnii/myspace/CommonLua/Editor/XEditor/XEditorBrushTool.lua
-
curl -L -o XEditorBrushTool.lua https://huggingface.co/spaces/sirnii/myspace/resolve/main/CommonLua/Editor/XEditor/XEditorBrushTool.lua
7.66 kB
| ----- XEditorBrushTool | |
| -- | |
| -- Implements the following functionality: | |
| -- 1. Calls StartDraw, Draw, EndDraw, passing brush position in world coordinates | |
| -- 2. Supports horizontal/vertical snapping when holding Shift | |
| -- 3. Supports drawing a brush cursor | |
| DefineClass.XEditorBrushTool = { | |
| __parents = { "XEditorTool" }, | |
| properties = { | |
| { id = "Size", editor = "number", default = 30 * guim, scale = "m", min = const.HeightTileSize, max = 300 * guim, step = guim / 10, | |
| slider = true, persisted_setting = true, auto_select_all = true, sort_order = -1, exponent = 3, }, | |
| }, | |
| UsesCodeRenderables = true, | |
| first_pos = false, | |
| last_pos = false, | |
| snap_axis = 0, | |
| invalid_box = false, | |
| cursor_mesh = false, | |
| cursor_circles = 2, | |
| cursor_max_tiles = const.SlabSizeZ and (const.MaxTerrainHeight / const.SlabSizeZ) or 100, | |
| cursor_tile_size = const.SlabSizeX, | |
| cursor_verts = 100, | |
| cursor_default_flags = const.mfOffsetByTerrainCursor + const.mfTerrainDistorted + const.mfWorldSpace, | |
| } | |
| function XEditorBrushTool:Init() | |
| DelayedCall(0, self.CreateCursor, self) | |
| end | |
| function XEditorBrushTool:Done() | |
| if self.last_pos then -- destroyed while drawing | |
| self:OnMouseButtonUp() | |
| end | |
| self:DestroyCursor() | |
| end | |
| ----- Drawing | |
| function XEditorBrushTool:GetWorldMousePos() | |
| return GetTerrainCursor():SetInvalidZ() | |
| end | |
| function XEditorBrushTool:OnMouseButtonDown(pt, button) | |
| if button == "L" then | |
| self.snap_axis = 0 | |
| self.first_pos = self:GetWorldMousePos() | |
| self.last_pos = self.first_pos | |
| self.invalid_box = editor.GetSegmentBoundingBox(self.last_pos, self.last_pos, self:GetAffectedRadius(), self:IsCursorSquare()) | |
| self:StartDraw(self.last_pos) | |
| self:Draw(self.last_pos, self.last_pos) | |
| self.desktop:SetMouseCapture(self) | |
| ForceHideMouseCursor("XEditorBrushTool") | |
| return "break" | |
| end | |
| return XEditorTool.OnMouseButtonDown(self, pt, button) | |
| end | |
| function XEditorBrushTool:GetWorldPos() | |
| local pos = self:GetWorldMousePos() | |
| if terminal.IsKeyPressed(const.vkShift) then | |
| pos = self:SnapPosToAxis(pos) | |
| end | |
| return pos | |
| end | |
| function XEditorBrushTool:OnMousePos(pt, button) | |
| if self.last_pos then | |
| local pos = self:GetWorldPos() | |
| self.invalid_box:InplaceExtend(editor.GetSegmentBoundingBox(self.last_pos, pos, self:GetAffectedRadius(), self:IsCursorSquare())) | |
| self:Draw(self.last_pos, pos) | |
| self.last_pos = pos | |
| return "break" | |
| end | |
| return XEditorTool.OnMousePos(self, pt, button) | |
| end | |
| function XEditorBrushTool:OnMouseButtonUp(pt, button) | |
| if self.last_pos then | |
| self.desktop:SetMouseCapture() -- calls OnCaptureLost below | |
| return "break" | |
| end | |
| return XEditorTool.OnMouseButtonUp(self, pt, button) | |
| end | |
| function XEditorBrushTool:OnCaptureLost() | |
| local pos = self:GetWorldPos() | |
| self.invalid_box:InplaceExtend(editor.GetSegmentBoundingBox(self.last_pos, pos, self:GetAffectedRadius(), self:IsCursorSquare())) | |
| self:EndDraw(self.last_pos, pos, self.invalid_box) | |
| UnforceHideMouseCursor("XEditorBrushTool") | |
| self.last_pos = false | |
| end | |
| function XEditorBrushTool:SnapPosToAxis(pos) | |
| local x0, y0 = self.first_pos:xy() | |
| local x1, y1 = pos:xy() | |
| if self.snap_axis == 0 then | |
| local dx, dy = abs(x1 - x0), abs(y1 - y0) | |
| if dx > guim and dy < guim then | |
| self.snap_axis = 1 | |
| elseif dy > guim and dx < guim then | |
| self.snap_axis = 2 | |
| elseif dx > guim and dy > guim then | |
| self.snap_axis = dx > dy and 1 or 2 | |
| end | |
| end | |
| if self.snap_axis == 1 then | |
| return pos:SetY(y0) | |
| elseif self.snap_axis == 2 then | |
| return pos:SetX(x0) | |
| end | |
| return pos | |
| end | |
| ----- Shortcuts | |
| function XEditorBrushTool:OnShortcut(shortcut, source, ...) | |
| 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 shortcut == "Shift-MouseWheelFwd" then | |
| self:SetSize(self:GetSize() + (self:IsCursorSquare() and const.SlabSizeX or guim * (self:GetSize() < 10 * guim and 1 or 5))) | |
| return "break" | |
| elseif shortcut == "Shift-MouseWheelBack" then | |
| self:SetSize(self:GetSize() - (self:IsCursorSquare() and const.SlabSizeX or guim * (self:GetSize() <= 10 * guim and 1 or 5))) | |
| return "break" | |
| elseif key == "]" then | |
| self:SetSize(self:GetSize() + (self:IsCursorSquare() and const.SlabSizeX or guim / divisor)) | |
| return "break" | |
| elseif key == "[" then | |
| self:SetSize(self:GetSize() - (self:IsCursorSquare() and const.SlabSizeX or guim / divisor)) | |
| return "break" | |
| end | |
| -- don't change tool modes, allow undo, etc. while in the process of dragging | |
| if terminal.desktop:GetMouseCapture() and shortcut ~= "Ctrl-F1" and shortcut ~= "Escape" then | |
| return "break" | |
| end | |
| return XEditorTool.OnShortcut(self, shortcut, source, ...) | |
| end | |
| ----- Cursor | |
| function XEditorBrushTool:CreateCursor() | |
| if self.cursor_mesh then | |
| self:DestroyCursor() | |
| end | |
| local cursor = Mesh:new() | |
| cursor:SetShader(ProceduralMeshShaders.mesh_linelist) | |
| self.cursor_mesh = cursor | |
| self:UpdateCursor() | |
| self:CreateThread("UpdateCursorThread", function() | |
| while true do | |
| self:UpdateCursor() | |
| Sleep(100) | |
| end | |
| end) | |
| self:OnCursorCreate(self.cursor_mesh) | |
| end | |
| function XEditorBrushTool:OnCursorCreate(cursor_mesh) | |
| end | |
| function XEditorBrushTool:CreateCircleCursor() | |
| local vpstr = pstr("") | |
| local cursor_verts = self.cursor_verts | |
| local inner_rad, outer_rad = self:GetCursorRadius() | |
| vpstr = AppendCircleVertices(nil, nil, inner_rad, self:GetCursorColor()) | |
| vpstr = AppendCircleVertices(vpstr, nil, outer_rad, self:GetCursorColor()) | |
| return vpstr | |
| end | |
| function XEditorBrushTool:CreateSquareCursor() | |
| local vpstr = pstr("") | |
| local inner_rad, outer_rad = self:GetCursorRadius() | |
| local tilesize = self.cursor_tile_size | |
| local tiles = outer_rad * 2 / tilesize | |
| local offset_x, offset_y, offset_xy = point(tilesize, 0, 0), point(0, tilesize, 0), point(tilesize, tilesize, 0) | |
| for x = 0, tiles - 1 do | |
| for y = 0, tiles - 1 do | |
| local start_pt = point(x * tilesize - outer_rad, y * tilesize - outer_rad, 0) | |
| vpstr:AppendVertex(start_pt, self:GetCursorColor(), 0) | |
| vpstr:AppendVertex(start_pt + offset_x) | |
| vpstr:AppendVertex(start_pt) | |
| vpstr:AppendVertex(start_pt + offset_y) | |
| if x == tiles - 1 then | |
| vpstr:AppendVertex(start_pt + offset_x) | |
| vpstr:AppendVertex(start_pt + offset_xy) | |
| end | |
| if y == tiles - 1 then | |
| vpstr:AppendVertex(start_pt + offset_y) | |
| vpstr:AppendVertex(start_pt + offset_xy) | |
| end | |
| end | |
| end | |
| return vpstr | |
| end | |
| function XEditorBrushTool:UpdateCursor() | |
| local v_pstr | |
| if self:IsCursorSquare() then | |
| v_pstr = self:CreateSquareCursor() | |
| else | |
| v_pstr = self:CreateCircleCursor() | |
| end | |
| local strength = self:GetCursorHeight() | |
| if strength then | |
| v_pstr:AppendVertex(point(0, 0, 0)) | |
| v_pstr:AppendVertex(point(0, 0, strength)) | |
| end | |
| self.cursor_mesh:SetMeshFlags(self.cursor_default_flags + self:GetCursorExtraFlags()) | |
| self.cursor_mesh:SetMesh(v_pstr) | |
| self.cursor_mesh:SetPos(GetTerrainCursor()) | |
| self.cursor_mesh:SetGameFlags(const.gofAlwaysRenderable) | |
| end | |
| function XEditorBrushTool:DestroyCursor() | |
| if not self.cursor_mesh then return end | |
| self:DeleteThread("UpdateCursorThread") | |
| DoneObject(self.cursor_mesh) | |
| self.cursor_mesh = nil | |
| end | |
| ----- Overrides | |
| function XEditorBrushTool:StartDraw(pt) | |
| end | |
| function XEditorBrushTool:Draw(pt1, pt2) | |
| end | |
| function XEditorBrushTool:EndDraw(pt1, pt2) | |
| end | |
| function XEditorBrushTool:GetCursorRadius() | |
| return 5 * guim, 5 * guim | |
| end | |
| function XEditorBrushTool:GetAffectedRadius() | |
| local _, outer_radius = self:GetCursorRadius() | |
| return outer_radius | |
| end | |
| function XEditorBrushTool:GetCursorColor() | |
| return RGB(255, 255, 255) | |
| end | |
| function XEditorBrushTool:GetCursorHeight() | |
| end | |
| function XEditorBrushTool:IsCursorSquare() | |
| return false | |
| end | |
| function XEditorBrushTool:GetCursorExtraFlags() | |
| return 0 | |
| end | |