Skip to content

Commit

Permalink
editor view features, fixes and more
Browse files Browse the repository at this point in the history
usable in shortcuts:
-orthographic view
-entity follow angle: forward and sideview variations
-reset_eyeang, reset_eyeang_pitch

orthographic view major culling issues

usable in partmenu actions:
-view go to: move view to a certain axis
-view lock on: point camera to target. different pitch control modes (zero pitch, free pitch, direct, frame of reference)

partmenu config menu: right click to insert an action at the beginning of the list

new movement bind: roll view (unbound by default). drag to tilt, it wraps around the screen, tap to reset.
roll applies post and doesn't impact pace.ViewAngles. there's issues with both this and the alternative, I chose the former.

more quicksetups
proxy: basic feedback controllers
base_movables on camera bone: suggest use of event viewed_by_owner, suggest distance-based fade setup

remember editor width option
fix remember property divider position: preserve across games

multipurpose pace.GoTo function: moves camera to point toward an object, or navigate to a part in the tree, or property in the properties

fix plain disable editor cam (the camera part rework jank kinda broke it)
  • Loading branch information
pingu7867 committed Dec 24, 2024
1 parent cc9ebcc commit 154a8d3
Show file tree
Hide file tree
Showing 6 changed files with 752 additions and 23 deletions.
3 changes: 3 additions & 0 deletions lua/pac3/editor/client/menu_bar.lua
Original file line number Diff line number Diff line change
Expand Up @@ -196,8 +196,11 @@ local function populate_options(menu)
menu:AddCVar(L"Keyboard shortcuts: Legacy mode", "pac_editor_shortcuts_legacy_mode", "1", "0")
menu:AddCVar(L"inverse collapse/expand controls", "pac_reverse_collapse", "1", "0")
menu:AddCVar(L"enable shift+move/rotate clone", "pac_grab_clone", "1", "0")

menu:AddCVar(L"remember editor position", "pac_editor_remember_position", "1", "0")
menu:AddCVar(L"remember divider position", "pac_editor_remember_divider_height", "1", "0")
menu:AddCVar(L"remember editor width", "pac_editor_remember_width", "1", "0")

menu:AddCVar(L"ask before loading autoload", "pac_prompt_for_autoload", "1", "0")

local prop_pac_load_mode, pnlpplm = menu:AddSubMenu("(singleplayer only) How to handle prop/npc outfits", function() end)
Expand Down
72 changes: 72 additions & 0 deletions lua/pac3/editor/client/panels/editor.lua
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ local use_tabs = CreateClientConVar("pac_property_tabs", 1, true)
local zoom_persistent = CreateClientConVar("pac_zoom_persistent", 0, true, false, 'Keep zoom between sessions.')
local zoom_mousewheel = CreateClientConVar("pac_zoom_mousewheel", 0, true, false, 'Enable zooming with mouse wheel.')
local zoom_smooth = CreateClientConVar("pac_zoom_smooth", 0, true, false, 'Enable smooth zooming.')

local remember_divider = CreateConVar("pac_editor_remember_divider_height", "0", {FCVAR_ARCHIVE}, "Remember PAC3 editor's vertical divider position")
local remember_width = CreateConVar("pac_editor_remember_width", "0", {FCVAR_ARCHIVE}, "Remember PAC3 editor's width")

function PANEL:Init()
self:SetTitle("")
Expand Down Expand Up @@ -102,6 +104,46 @@ function PANEL:Init()
self.smoothlabel:SetWrap(true)
self.smoothlabel:SetAutoStretchVertical(true)

self.orthocheckbox = vgui.Create("DCheckBoxLabel", self.zoomsettings)
self.orthocheckbox:SetText("Orthographic")
self.orthocheckbox:Dock(TOP)
self.orthocheckbox:SetDark(true)
self.orthocheckbox:DockMargin(0,SETTING_MARGIN_TOP,0,0)
self.orthocheckbox:SetConVar("pac_camera_orthographic")
self.orthocheckbox:SetTooltip("Orthographic view projects parallel rays perpendicular to a rectangle. Instead of degrees, it is in terms of distance units (Hammer Units)\n\nThere are still —possibly engine-related— issues where objects and world geometry can disapear if looking from the wrong angle due to culling. Especially worse in tight spaces.")

self.ortholabel = vgui.Create("DLabel", self.zoomsettings)
self.ortholabel:Dock(TOP)
self.ortholabel:SetDark(true)
self.ortholabel:SetText("Enable orthographic view.")
self.ortholabel:SetWrap(true)
self.ortholabel:SetAutoStretchVertical(true)

self.ortho_nearz = vgui.Create("DNumSlider", self.zoomsettings)
self.ortho_nearz:Dock(TOP)
self.ortho_nearz:SetMin( 0 )
self.ortho_nearz:SetMax( 5000 )
self.ortho_nearz:SetDecimals( 1 )
self.ortho_nearz:SetText("NearZ")
self.ortho_nearz:SetDark(true)
self.ortho_nearz:SetDefaultValue( 0 )
self.ortho_nearz:SetValue( 0 )

self.ortho_farz = vgui.Create("DNumSlider", self.zoomsettings)
self.ortho_farz:Dock(TOP)
self.ortho_farz:SetMin( 0 )
self.ortho_farz:SetMax( 64000 )
self.ortho_farz:SetDecimals( 1 )
self.ortho_farz:SetText("FarZ")
self.ortho_farz:SetDark(true)
self.ortho_farz:SetDefaultValue( 64000 )
self.ortho_farz:SetValue( 64000 )
if not pace.camera_orthographic then
self.ortho_nearz:Hide()
self.ortho_farz:Hide()
end


self.sliderpanel = vgui.Create("DPanel", self.zoomframe)
self.sliderpanel:SetSize(180, 20)
self.sliderpanel:Dock(TOP)
Expand All @@ -113,6 +155,11 @@ function PANEL:Init()
self.zoomslider:SetMax( 100 )
self.zoomslider:SetDecimals( 0 )
self.zoomslider:SetText("Camera FOV")
if pace.camera_orthographic then
self.zoomslider:SetText("Ortho. Width")
self.zoomslider:SetMin( -10000 )
self.zoomslider:SetMax( 10000 )
end
self.zoomslider:SetDark(true)
self.zoomslider:SetDefaultValue( 75 )

Expand All @@ -129,6 +176,13 @@ function PANEL:Init()
self:SetCookieName("pac3_editor")
self:SetPos(self:GetCookieNumber("x"), BAR_SIZE)

if remember_width:GetBool() then
self.init_w = math.max(self:GetCookieNumber("width"), 200)
end
if remember_divider:GetBool() then
pace.vertical_div_height = self:GetCookieNumber("y_divider")
end

self:MakeBar()
self.lastTopBarHover = 0
self.rendertime_data = {}
Expand Down Expand Up @@ -177,6 +231,10 @@ function PANEL:OnRemove()
pace.vertical_div_height = self.div:GetTopHeight()
end

if remember_width:GetBool() then
pace.editor_width = math.max(self:GetWide(), 200)
end

if self.menu_bar:IsValid() then
self.menu_bar:Remove()
end
Expand Down Expand Up @@ -212,13 +270,27 @@ function PANEL:Think(...)

self:SetTall(ScrH() - (self.y_offset or 0))
local w = math.max(self:GetWide(), 200)

--wtf the GetWide isn't saved on Init??? I have to do this?
if self.init_w then
w = self.init_w
self.init_w = nil
end
self:SetWide(w)
self:SetPos(math.Clamp(self:GetPos(), 0, ScrW() - w), (self.y_offset or 0))

if x ~= self.last_x then
self:SetCookie("x", x)
self.last_x = x
end
if w ~= self.last_w then
self:SetCookie("width", w)
self.last_w = w
end
if pace.vertical_div_height ~= self.last_vertical_div_height then
self:SetCookie("y_divider", pace.vertical_div_height)
self.last_vertical_div_height = pace.vertical_div_height
end

if self.exit_button:IsValid() then

Expand Down
184 changes: 183 additions & 1 deletion lua/pac3/editor/client/parts.lua
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ pace.BulkSelectList = {}
pace.BulkSelectUIDs = {}
pace.BulkSelectClipboard = {}
local refresh_halo_hook = true
pace.operations_all_operations = {"wear", "copy", "paste", "cut", "paste_properties", "clone", "spacer", "registered_parts", "save", "load", "remove", "bulk_select", "bulk_apply_properties", "partsize_info", "hide_editor", "expand_all", "collapse_all", "copy_uid", "help_part_info", "reorder_movables", "arraying_menu", "criteria_process", "bulk_morph"}
pace.operations_all_operations = {"wear", "copy", "paste", "cut", "paste_properties", "clone", "spacer", "registered_parts", "save", "load", "remove", "bulk_select", "bulk_apply_properties", "partsize_info", "hide_editor", "expand_all", "collapse_all", "copy_uid", "help_part_info", "reorder_movables", "arraying_menu", "criteria_process", "bulk_morph", "view_goto", "view_lockon"}

pace.operations_default = {"help_part_info", "wear", "copy", "paste", "cut", "paste_properties", "clone", "spacer", "registered_parts", "spacer", "bulk_select", "bulk_apply_properties", "spacer", "save", "load", "spacer", "remove"}
pace.operations_legacy = {"wear", "copy", "paste", "cut", "paste_properties", "clone", "spacer", "registered_parts", "spacer", "save", "load", "spacer", "remove"}
Expand Down Expand Up @@ -132,6 +132,7 @@ local function DrawHaloHighlight(tbl)
if not pace.Active then
pac.RemoveHook("PreDrawHalos", "BulkSelectHighlights")
end
if pace.camera_orthographic then return end

--Find out the color and apply the halo
local color_string = GetConVar("pac_hover_color"):GetString()
Expand Down Expand Up @@ -2548,6 +2549,15 @@ function pace.AddQuickSetupsToPartMenu(menu, obj)
local main, pnlmain = menu:AddSubMenu("quick setups") pnlmain:SetIcon("icon16/basket_go.png")
--base_movables can restructure, but nah bones aint it
if obj.GetDrawPosition and obj.ClassName ~= "bone" and obj.ClassName ~= "bone2" and obj.ClassName ~= "bone3" then
if obj.Bone and obj.Bone == "camera" then
main:AddOption("camera bone suggestion: limit view to yourself", function()
local event = pac.CreatePart("event") event:SetEvent("viewed_by_owner") event:SetParent(obj)
end):SetImage("icon16/star.png")
if obj.GetAlpha then main:AddOption("camera bone suggestion: fade with distance", function()
local model = pac.CreatePart("model2") model:SetModel("models/empty.mdl") model:SetParent(obj.Parent) model:SetName("head_position")
local proxy = pac.CreatePart("proxy") proxy:SetExpression("clamp(2 - (part_distance(\"head_position\")/100),0,1)") proxy:SetParent(obj) proxy:SetVariableName("Alpha")
end):SetImage("icon16/star.png") end
end
local substitutes, pnl = main:AddSubMenu("Restructure / Create parent substitute", function()
pace.SubstituteBaseMovable(obj, "create_parent")
timer.Simple(20, function() if pace.recently_substituted_movable_part == obj then pace.recently_substituted_movable_part = nil end end)
Expand Down Expand Up @@ -2654,6 +2664,61 @@ function pace.AddQuickSetupsToPartMenu(menu, obj)
end):SetIcon("icon16/asterisk_yellow.png")
elseif obj.ClassName == "proxy" then
pnlmain:SetTooltip("remember you also have a preset library by right clicking on the expression field")
main:AddOption("basic feedback controller setup", function()
Derma_StringRequest("What should we call this controller variable?", "Type a name for the commands.\nThese number ranges would be appropriate for positions\nIf you make more, name them something different", "speed", function(str)
if str == "" then return end if str == " " then return end
local cmdforward = pac.CreatePart("command") cmdforward:SetParent(obj)
cmdforward:SetString("pac_proxy " .. str .. " 100")
local btn = pac.CreatePart("event") btn:SetEvent("button") btn:SetArguments("up") btn:SetParent(cmdforward)

local cmdback = pac.CreatePart("command") cmdback:SetParent(obj)
cmdback:SetString("pac_proxy " .. str .. " -100")
local btn = pac.CreatePart("event") btn:SetEvent("button") btn:SetArguments("down") btn:SetParent(cmdback)

local cmdneutral = pac.CreatePart("command") cmdneutral:SetParent(obj)
cmdneutral:SetString("pac_proxy " .. str .. " 0")
local btn = pac.CreatePart("event") btn:SetEvent("button") btn:SetArguments("up") btn:SetParent(cmdneutral) btn:SetInvert(false)
local btn = pac.CreatePart("event") btn:SetEvent("button") btn:SetArguments("down") btn:SetParent(cmdneutral) btn:SetInvert(false)

obj:SetExpression("feedback() + ftime()*command(\"".. str .. "\")")
end)
end):SetIcon("icon16/joystick.png")
main:AddOption("2D feedback controller setup", function()
Derma_StringRequest("What should we call this controller variable?", "Type a name for the commands.\nThese number ranges would be appropriate for positions\nIf you make more, name them something different", "speed", function(str)
if str == "" then return end if str == " " then return end
local cmdforward = pac.CreatePart("command") cmdforward:SetParent(obj)
cmdforward:SetString("pac_proxy " .. str .. "_x" .. " 100")
local btn = pac.CreatePart("event") btn:SetEvent("button") btn:SetArguments("up") btn:SetParent(cmdforward)

local cmdback = pac.CreatePart("command") cmdback:SetParent(obj)
cmdback:SetString("pac_proxy " .. str .. "_x" .. " -100")
local btn = pac.CreatePart("event") btn:SetEvent("button") btn:SetArguments("down") btn:SetParent(cmdback)

local cmdneutral = pac.CreatePart("command") cmdneutral:SetParent(obj)
cmdneutral:SetString("pac_proxy " .. str .. "_x" .. " 0")
local btn = pac.CreatePart("event") btn:SetEvent("button") btn:SetArguments("up") btn:SetParent(cmdneutral) btn:SetInvert(false)
local btn = pac.CreatePart("event") btn:SetEvent("button") btn:SetArguments("down") btn:SetParent(cmdneutral) btn:SetInvert(false)


local cmdright = pac.CreatePart("command") cmdright:SetParent(obj)
cmdright:SetString("pac_proxy " .. str .. "_y" .. " 100")
local btn = pac.CreatePart("event") btn:SetEvent("button") btn:SetArguments("right") btn:SetParent(cmdright)

local cmdleft = pac.CreatePart("command") cmdleft:SetParent(obj)
cmdleft:SetString("pac_proxy " .. str .. "_y" .. " -100")
local btn = pac.CreatePart("event") btn:SetEvent("button") btn:SetArguments("left") btn:SetParent(cmdleft)

local cmdneutral = pac.CreatePart("command") cmdneutral:SetParent(obj)
cmdneutral:SetString("pac_proxy " .. str .. "_y" .. " 0")
local btn = pac.CreatePart("event") btn:SetEvent("button") btn:SetArguments("left") btn:SetParent(cmdneutral) btn:SetInvert(false)
local btn = pac.CreatePart("event") btn:SetEvent("button") btn:SetArguments("right") btn:SetParent(cmdneutral) btn:SetInvert(false)
obj:SetExpression(
"feedback_x() + ftime()*command(\"".. str .. "_x\")"
.. "," ..
"feedback_y() + ftime()*command(\"".. str .. "_y\")"
)
end)
end):SetIcon("icon16/joystick.png")
main:AddOption("command feedback attractor setup (-100, -50, 0, 50, 100)", function()
Derma_StringRequest("What should we call this attractor?", "Type a name for the commands.\nThese number ranges would be appropriate for positions\nIf you make more, name them something different", "target_number", function(str)
if str == "" then return end if str == " " then return end
Expand Down Expand Up @@ -3960,6 +4025,123 @@ function pace.addPartMenuComponent(menu, obj, option_name)
substitute:AddOption("Switch with another (select two parts with bulk select)", function() pace.SwapBaseMovables(pace.BulkSelectList[1], pace.BulkSelectList[2], false) end)
substitute:AddOption("Recast into new class (warning!)", function() pace.SubstituteBaseMovable(obj, "cast") end)
end
elseif option_name == "view_lockon" then
if not obj then return end
local function add_entity_version(obj, root_owner)
local root_owner = obj:GetRootPart():GetOwner()
local lockons, pnl2 = menu:AddSubMenu("lock on to " .. tostring(root_owner))
local function viewlock(mode)
if mode ~= "toggle" then
pace.viewlock_mode = mode
else
if pace.viewlock then
if pace.viewlock ~= root_owner then
pace.viewlock = root_owner
return
end
pace.viewlock = nil
return
end
pace.viewlock = root_owner
end
if mode == "disable" then
pace.viewlock = nil
return
end
pace.viewlock_distance = pace.ViewPos:Distance(root_owner:GetPos() + root_owner:OBBCenter())
pace.viewlock = root_owner
end
lockons:AddOption("direct", function() viewlock("direct") end):SetImage("icon16/arrow_right.png")
lockons:AddOption("free pitch", function() viewlock("free pitch") end):SetImage("icon16/arrow_refresh.png")
lockons:AddOption("zero pitch", function() viewlock("zero pitch") end):SetImage("icon16/arrow_turn_right.png")
lockons:AddOption("disable", function() viewlock("disable") end):SetImage("icon16/cancel.png")
pnl2:SetImage("icon16/zoom.png")
end
local function add_part_version(obj)
local lockons, pnl2 = menu:AddSubMenu("lock on to " .. tostring(obj))
local function viewlock(mode)
if mode ~= "toggle" then
pace.viewlock_mode = mode
else
if pace.viewlock then
if pace.viewlock ~= obj then
pace.viewlock = obj
return
end
pace.viewlock = nil
return
end
pace.viewlock = obj
end
if mode == "disable" then
pace.viewlock = nil
return
end
pace.viewlock_distance = pace.ViewPos:Distance(obj:GetWorldPosition())
pace.viewlock = obj
end
lockons:AddOption("direct", function() viewlock("direct") end):SetImage("icon16/arrow_right.png")
lockons:AddOption("free pitch", function() viewlock("free pitch") end):SetImage("icon16/arrow_refresh.png")
lockons:AddOption("zero pitch", function() viewlock("zero pitch") end):SetImage("icon16/arrow_turn_right.png")
lockons:AddOption("frame of reference (x)", function() pace.viewlock_axis = "x" viewlock("frame of reference") end):SetImage("icon16/arrow_branch.png")
lockons:AddOption("frame of reference (y)", function() pace.viewlock_axis = "y" viewlock("frame of reference") end):SetImage("icon16/arrow_branch.png")
lockons:AddOption("frame of reference (z)", function() pace.viewlock_axis = "z" viewlock("frame of reference") end):SetImage("icon16/arrow_branch.png")
lockons:AddOption("disable", function() viewlock("disable") end):SetImage("icon16/cancel.png")
pnl2:SetImage("icon16/zoom.png")
end
local is_root_entity = obj:GetOwner() == obj:GetRootPart():GetOwner()
if obj.ClassName == "group" then
if is_root_entity then
add_entity_version(obj, obj:GetRootPart():GetOwner())
elseif obj:GetOwner().GetWorldPosition then
add_part_version(obj:GetOwner())
end
elseif obj.GetWorldPosition then
add_part_version(obj)
end
elseif option_name == "view_goto" then
if not obj then return end
local is_root_entity = obj:GetOwner() == obj:GetRootPart():GetOwner()
if obj.ClassName == "group" then
if is_root_entity then
local gotos, pnl2 = menu:AddSubMenu("go to")
pnl2:SetImage("icon16/arrow_turn_right.png")
local axes = {"x","y","z","world_x","world_y","world_z"}
for _,ax in ipairs(axes) do
gotos:AddOption("+" .. ax, function()
pace.GoTo(obj:GetRootPart():GetOwner(), "view", {radius = 50, axis = ax})
end):SetImage("icon16/arrow_turn_right.png")
gotos:AddOption("-" .. ax, function()
pace.GoTo(obj:GetRootPart():GetOwner(), "view", {radius = -50, axis = ax})
end):SetImage("icon16/arrow_turn_right.png")
end
elseif obj:GetOwner().GetWorldPosition then
local gotos, pnl2 = menu:AddSubMenu("go to")
pnl2:SetImage("icon16/arrow_turn_right.png")
local axes = {"x","y","z","world_x","world_y","world_z"}
for _,ax in ipairs(axes) do
gotos:AddOption("+" .. ax, function()
pace.GoTo(obj, "view", {radius = 50, axis = ax})
end):SetImage("icon16/arrow_turn_right.png")
gotos:AddOption("-" .. ax, function()
pace.GoTo(obj, "view", {radius = -50, axis = ax})
end):SetImage("icon16/arrow_turn_right.png")
end
end
elseif obj.GetWorldPosition then
local gotos, pnl2 = menu:AddSubMenu("go to")
pnl2:SetImage("icon16/arrow_turn_right.png")
local axes = {"x","y","z","world_x","world_y","world_z"}
for _,ax in ipairs(axes) do
gotos:AddOption("+" .. ax, function()
pace.GoTo(obj, "view", {radius = 50, axis = ax})
end):SetImage("icon16/arrow_turn_right.png")
gotos:AddOption("-" .. ax, function()
pace.GoTo(obj, "view", {radius = -50, axis = ax})
end):SetImage("icon16/arrow_turn_right.png")
end
end

end

end
Expand Down
Loading

0 comments on commit 154a8d3

Please sign in to comment.