--[[ | 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 ActiveVideo = nil VideoSettings = nil local stats = { reset = 0, encodetime = 0, starttime = 0, last_encodetime = 0 } concommand.Add( "gm_demo_to_video", function( ply, cmd, args ) local demoname = args[ 1 ] if ( !demoname ) then return end local settings = { name = "filled_in_later", container = "webm", video = "vp8", audio = "vorbis", bitrate = 25000, quality = 1, width = 640, height = 480, fps = 25, frameblend = 1, fbshutter = 0.5, dofsteps = 0, dofpasses = 0, doffocusspeed = 1.0, dofsize = 1.0, viewsmooth = 0.0, possmooth = 0.0 } local Window = vgui.Create( "DFrame" ) Window:SetTitle( "Render Video" ) Window:SetSize( 600, 400 ) Window:LoadGWENFile( "resource/ui/DemoToVideo.gwen" ) Window:Center() Window:MakePopup() local inCodec = Window:Find( "inCodec" ) local inQuality = Window:Find( "inQuality" ) local inSize = Window:Find( "inSize" ) local btnStart = Window:Find( "btnStart" ) local inBitRate = Window:Find( "inBitRate" ) local inFPS = Window:Find( "inFPS" ) local inFrameBlend = Window:Find( "inFrameBlend" ) local inFBShutter = Window:Find( "inFBShutter" ) local inDOF = Window:Find( "inDepthOfField" ) local inDOFSpeed = Window:Find( "inDOFFocusSpeed" ) local inDOFSize = Window:Find( "inDOFBlurSize" ) local inViewSmooth = Window:Find( "inViewSmooth" ) local inPosSmooth = Window:Find( "inPosSmooth" ) inFPS.OnChange = function() settings.fps = inFPS:GetInt() end inFPS:SetText( settings.fps ) inBitRate.OnChange = function() settings.bitrate = inBitRate:GetInt() end inBitRate:SetText( settings.bitrate ) -- TODO!!! inCodec.OnSelect = function( _, index, value, data ) settings.container = data[1]; settings.video = data[2]; settings.audio = data[3] end inCodec:AddChoice( "webm", { "webm", "vp8", "vorbis" }, true ) inCodec:AddChoice( "ogg", { "ogg", "theora", "vorbis" } ) inQuality.OnSelect = function( _, index, value, data ) settings.quality = data end inQuality:AddChoice( "0.0 - Low (but fast)", 0 ) inQuality:AddChoice( "0.5 - Medium", 0.5 ) inQuality:AddChoice( "1.0 - Highest (but slow)", 1, true ) -- TODO!!! inSize.OnSelect = function( _, index, value, data ) settings.width = data[1] settings.height = data[2] end local sw, sh = ScrW(), ScrH() inSize:AddChoice( sw .. " x " .. sh .. " (highest)", { sw, sh }, true ) sw, sh = sw * 0.66666, sh * 0.66666 inSize:AddChoice( math.ceil( sw ) .. " x " .. math.ceil( sh ), { sw, sh }, true ) sw, sh = sw * 0.5, sh * 0.5 inSize:AddChoice( math.ceil( sw ) .. " x " .. math.ceil( sh ), { sw, sh }, true ) inFrameBlend.OnSelect = function( _, index, value, data ) settings.frameblend = data end inFrameBlend:AddChoice( "Off", 1, true ) inFrameBlend:AddChoice( "Draft (8 Samples)", 8 ) inFrameBlend:AddChoice( "Good (16 Samples)", 16 ) inFrameBlend:AddChoice( "Great (32 Samples)", 32 ) inFrameBlend:AddChoice( "Overkill (64 Samples)", 64 ) inFrameBlend:AddChoice( "OverOverKill (128 Samples)", 128 ) inFBShutter.OnSelect = function( _, index, value, data ) settings.fbshutter = data end inFBShutter:AddChoice( "90", 0.75 ) inFBShutter:AddChoice( "180", 0.5, true ) inFBShutter:AddChoice( "240", 0.25 ) inFBShutter:AddChoice( "360", 0.0 ) -- -- DOF -- inDOF.OnSelect = function( _, index, value, data ) settings.dofsteps = data[1]; settings.dofpasses = data[2] end inDOF:AddChoice( "Off", { 0, 0 }, true ) inDOF:AddChoice( "Draft (21 Samples)", { 6, 3 } ) inDOF:AddChoice( "Good (72 Samples)", { 12, 6 } ) inDOF:AddChoice( "Best (288 Samples)", { 24, 12 } ) inDOFSpeed.OnChange = function() settings.doffocusspeed = inDOFSpeed:GetFloat() end inDOFSpeed:SetText( "1.0" ) inDOFSize.OnChange = function() settings.dofsize = inDOFSize:GetFloat() end inDOFSize:SetText( "1.0" ) -- -- Smoothing -- inViewSmooth.OnSelect = function( _, index, value, data ) settings.viewsmooth = data end inViewSmooth:AddChoice( "Off", 0.0, true ) inViewSmooth:AddChoice( "Minimal", 0.2 ) inViewSmooth:AddChoice( "Low", 0.4 ) inViewSmooth:AddChoice( "Medium", 0.7 ) inViewSmooth:AddChoice( "High", 0.8 ) inViewSmooth:AddChoice( "Lots", 0.9 ) inViewSmooth:AddChoice( "Too Smooth", 0.97 ) inPosSmooth.OnSelect = function( _, index, value, data ) settings.possmooth = data end inPosSmooth:AddChoice( "Off", 0.0, true ) inPosSmooth:AddChoice( "Minimal", 0.2 ) inPosSmooth:AddChoice( "Low", 0.4 ) inPosSmooth:AddChoice( "Medium", 0.7 ) inPosSmooth:AddChoice( "High", 0.8 ) inPosSmooth:AddChoice( "Lots", 0.9 ) inPosSmooth:AddChoice( "Too Smooth", 0.97 ) btnStart.DoClick = function() -- Fill in the name here, or we'll be overwriting the same video! local cleanname = string.GetFileFromFilename( demoname ) cleanname = cleanname:Replace( ".", "_" ) cleanname = cleanname .. " " .. util.DateStamp() settings.name = cleanname PrintTable( settings ) ActiveVideo, error = video.Record( settings ) if ( !ActiveVideo ) then Derma_Message( "Couldn't record video: \n" .. error, "Make Video Error", "OK" ) return end RunConsoleCommand( "sv_cheats", 1 ) RunConsoleCommand( "host_framerate", settings.fps * settings.frameblend ) RunConsoleCommand( "snd_fixed_rate", 1 ) RunConsoleCommand( "progress_enable", 1 ) RunConsoleCommand( "playdemo", demoname ) VideoSettings = table.Copy( settings ) Window:Remove() end end, nil, "", { FCVAR_DONTRECORD } ) local function FinishRecording() VideoSettings = nil ActiveVideo:Finish() ActiveVideo = nil RunConsoleCommand( "host_framerate", 0 ) RunConsoleCommand( "sv_cheats", 0 ) RunConsoleCommand( "snd_fixed_rate", 0 ) MsgN( "Rendering Finished - Took ", SysTime() - stats.starttime, " seconds" ) end local function UpdateFrame() if ( !engine.IsPlayingDemo() ) then if ( !VideoSettings.started ) then return end FinishRecording() return end if ( !VideoSettings.started ) then if ( gui.IsGameUIVisible() ) then return end VideoSettings.started = true VideoSettings.framecount = 0 stats.starttime = SysTime() end end local function DrawOverlay() if ( !VideoSettings ) then return end local complete = engine.GetDemoPlaybackTick() / engine.GetDemoPlaybackTotalTicks() local x = ScrW() * 0.1 local y = ScrH() * 0.8 local w = ScrW() * 0.8 local h = ScrH() * 0.05 surface.SetFont( "DermaDefault" ) surface.SetTextColor( 255, 255, 255, 255 ) -- Static text local info = "Rendering " .. math.floor( VideoSettings.width ) .. "x" .. math.floor( VideoSettings.height ) .. " at " .. math.floor( VideoSettings.fps ) .. "fps " local with = {} if ( VideoSettings.dofsteps > 0 ) then table.insert( with, "DOF" ) end if ( VideoSettings.frameblend > 1 ) then table.insert( with, "Frame Blending" ) end if ( VideoSettings.viewsmooth > 0 ) then table.insert( with, "View Smoothing" ) end if ( VideoSettings.possmooth > 0 ) then table.insert( with, "Position Smoothing" ) end if ( #with > 0 ) then local withS = table.concat( with, ", " ) info = info .. "with " .. withS end info = info .. " (rendering " .. ( VideoSettings.frameblend * math.max( VideoSettings.dofsteps, 1 ) * math.max( VideoSettings.dofpasses, 1 ) ) .. " frames per frame)" local tw, th = surface.GetTextSize( info ) surface.SetTextPos( x, y - th - 10 ) surface.DrawText( info ) -- The box surface.SetDrawColor( 0, 0, 0, 50 ) surface.DrawRect( x-3, y-3, w + 6, h + 6 ) surface.SetDrawColor( 255, 255, 255, 200 ) surface.DrawRect( x -2, y-2, w + 4, 2 ) surface.DrawRect( x - 2, y, 2, h ) surface.DrawRect( x + w, y, 2, h ) surface.DrawRect( x-2, y + h, w + 4, 2 ) surface.SetDrawColor( 255, 255, 100, 150 ) surface.DrawRect( x + 1, y + 1, w * complete - 2, h - 2 ) -- Demo length local demolength = "Demo Length: " .. string.FormattedTime( engine.GetDemoPlaybackTotalTicks() * engine.TickInterval(), "%2i:%02i" ) local tw, th = surface.GetTextSize( demolength ) surface.SetTextPos( x + w - tw, y - th - 10 ) surface.DrawText( demolength ) if ( !VideoSettings.started ) then return end -- Timers surface.SetTextPos( x, y + h + 10 ) surface.DrawText( "Time Taken: " .. string.NiceTime( SysTime() - stats.starttime ) ) local tw, th = surface.GetTextSize( "Time Left: " .. string.NiceTime( stats.timeremaining ) ) surface.SetTextPos( x + w - tw, y + h + 10 ) surface.DrawText( "Time Left: " .. string.NiceTime( stats.timeremaining ) ) local demotime = string.FormattedTime( engine.GetDemoPlaybackTick() * engine.TickInterval(), "%2i:%02i" ) local tw, th = surface.GetTextSize( demotime ) if ( w * complete > tw + 20 ) then surface.SetTextColor( 0, 0, 0, 200 ) surface.SetTextPos( x + w * complete - tw - 10, y + h * 0.5 - th * 0.5 ) surface.DrawText( demotime ) end local demotime = string.FormattedTime( ( engine.GetDemoPlaybackTotalTicks() - engine.GetDemoPlaybackTick() ) * engine.TickInterval(), "%2i:%02i" ) local tw, th = surface.GetTextSize( demotime ) if ( w - w * complete > tw + 20 ) then surface.SetTextColor( 255, 255, 255, 200 ) surface.SetTextPos( x + w * complete + 10, y + h * 0.5 - th * 0.5 ) surface.DrawText( demotime ) end end hook.Add( "CaptureVideo", "CaptureDemoFrames", function() if ( !ActiveVideo ) then return end if ( !VideoSettings ) then return end UpdateFrame() DrawOverlay() if ( stats.reset < SysTime() ) then stats.reset = SysTime() + 1 stats.last_encodetime = stats.encodetime stats.encodetime = 0 local timetaken = SysTime() - stats.starttime local fractioncomplete = engine.GetDemoPlaybackTotalTicks() / engine.GetDemoPlaybackTick() stats.timeremaining = ( timetaken * fractioncomplete ) - timetaken if ( stats.timeremaining < 0 ) then stats.timeremaining = 0 end end end ) function RecordDemoFrame() if ( !ActiveVideo ) then return end if ( !VideoSettings ) then return end if ( !VideoSettings.started ) then return end ActiveVideo:AddFrame( 1 / VideoSettings.fps, true ) VideoSettings.framecount = VideoSettings.framecount + 1 end