Files
wnsrc/gamemodes/sandbox/gamemode/gui/iconeditor.lua

655 lines
18 KiB
Lua
Raw Normal View History

2024-08-04 23:54:45 +03:00
--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local PANEL = {}
AccessorFunc( PANEL, "m_strModel", "Model" )
AccessorFunc( PANEL, "m_pOrigin", "Origin" )
AccessorFunc( PANEL, "m_bCustomIcon", "CustomIcon" )
function PANEL:Init()
self:SetSize( 762, 502 )
self:SetTitle( "#smwidget.icon_editor" )
local left = self:Add( "Panel" )
left:Dock( LEFT )
left:SetWide( 400 )
self.LeftPanel = left
local bg = left:Add( "DPanel" )
bg:Dock( FILL )
bg:DockMargin( 0, 0, 0, 4 )
bg.Paint = function( s, w, h ) draw.RoundedBox( 0, 0, 0, w, h, Color( 0, 0, 0, 128 ) ) end
self.SpawnIcon = bg:Add( "SpawnIcon" )
--self.SpawnIcon.DoClick = function() self:RenderIcon() end
self.ModelPanel = bg:Add( "DAdjustableModelPanel" )
self.ModelPanel:Dock( FILL )
self.ModelPanel.FarZ = 32768
local mat_wireframe = Material( "models/wireframe" )
function self.ModelPanel.PostDrawModel( mdlpnl, ent )
if ( self.ShowOriginPnl:GetChecked() ) then
render.DrawLine( vector_origin, Vector( 0, 0, 100 ), Color( 0, 0, 255 ) )
render.DrawLine( vector_origin, Vector( 0, 100, 0 ), Color( 0, 255, 0 ) )
render.DrawLine( vector_origin, Vector( 100, 0, 0 ), Color( 255, 0, 0 ) )
end
if ( self.ShowBBoxPnl:GetChecked() ) then
local mins, maxs = ent:GetRenderBounds()
local scale = 1
mat_wireframe:SetVector( "$color", Vector( 1, 1, 1 ) )
render.SetMaterial( mat_wireframe )
render.DrawBox( ent:GetPos(), ent:GetAngles(), mins * scale, maxs * scale )
end
end
local controls = left:Add( "Panel" )
controls:SetTall( 64 )
controls:Dock( BOTTOM )
local controls_anim = controls:Add( "Panel" )
controls_anim:SetTall( 20 )
controls_anim:Dock( TOP )
controls_anim:DockMargin( 0, 0, 0, 4 )
controls_anim:MoveToBack()
self.AnimTrack = controls_anim:Add( "DSlider" )
self.AnimTrack:Dock( FILL )
self.AnimTrack:SetNotches( 100 )
self.AnimTrack:SetTrapInside( true )
self.AnimTrack:SetLockY( 0.5 )
self.AnimPause = controls_anim:Add( "DImageButton" )
self.AnimPause:SetImage( "icon16/control_pause_blue.png" )
self.AnimPause:SetStretchToFit( false )
self.AnimPause:SetPaintBackground( true )
self.AnimPause:SetIsToggle( true )
self.AnimPause:SetToggle( false )
self.AnimPause:Dock( LEFT )
self.AnimPause:SetWide( 32 )
local BestGuess = controls:Add( "DImageButton" )
BestGuess:SetImage( "icon32/wand.png" )
BestGuess:SetStretchToFit( false )
BestGuess:SetPaintBackground( true )
BestGuess.DoClick = function() self:BestGuessLayout() end
BestGuess:Dock( LEFT )
BestGuess:DockMargin( 0, 0, 0, 0 )
BestGuess:SetWide( 50 )
BestGuess:SetTooltip( "Best Guess" )
local FullFrontal = controls:Add( "DImageButton" )
FullFrontal:SetImage( "icon32/hand_point_090.png" )
FullFrontal:SetStretchToFit( false )
FullFrontal:SetPaintBackground( true )
FullFrontal.DoClick = function() self:FullFrontalLayout() end
FullFrontal:Dock( LEFT )
FullFrontal:DockMargin( 2, 0, 0, 0 )
FullFrontal:SetWide( 50 )
FullFrontal:SetTooltip( "Front" )
local Above = controls:Add( "DImageButton" )
Above:SetImage( "icon32/hand_property.png" )
Above:SetStretchToFit( false )
Above:SetPaintBackground( true )
Above.DoClick = function() self:AboveLayout() end
Above:Dock( LEFT )
Above:DockMargin( 2, 0, 0, 0 )
Above:SetWide( 50 )
Above:SetTooltip( "Above" )
local Right = controls:Add( "DImageButton" )
Right:SetImage( "icon32/hand_point_180.png" )
Right:SetStretchToFit( false )
Right:SetPaintBackground( true )
Right.DoClick = function() self:RightLayout() end
Right:Dock( LEFT )
Right:DockMargin( 2, 0, 0, 0 )
Right:SetWide( 50 )
Right:SetTooltip( "Right" )
local Origin = controls:Add( "DImageButton" )
Origin:SetImage( "icon32/hand_point_090.png" )
Origin:SetStretchToFit( false )
Origin:SetPaintBackground( true )
Origin.DoClick = function() self:OriginLayout() end
Origin:Dock( LEFT )
Origin:DockMargin( 2, 0, 0, 0 )
Origin:SetWide( 50 )
Origin:SetTooltip( "Center" )
local Render = controls:Add( "DButton" )
Render:SetText( "RENDER" )
Render.DoClick = function() self:RenderIcon() end
Render:Dock( RIGHT )
Render:DockMargin( 2, 0, 0, 0 )
Render:SetWide( 50 )
Render:SetTooltip( "Render Icon" )
local Picker = controls:Add( "DImageButton" )
Picker:SetImage( "icon32/color_picker.png" )
Picker:SetStretchToFit( false )
Picker:SetPaintBackground( true )
Picker:Dock( RIGHT )
Picker:DockMargin( 2, 0, 0, 0 )
Picker:SetWide( 50 )
Picker:SetTooltip( "Pick a new model from an entity" )
Picker.DoClick = function()
self:SetVisible( false )
util.worldpicker.Start( function( tr )
self:SetVisible( true )
if ( !IsValid( tr.Entity ) ) then return end
self:SetFromEntity( tr.Entity )
end )
end
local right = self:Add( "DPropertySheet" )
right:Dock( FILL )
right:SetPadding( 0 )
right:DockMargin( 4, 0, 0, 0 )
self.PropertySheet = right
-- Animations
local anims = right:Add( "Panel" )
anims:Dock( FILL )
anims:DockPadding( 2, 0, 2, 2 )
right:AddSheet( "#smwidget.animations", anims, "icon16/monkey.png" )
self.AnimList = anims:Add( "DListView" )
self.AnimList:AddColumn( "name" )
self.AnimList:Dock( FILL )
self.AnimList:SetMultiSelect( false )
self.AnimList:SetHideHeaders( true )
-- Bodygroups
local pnl = right:Add( "Panel" )
pnl:Dock( FILL )
pnl:DockPadding( 7, 0, 7, 7 )
self.BodygroupTab = right:AddSheet( "#smwidget.bodygroups", pnl, "icon16/brick.png" )
self.BodyList = pnl:Add( "DScrollPanel" )
self.BodyList:Dock( FILL )
--This kind of works but they don't move their stupid mouths. So fuck off.
--[[
self.Scenes = pnl:Add( "DTree" )
self.Scenes:Dock( BOTTOM )
self.Scenes:SetSize( 200, 200 )
self.Scenes.DoClick = function( _, node )
if ( !node.FileName ) then return end
local ext = string.GetExtensionFromFilename( node.FileName )
if( ext != "vcd" ) then return end
self.ModelPanel:StartScene( node.FileName )
MsgN( node.FileName )
end
local materials = self.Scenes.RootNode:AddFolder( "Scenes", "scenes/", true )
materials:SetIcon( "icon16/photos.png" )--]]
-- Settings
local settings = right:Add( "Panel" )
settings:Dock( FILL )
settings:DockPadding( 7, 0, 7, 7 )
right:AddSheet( "#smwidget.settings", settings, "icon16/cog.png" )
local bbox = settings:Add( "DCheckBoxLabel" )
bbox:SetText( "Show Bounding Box" )
bbox:Dock( TOP )
bbox:DockMargin( 0, 0, 0, 3 )
bbox:SetDark( true )
bbox:SetCookieName( "model_editor_bbox" )
self.ShowBBoxPnl = bbox
local origin = settings:Add( "DCheckBoxLabel" )
origin:SetText( "Show Origin" )
origin:Dock( TOP )
origin:SetDark( true )
origin:SetCookieName( "model_editor_origin" )
self.ShowOriginPnl = origin
local playSpeed = settings:Add( "DNumSlider" )
playSpeed:SetText( "Playback Speed" )
playSpeed:Dock( TOP )
playSpeed:SetValue( 1 )
playSpeed:SetMinMax( -1, 2 )
playSpeed:SetDark( true )
playSpeed.OnValueChanged = function( s, value )
self.ModelPanel:GetEntity():SetPlaybackRate( value )
end
local moveSpeed = settings:Add( "DNumSlider" )
moveSpeed:SetText( "Move Speed" )
moveSpeed:Dock( TOP )
moveSpeed:SetMinMax( 0.5, 8 )
moveSpeed:SetValue( 1 )
moveSpeed:SetDark( true )
moveSpeed.OnValueChanged = function( p )
self.ModelPanel:SetMovementScale( p:GetValue() )
end
moveSpeed:SetCookieName( "iconeditor_movespeed" )
local angle = settings:Add( "DTextEntry" )
angle:SetTooltip( "Entity Angles" )
angle:Dock( TOP )
angle:DockMargin( 0, 0, 0, 3 )
angle:SetZPos( 100 )
angle.OnChange = function( p )
self.ModelPanel:GetEntity():SetAngles( Angle( p:GetText() ) )
end
self.TargetAnglePanel = angle
local cam_angle = settings:Add( "DTextEntry" )
cam_angle:SetTooltip( "Camera Angles" )
cam_angle:Dock( TOP )
cam_angle:DockMargin( 0, 0, 0, 3 )
cam_angle:SetZPos( 101 )
cam_angle.OnChange = function( p )
self.ModelPanel:SetLookAng( Angle( p:GetText() ) )
end
self.TargetCamAnglePanel = cam_angle
local cam_pos = settings:Add( "DTextEntry" )
cam_pos:SetTooltip( "Camera Position" )
cam_pos:Dock( TOP )
cam_pos:DockMargin( 0, 0, 0, 3 )
cam_pos:SetZPos( 102 )
cam_pos.OnChange = function( p )
self.ModelPanel:SetCamPos( Vector( p:GetText() ) )
end
self.TargetCamPosPanel = cam_pos
local cam_fov = settings:Add( "DNumSlider" )
cam_fov:SetText( "Camera FOV" )
cam_fov:Dock( TOP )
cam_fov:DockMargin( 0, 0, 0, 3 )
cam_fov:SetZPos( 103 )
cam_fov:SetMinMax( 0.001, 179 )
cam_fov:SetDark( true )
cam_fov.OnValueChanged = function( p )
self.ModelPanel:SetFOV( p:GetValue() )
end
self.TargetCamFOVPanel = cam_fov
local copypaste_cam = settings:Add( "Panel" )
copypaste_cam:SetTall( 20 )
copypaste_cam:Dock( TOP )
copypaste_cam:SetZPos( 104 )
copypaste_cam:DockMargin( 0, 0, 0, 4 )
local copy = copypaste_cam:Add( "DButton" )
copy:Dock( FILL )
copy:SetText( "Copy Camera Settings" )
copy:DockMargin( 0, 0, 3, 0 )
copy.DoClick = function() SetClipboardText( util.TableToJSON( {
pos = self.ModelPanel:GetCamPos(),
ang = self.ModelPanel:GetLookAng(),
fov = self.ModelPanel:GetFOV(),
mdl_ang = self.ModelPanel:GetEntity():GetAngles()
} ) ) end
local paste = copypaste_cam:Add( "DTextEntry" )
paste:SetWide( 140 ) -- Ew
paste:Dock( RIGHT )
paste:SetPlaceholderText( "Paste Camera Settings Here" )
paste.OnChange = function( p )
local tabl = util.JSONToTable( p:GetText() )
if ( tabl ) then
self.ModelPanel:SetCamPos( tabl.pos )
self.ModelPanel:SetLookAng( tabl.ang )
self.ModelPanel:SetFOV( tabl.fov )
self.ModelPanel:GetEntity():SetAngles( tabl.mdl_ang )
end
p:SetText( "" )
end
local labels = { "Pitch", "Yaw", "Roll" }
for i = 1, 3 do
local rotate45 = settings:Add( "DButton" )
rotate45:SetText( "Rotate Entity +/-45 " .. labels[ i ] )
rotate45:Dock( TOP )
rotate45:DockMargin( 0, 0, 0, 3 )
rotate45:SetZPos( 110 + i )
rotate45.DoClick = function( p )
local aang = self.ModelPanel:GetEntity():GetAngles()
aang[ i ] = aang[ i ] + 45
self.ModelPanel:GetEntity():SetAngles( aang )
end
rotate45.DoRightClick = function( p )
local aang = self.ModelPanel:GetEntity():GetAngles()
aang[ i ] = aang[ i ] - 45
self.ModelPanel:GetEntity():SetAngles( aang )
end
end
end
function PANEL:SetDefaultLighting()
self.ModelPanel:SetAmbientLight( Color( 255 * 0.3, 255 * 0.3, 255 * 0.3 ) )
self.ModelPanel:SetDirectionalLight( BOX_FRONT, Color( 255 * 1.3, 255 * 1.3, 255 * 1.3 ) )
self.ModelPanel:SetDirectionalLight( BOX_BACK, Color( 255 * 0.2, 255 * 0.2, 255 * 0.2 ) )
self.ModelPanel:SetDirectionalLight( BOX_RIGHT, Color( 255 * 0.2, 255 * 0.2, 255 * 0.2 ) )
self.ModelPanel:SetDirectionalLight( BOX_LEFT, Color( 255 * 0.2, 255 * 0.2, 255 * 0.2 ) )
self.ModelPanel:SetDirectionalLight( BOX_TOP, Color( 255 * 2.3, 255 * 2.3, 255 * 2.3 ) )
self.ModelPanel:SetDirectionalLight( BOX_BOTTOM, Color( 255 * 0.1, 255 * 0.1, 255 * 0.1 ) )
end
function PANEL:BestGuessLayout()
local ent = self.ModelPanel:GetEntity()
if ( !IsValid( ent ) ) then return end
local pos = ent:GetPos()
local ang = ent:GetAngles()
local tab = PositionSpawnIcon( ent, pos, true )
ent:SetAngles( ang )
if ( tab ) then
self.ModelPanel:SetCamPos( tab.origin )
self.ModelPanel:SetFOV( tab.fov )
self.ModelPanel:SetLookAng( tab.angles )
end
end
function PANEL:FullFrontalLayout()
local ent = self.ModelPanel:GetEntity()
if ( !IsValid( ent ) ) then return end
local pos = ent:GetPos()
local campos = pos + Vector( -200, 0, 0 )
self.ModelPanel:SetCamPos( campos )
self.ModelPanel:SetFOV( 45 )
self.ModelPanel:SetLookAng( ( campos * -1 ):Angle() )
end
function PANEL:AboveLayout()
local ent = self.ModelPanel:GetEntity()
if ( !IsValid( ent ) ) then return end
local pos = ent:GetPos()
local campos = pos + Vector( 0, 0, 200 )
self.ModelPanel:SetCamPos( campos )
self.ModelPanel:SetFOV( 45 )
self.ModelPanel:SetLookAng( ( campos * -1 ):Angle() )
end
function PANEL:RightLayout()
local ent = self.ModelPanel:GetEntity()
if ( !IsValid( ent ) ) then return end
local pos = ent:GetPos()
local campos = pos + Vector( 0, 200, 0 )
self.ModelPanel:SetCamPos( campos )
self.ModelPanel:SetFOV( 45 )
self.ModelPanel:SetLookAng( ( campos * -1 ):Angle() )
end
function PANEL:OriginLayout()
local ent = self.ModelPanel:GetEntity()
if ( !IsValid( ent ) ) then return end
local pos = ent:GetPos()
local campos = pos + vector_origin
self.ModelPanel:SetCamPos( campos )
self.ModelPanel:SetFOV( 45 )
self.ModelPanel:SetLookAng( Angle( 0, -180, 0 ) )
end
function PANEL:UpdateEntity( ent )
ent:SetEyeTarget( self.ModelPanel:GetCamPos() )
if ( IsValid( self.TargetAnglePanel ) && !self.TargetAnglePanel:IsEditing() && !self.TargetAnglePanel:IsHovered() ) then
self.TargetAnglePanel:SetText( tostring( ent:GetAngles() ) )
end
if ( IsValid( self.TargetCamAnglePanel ) && !self.TargetCamAnglePanel:IsEditing() && !self.TargetCamAnglePanel:IsHovered() ) then
self.TargetCamAnglePanel:SetText( tostring( self.ModelPanel:GetLookAng() ) )
end
if ( IsValid( self.TargetCamPosPanel ) && !self.TargetCamPosPanel:IsEditing() && !self.TargetCamPosPanel:IsHovered() ) then
self.TargetCamPosPanel:SetText( tostring( self.ModelPanel:GetCamPos() ) )
end
if ( IsValid( self.TargetCamFOVPanel ) && !self.TargetCamFOVPanel:IsEditing() && !self.TargetCamFOVPanel:IsHovered() ) then
self.TargetCamFOVPanel:SetValue( self.ModelPanel:GetFOV() )
end
if ( self.AnimTrack:GetDragging() ) then
ent:SetCycle( self.AnimTrack:GetSlideX() )
self.AnimPause:SetToggle( true )
elseif ( ent:GetCycle() != self.AnimTrack:GetSlideX() ) then
local cyc = ent:GetCycle()
if ( cyc < 0 ) then cyc = cyc + 1 end
self.AnimTrack:SetSlideX( cyc )
end
if ( !self.AnimPause:GetToggle() ) then
ent:FrameAdvance( FrameTime() )
end
end
function PANEL:RenderIcon()
local tab = {}
tab.ent = self.ModelPanel:GetEntity()
tab.cam_pos = self.ModelPanel:GetCamPos()
tab.cam_ang = self.ModelPanel:GetLookAng()
tab.cam_fov = self.ModelPanel:GetFOV()
self.SpawnIcon:RebuildSpawnIconEx( tab )
end
function PANEL:SetIcon( icon )
if ( !IsValid( icon ) ) then return end
local model = icon:GetModelName()
self:SetOrigin( icon )
self.SpawnIcon:SetSize( icon:GetSize() )
self.SpawnIcon:InvalidateLayout( true )
local w, h = icon:GetSize()
if ( w / h < 1 ) then
self:SetSize( 700, 502 + 400 )
self.LeftPanel:SetWide( 400 )
elseif ( w / h > 1 ) then
self:SetSize( 900, 502 - 100 )
self.LeftPanel:SetWide( 600 )
else
self:SetSize( 700, 502 )
self.LeftPanel:SetWide( 400 )
end
if ( !model or model == "" ) then
self:SetModel( "error.mdl" )
self.SpawnIcon:SetSpawnIcon( icon:GetIconName() )
self:SetCustomIcon( true )
else
self:SetModel( model )
self.SpawnIcon:SetModel( model, icon:GetSkinID(), icon:GetBodyGroup() )
self:SetCustomIcon( false )
end
-- Keep the spawnmenu open
g_SpawnMenu:HangOpen( true )
end
function PANEL:Refresh()
if ( !self:GetModel() ) then return end
self.ModelPanel:SetModel( self:GetModel() )
self.ModelPanel.LayoutEntity = function() self:UpdateEntity( self.ModelPanel:GetEntity() ) end
local ent = self.ModelPanel:GetEntity()
if ( !IsValid( ent ) ) then return end
ent:SetSkin( self.SpawnIcon:GetSkinID() )
ent:SetBodyGroups( self.SpawnIcon:GetBodyGroup() )
ent:SetLOD( 0 )
self:BestGuessLayout()
self:FillAnimations( ent )
self:SetDefaultLighting()
end
function PANEL:FillAnimations( ent )
self.AnimList:Clear()
for k, v in SortedPairsByValue( ent:GetSequenceList() or {} ) do
local line = self.AnimList:AddLine( string.lower( v ) )
line.OnSelect = function()
local speed = ent:GetPlaybackRate()
ent:ResetSequence( v )
ent:SetCycle( 0 )
ent:SetPlaybackRate( speed )
if ( speed < 0 ) then ent:SetCycle( 1 ) end
end
end
self.BodyList:Clear()
local newItems = 0
if ( ent:SkinCount() > 1 ) then
local skinSlider = self.BodyList:Add( "DNumSlider" )
skinSlider:Dock( TOP )
skinSlider:DockMargin( 0, 0, 0, 3 )
skinSlider:SetText( "Skin" )
skinSlider:SetDark( true )
skinSlider:SetDecimals( 0 )
skinSlider:SetMinMax( 0, ent:SkinCount() - 1 )
skinSlider:SetValue( ent:GetSkin() )
skinSlider.OnValueChanged = function( s, newVal )
newVal = math.Round( newVal )
ent:SetSkin( newVal )
if ( IsValid( self:GetOrigin() ) ) then self:GetOrigin():SkinChanged( newVal ) end
-- If we're not using a custom, change our spawnicon
-- so we save the new skin in the right place...
if ( !self:GetCustomIcon() ) then
self.SpawnIcon:SetModel( self.SpawnIcon:GetModelName(), newVal, self.SpawnIcon:GetBodyGroup() )
end
end
newItems = newItems + 1
end
for k = 0, ent:GetNumBodyGroups() - 1 do
if ( ent:GetBodygroupCount( k ) <= 1 ) then continue end
local bgSlider = self.BodyList:Add( "DNumSlider" )
bgSlider:Dock( TOP )
bgSlider:DockMargin( 0, 0, 0, 3 )
bgSlider:SetDark( true )
bgSlider:SetDecimals( 0 )
bgSlider:SetText( ent:GetBodygroupName( k ) )
bgSlider:SetMinMax( 0, ent:GetBodygroupCount( k ) - 1 )
bgSlider:SetValue( ent:GetBodygroup( k ) )
bgSlider.BodyGroupID = k
bgSlider.OnValueChanged = function( s, newVal )
newVal = math.Round( newVal )
ent:SetBodygroup( s.BodyGroupID, newVal )
if ( IsValid( self:GetOrigin() ) ) then self:GetOrigin():BodyGroupChanged( s.BodyGroupID, newVal ) end
-- If we're not using a custom, change our spawnicon
-- so we save the new skin in the right place...
if ( !self:GetCustomIcon() ) then
self.SpawnIcon:SetBodyGroup( s.BodyGroupID, newVal )
self.SpawnIcon:SetModel( self.SpawnIcon:GetModelName(), self.SpawnIcon:GetSkinID(), self.SpawnIcon:GetBodyGroup() )
end
end
newItems = newItems + 1
end
if ( newItems > 0 ) then
self.BodygroupTab.Tab:SetVisible( true )
else
self.BodygroupTab.Tab:SetVisible( false )
end
local propertySheet = self.PropertySheet
propertySheet.tabScroller:InvalidateLayout()
end
function PANEL:SetFromEntity( ent )
if ( !IsValid( ent ) ) then return end
local bodyStr = ""
for i = 0, 8 do
bodyStr = bodyStr .. math.min( ent:GetBodygroup( i ) or 0, 9 )
end
self.SpawnIcon:SetModel( ent:GetModel(), ent:GetSkin(), bodyStr )
self:SetModel( ent:GetModel() )
self:Refresh()
end
vgui.Register( "IconEditor", PANEL, "DFrame" )