using Godot; using System.Collections.Generic; namespace Rokojori { [Tool] [GlobalClass] public partial class RokojoriCompositorEffect:CompositorEffect { protected RenderingDevice _rd; public RenderingDevice rd => _rd; protected int _groupSize = 16; protected List _cleanUps = new List(); protected List _cleanUpInfo = new List(); EditableRokojoriCompositorContext _context; protected bool _hasContext = false; public RokojoriCompositorContext context => _hasContext ? _context : null; protected List _messages = new List(); public List messages => _messages; public bool logMessages = true; public int messageLogLevel = Messages.GetLevel( MessageType.Verbose ); protected virtual void OnConfigure(){} protected virtual void OnInitialize(){} protected virtual void ForAllViews(){} protected virtual void RenderView(){} public RokojoriCompositorEffect():base() { RenderingServer.CallOnRenderThread( Callable.From( _InitializeCompositorEffect ) ); } protected void _InitializeCompositorEffect() { OnConfigure(); _rd = RenderingServer.Singleton.GetRenderingDevice(); if ( _rd == null ) { Error( "Found no rendering device" ); return; } _context = new EditableRokojoriCompositorContext(); _context.SetEffect( this ); _hasContext = true; OnInitialize(); _hasContext = false; } public override void _RenderCallback( int effectCallbackType, RenderData renderData ) { _hasContext = false; if ( rd == null ) { Error( "No render device" ); return; } var sceneBuffers = ( RenderSceneBuffersRD ) renderData.GetRenderSceneBuffers(); var sceneData = ( RenderSceneDataRD ) renderData.GetRenderSceneData(); if ( sceneBuffers == null && sceneData == null ) { Error( "sceneBuffers == null && sceneData == null" ); return; } var size = sceneBuffers.GetInternalSize(); if ( size.X == 0 || size.Y == 0 ) { Warning( "InternalSize.X == 0 || InternalSize.Y == 0" ); return; } _context.SetRenderData( renderData, sceneBuffers, sceneData ); _context.SetView( -1 ); _context.SetGroups( new Vector3I( 1, 1, 1 ) ); _hasContext = true; var groups = ComputeGroups(); _context.SetGroups( groups ); ForAllViews(); int viewCount = ( int ) sceneBuffers.GetViewCount(); for ( int i = 0; i < viewCount; i++ ) { _context.SetView( i ); RenderView(); } _hasContext = false; } protected virtual Vector3I ComputeGroups() { var size = context.sceneBuffers.GetInternalSize(); var xGroups = Mathf.CeilToInt( size.X / (float) _groupSize ); var yGroups = Mathf.CeilToInt( size.Y / (float) _groupSize ); return new Vector3I( xGroups, yGroups, 1 ); } public override void _Notification( int what ) { var _shader = context.shader; Verbose( "Got notification: ", what ); if ( what != NotificationPredelete || ( _shader == null || !_shader.valid ) || rd == null ) { Verbose( "what != NotificationPredelete", what != NotificationPredelete, "( _shader == null || !_shader.valid )", ( _shader == null || !_shader.valid ), "rd == null", rd == null ); return; } CleanUp( _shader, "Shader" ); var index = 0; _cleanUps.ForEach( c => { CleanUp( c, "_cleanUps[" + index + "]"); index ++; } ); _cleanUps.Clear(); } public void AddToCleanUp( RenderingObject ro, string info = null ) { var _shader = context.shader; if ( _cleanUps.Contains( ro ) || _shader == ro ) { return; } _cleanUps.Add( ro ); _cleanUpInfo.Add( info ); } public void AddToCleanUp( List ro, string info = null ) { var index = 0; info = info == null ? "" : info; ro.ForEach( r => { AddToCleanUp( r, info + "["+ index + "]" ); index ++; } ); } void CleanUp( RenderingObject ro, string info ) { if ( ro == null ) { Warning( "ro == null, couldn't clean up: ", info ); return; } Verbose( "Cleaning up: ", info, ro.rid ); rd.FreeRid( ro.rid ); } // --------------------------------------------- // --------------------------------------------- // CONVINIENCE // --------------------------------------------- // --------------------------------------------- public RDSampler Sampler( RDSamplerState state = null) { if ( state == null ) { state = new RDSamplerState(); state.MinFilter = RenderingDevice.SamplerFilter.Linear; state.MagFilter = RenderingDevice.SamplerFilter.Linear; state.RepeatU = RenderingDevice.SamplerRepeatMode.Repeat; state.RepeatV = RenderingDevice.SamplerRepeatMode.Repeat; } var sampler = RDSampler.Create( this, state ); return sampler; } public RDSampler Sampler( RenderingDevice.SamplerFilter filter, RenderingDevice.SamplerRepeatMode repeatMode) { var state = new RDSamplerState(); state.MinFilter = filter; state.MagFilter = filter; state.RepeatU = repeatMode; state.RepeatV = repeatMode; return Sampler( state ); } // --------------------------------------------- // --------------------------------------------- // MESSAGES // --------------------------------------------- // --------------------------------------------- public void Error( params object[] messages ) { var message = RJLog.GetLogString( messages ); Messages.Error( _messages, message ); if ( logMessages ) { this.LogError( message ); } } public void Warning( params object[] messages ) { var message = RJLog.GetLogString( messages ); Messages.Warning( _messages, message ); if ( logMessages && Messages.GetLevel( MessageType.Warning ) >= messageLogLevel ) { this.LogInfo( message ); } } public void Info( params object[] messages ) { var message = RJLog.GetLogString( messages ); Messages.Info( _messages, message ); if ( logMessages && Messages.GetLevel( MessageType.Info ) >= messageLogLevel ) { this.LogInfo( message ); } } public void Verbose( params object[] messages ) { var message = RJLog.GetLogString( messages ); Messages.Verbose( _messages, message ); if ( logMessages && Messages.GetLevel( MessageType.Verbose ) >= messageLogLevel ) { this.LogInfo( message ); } } } }