Lexing/Cameras
This commit is contained in:
parent
e88bfc81af
commit
273f1caa35
|
@ -0,0 +1,11 @@
|
|||
using Godot;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public class SceneFileHeader
|
||||
{
|
||||
public string type;
|
||||
public List<SceneFileNamedValue> attributes = new List<SceneFileNamedValue>();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
using Godot;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public class SceneFileHeaderAttribute
|
||||
{
|
||||
protected string _attributeName;
|
||||
|
||||
public static SceneFileHeaderAttribute Create( string value )
|
||||
{
|
||||
var an = new SceneFileHeaderAttribute();
|
||||
an._attributeName = value;
|
||||
|
||||
return an;
|
||||
}
|
||||
|
||||
public SceneFileNamedValue GetAttribute( SceneFileHeader header )
|
||||
{
|
||||
return header.attributes.Find( a => a.name == _attributeName );
|
||||
}
|
||||
|
||||
public string Get( SceneFileHeader header, string alternative = null )
|
||||
{
|
||||
var attribute = GetAttribute( header );
|
||||
|
||||
if ( attribute == null )
|
||||
{
|
||||
return alternative;
|
||||
}
|
||||
|
||||
return attribute.value.Substring( 1, attribute.value.Length - 2 );
|
||||
}
|
||||
|
||||
public double GetNumberValue( SceneFileHeader header, double alternative = 0 )
|
||||
{
|
||||
var attribute = GetAttribute( header );
|
||||
|
||||
if ( attribute == null )
|
||||
{
|
||||
return alternative;
|
||||
}
|
||||
|
||||
return RegexUtility.ParseDouble( attribute.value );
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public class SceneFileHeaderAttributeValue:SceneFileHeaderAttribute
|
||||
{
|
||||
public virtual void GetValue( SceneFileHeader header )
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class SceneFileHeaderAttributeValue<T>:SceneFileHeaderAttributeValue
|
||||
{
|
||||
T _value;
|
||||
|
||||
public T value => _value;
|
||||
|
||||
Func<SceneFileHeaderAttribute,SceneFileHeader,T> _getter;
|
||||
|
||||
public SceneFileHeaderAttributeValue( string name, Func<SceneFileHeaderAttribute,SceneFileHeader,T> getter )
|
||||
{
|
||||
_attributeName = name;
|
||||
_getter = getter;
|
||||
}
|
||||
|
||||
public override void GetValue( SceneFileHeader header )
|
||||
{
|
||||
_value = _getter( this, header );
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public class SFHStringAttribute:SceneFileHeaderAttributeValue<string>
|
||||
{
|
||||
public SFHStringAttribute( string name )
|
||||
:base( name, ( att, entry ) => att.Get( entry ) )
|
||||
{}
|
||||
|
||||
}
|
||||
|
||||
public class SFHNumberAttribute:SceneFileHeaderAttributeValue<double>
|
||||
{
|
||||
public SFHNumberAttribute( string name )
|
||||
:base( name, ( att, entry ) => att.GetNumberValue( entry ) )
|
||||
{}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
using Godot;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public class EditableSFO:SceneFileObject
|
||||
{
|
||||
public static readonly string headerType = "editable";
|
||||
|
||||
public readonly SFHStringAttribute path = new SFHStringAttribute( "path" );
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
using Godot;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public class ExtResourceSFO:SceneFileObject
|
||||
{
|
||||
public static readonly string headerType = "ext_resource";
|
||||
|
||||
public readonly SFHStringAttribute path = new SFHStringAttribute( "path" );
|
||||
public readonly SFHStringAttribute uid = new SFHStringAttribute( "uid" );
|
||||
public readonly SFHStringAttribute type = new SFHStringAttribute( "type" );
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
using Godot;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public class GDSceneSFO:SceneFileObject
|
||||
{
|
||||
public static readonly string headerType = "gd_scene";
|
||||
|
||||
public readonly SFHNumberAttribute loadSteps = new SFHNumberAttribute( "loadSteps" );
|
||||
public readonly SFHNumberAttribute format = new SFHNumberAttribute( "format" );
|
||||
public readonly SFHStringAttribute uid = new SFHStringAttribute( "uid" );
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
using Godot;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public class NodeSFO:SceneFileObject
|
||||
{
|
||||
public static readonly string headerType = "node";
|
||||
|
||||
|
||||
protected NodeSFO _parentObject;
|
||||
public readonly SFHStringAttribute name = new SFHStringAttribute( "name" );
|
||||
public readonly SFHStringAttribute parent = new SFHStringAttribute( "parent" );
|
||||
public readonly SFHStringAttribute type = new SFHStringAttribute( "type" );
|
||||
protected string _elementPath;
|
||||
public string elementPath => _elementPath;
|
||||
|
||||
|
||||
protected override void _CreateFromHeaderEntry( SceneFileEntry headerEntry )
|
||||
{
|
||||
_elementPath = name.value;
|
||||
var parentPath = parent.value;
|
||||
|
||||
if ( parentPath == null )
|
||||
{
|
||||
_elementPath = ".";
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( parentPath != "." )
|
||||
{
|
||||
_elementPath = parentPath + "/" + name.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ResolveParent( Dictionary<string,NodeSFO> nodeMap, NodeSFO rootNode )
|
||||
{
|
||||
var parentPath = parent.value;
|
||||
|
||||
if ( parentPath == "." )
|
||||
{
|
||||
_parentObject = rootNode;
|
||||
return;
|
||||
}
|
||||
|
||||
if ( parentPath != "." && parentPath != null )
|
||||
{
|
||||
if ( nodeMap.ContainsKey( parentPath ) )
|
||||
{
|
||||
_parentObject = nodeMap[ parentPath ];
|
||||
}
|
||||
else
|
||||
{
|
||||
RJLog.Log( "Parent not found:", name.value, parentPath, elementPath );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
using Godot;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public class SceneFileObject
|
||||
{
|
||||
protected SceneFileEntry _headerEntry;
|
||||
protected List<SceneFileHeaderAttributeValue> _attributes = new List<SceneFileHeaderAttributeValue>();
|
||||
|
||||
public SceneFileObject()
|
||||
{
|
||||
SetAttributes();
|
||||
}
|
||||
|
||||
public void CreateFromHeaderEntry( SceneFileEntry headerEntry )
|
||||
{
|
||||
ReadAttributes( headerEntry.header );
|
||||
|
||||
_CreateFromHeaderEntry( headerEntry);
|
||||
}
|
||||
|
||||
protected virtual void _CreateFromHeaderEntry( SceneFileEntry headerEntry )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected virtual void SetAttributes()
|
||||
{
|
||||
_attributes = ReflectionHelper.GetFieldsOfType<SceneFileHeaderAttributeValue>( this );
|
||||
}
|
||||
|
||||
protected void ReadAttributes( SceneFileHeader entry )
|
||||
{
|
||||
_attributes.ForEach( a => a.GetValue( entry ) );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
using Godot;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public class SceneFileObjectFactory
|
||||
{
|
||||
static Dictionary<string,Func<SceneFileObject>> factory =
|
||||
new Dictionary<string,Func<SceneFileObject>>()
|
||||
{
|
||||
{ GDSceneSFO.headerType, () => new GDSceneSFO() },
|
||||
{ ExtResourceSFO.headerType, () => new ExtResourceSFO() },
|
||||
{ SubResourceSFO.headerType, () => new SubResourceSFO() },
|
||||
{ NodeSFO.headerType, () => new NodeSFO() },
|
||||
{ EditableSFO.headerType, () => new EditableSFO() }
|
||||
};
|
||||
|
||||
public static SceneFileObject Create( SceneFileEntry entry )
|
||||
{
|
||||
if ( entry.header == null )
|
||||
{
|
||||
RJLog.Log( "Has no header >>", entry.line );
|
||||
return null;
|
||||
}
|
||||
|
||||
foreach ( var vk in factory )
|
||||
{
|
||||
if ( entry.IsHeaderType( vk.Key ) )
|
||||
{
|
||||
var sfo = vk.Value();
|
||||
sfo.CreateFromHeaderEntry( entry );
|
||||
|
||||
return sfo;
|
||||
}
|
||||
}
|
||||
|
||||
RJLog.Log( "Unknown header type >> ", entry.header.type, ":", entry.line );
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
using Godot;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public class SubResourceSFO:SceneFileObject
|
||||
{
|
||||
public static readonly string headerType = "sub_resource";
|
||||
|
||||
public readonly SFHStringAttribute id = new SFHStringAttribute( "uid" );
|
||||
public readonly SFHStringAttribute type = new SFHStringAttribute( "type" );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,147 @@
|
|||
using Godot;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public class SceneFileHeaderParser
|
||||
{
|
||||
public bool hasError = true;
|
||||
public string errorMessage;
|
||||
string line;
|
||||
|
||||
public void Parse( SceneFileEntry entry )
|
||||
{
|
||||
|
||||
line = entry.line.Substring( 1, entry.line.Length - 2 );
|
||||
|
||||
var lexer = new SceneFileLexer();
|
||||
var tokens = lexer.LexToList( line );
|
||||
|
||||
if ( lexer.hasError || tokens.Count == 0)
|
||||
{
|
||||
errorMessage = "Lexing failed";
|
||||
return;
|
||||
}
|
||||
|
||||
lexer.GrabMatches( tokens, line );
|
||||
|
||||
/*var info = "";
|
||||
tokens.ForEach(
|
||||
( tk )=>
|
||||
{
|
||||
info += tk.type + " " + tk.match + "\n";
|
||||
}
|
||||
);*/
|
||||
|
||||
var offset = 0;
|
||||
var token = tokens[ 0 ];
|
||||
|
||||
if ( ! token.Is( LexerMatcherLibrary.CwordMatcher ) )
|
||||
{
|
||||
errorMessage = "First token is not a word: "+ token.type + " '" + token.match + "'";
|
||||
return;
|
||||
}
|
||||
|
||||
var header = new SceneFileHeader();
|
||||
|
||||
entry.header = header;
|
||||
|
||||
header.type = tokens[ 0 ].match;
|
||||
|
||||
offset = 1; token = tokens[ offset ];
|
||||
|
||||
while ( offset < tokens.Count && token != null )
|
||||
{
|
||||
if ( ! token.Is( LexerMatcherLibrary.WhiteSpaceMatcher ) )
|
||||
{
|
||||
errorMessage = "Expected white space, but got: " + token.type + " '" + token.match + "'";
|
||||
return;
|
||||
}
|
||||
|
||||
offset ++; token = tokens[ offset ];
|
||||
|
||||
var assignmentResult = SceneFileLexer.ReadAssignment( tokens, offset );
|
||||
|
||||
if ( assignmentResult.hasError )
|
||||
{
|
||||
errorMessage = assignmentResult.errorMessage;
|
||||
return;
|
||||
}
|
||||
|
||||
header.attributes.Add( assignmentResult.GetNamedValue() );
|
||||
|
||||
offset = assignmentResult.endOffset;
|
||||
token = tokens[ offset ];
|
||||
|
||||
|
||||
/*if ( ! token.Is( LexerMatcherLibrary.CwordMatcher ) )
|
||||
{
|
||||
errorMessage = "Expected word for attribute name, but got: " + token.type + " '" + token.match + "'";
|
||||
return;
|
||||
}
|
||||
|
||||
var attribute = new SceneFileNamedValue();
|
||||
attribute.name = token.match;
|
||||
|
||||
offset ++; token = tokens[ offset ];
|
||||
|
||||
if ( ! token.Is( LexerMatcherLibrary.OperatorMatcher, "=" ) )
|
||||
{
|
||||
errorMessage = "Expected assignment operator, but got:" + token.type + " '" + token.match + "'";
|
||||
return;
|
||||
}
|
||||
|
||||
offset ++; token = tokens[ offset ];
|
||||
|
||||
if ( token.Is( LexerMatcherLibrary.NumberMatcher ) )
|
||||
{
|
||||
attribute.value = token.match;
|
||||
header.attributes.Add( attribute );
|
||||
|
||||
}
|
||||
else if ( token.Is( LexerMatcherLibrary.DoubleQuotedStringMatcher ) )
|
||||
{
|
||||
attribute.value = token.match;
|
||||
header.attributes.Add( attribute );
|
||||
}
|
||||
else if ( token.Is( LexerMatcherLibrary.CFunctionMatcher ) )
|
||||
{
|
||||
var closer = LexerEvent.FindClosingBracket( tokens, offset + 1 );
|
||||
|
||||
if ( closer.type != LexerEvent.FindResultType.Found )
|
||||
{
|
||||
errorMessage = "Function with unmatched brackets: " + token.type + " '" + token.match + "'";
|
||||
return;
|
||||
}
|
||||
|
||||
for ( int i = offset; i <= closer.index; i++ )
|
||||
{
|
||||
attribute.value += tokens[ i ].match;
|
||||
}
|
||||
|
||||
offset = closer.index + 1;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
errorMessage = "Unexpected token:" + token.type + " '" + token.match + "'";
|
||||
return;
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
offset ++;
|
||||
|
||||
token = ( offset < tokens.Count - 1 ) ? tokens[ offset ] : null ;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
//RJLog.Log( info );
|
||||
|
||||
hasError = false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,129 @@
|
|||
using Godot;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public class SceneFileLexer:Lexer
|
||||
{
|
||||
public SceneFileLexer()
|
||||
{
|
||||
AddAllMatchers(
|
||||
LexerMatcherLibrary.DoubleQuotedStringMatcher,
|
||||
LexerMatcherLibrary.NumberMatcher,
|
||||
LexerMatcherLibrary.NullMatcher,
|
||||
LexerMatcherLibrary.BoolMatcher,
|
||||
LexerMatcherLibrary.BreakMatcher,
|
||||
LexerMatcherLibrary.WhiteSpaceMatcher,
|
||||
LexerMatcherLibrary.BracketMatcher,
|
||||
LexerMatcherLibrary.OperatorMatcher,
|
||||
LexerMatcherLibrary.CFunctionMatcher,
|
||||
LexerMatcherLibrary.CwordMatcher,
|
||||
LexerMatcherLibrary.AnySymbolMatcher
|
||||
);
|
||||
}
|
||||
|
||||
public class SceneFileAssignmentResult
|
||||
{
|
||||
public bool hasError = true;
|
||||
public string errorMessage = "";
|
||||
|
||||
public string name;
|
||||
public string value;
|
||||
|
||||
public SceneFileNamedValue GetNamedValue()
|
||||
{
|
||||
return SceneFileNamedValue.Create( name, value );
|
||||
}
|
||||
|
||||
public int startOffset;
|
||||
public int endOffset;
|
||||
|
||||
public static SceneFileAssignmentResult Create( int startOffset )
|
||||
{
|
||||
var r = new SceneFileAssignmentResult();
|
||||
|
||||
r.startOffset = startOffset;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
public SceneFileAssignmentResult AsError( int offset, LexerEvent le, string message )
|
||||
{
|
||||
hasError = true;
|
||||
endOffset = offset;
|
||||
errorMessage = message + " Token: " + le.type + "'" + le.match + "'" ;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public SceneFileAssignmentResult AsValue( int offset, LexerEvent le )
|
||||
{
|
||||
hasError = false;
|
||||
endOffset = offset;
|
||||
value = le.match;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public SceneFileAssignmentResult AsValue( int offset, string value )
|
||||
{
|
||||
hasError = false;
|
||||
endOffset = offset;
|
||||
this.value = value;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static SceneFileAssignmentResult ReadAssignment( List<LexerEvent> tokens, int offset )
|
||||
{
|
||||
var result = SceneFileAssignmentResult.Create( offset );
|
||||
var token = tokens[ offset ];
|
||||
|
||||
if ( ! token.Is( LexerMatcherLibrary.CwordMatcher ) )
|
||||
{
|
||||
return result.AsError( offset, token, "Expected a word as name." ) ;
|
||||
}
|
||||
|
||||
result.name = token.match;
|
||||
|
||||
offset ++; token = tokens[ offset ];
|
||||
|
||||
if ( ! token.Is( LexerMatcherLibrary.OperatorMatcher, "=" ) )
|
||||
{
|
||||
return result.AsError( offset, token, "Expected assignment operator." ) ;
|
||||
}
|
||||
|
||||
offset ++; token = tokens[ offset ];
|
||||
|
||||
if ( token.Is( LexerMatcherLibrary.NumberMatcher ) ||
|
||||
token.Is( LexerMatcherLibrary.DoubleQuotedStringMatcher )
|
||||
)
|
||||
{
|
||||
return result.AsValue( offset, token );
|
||||
}
|
||||
else if ( token.Is( LexerMatcherLibrary.CFunctionMatcher ) )
|
||||
{
|
||||
var start = offset + 1;
|
||||
var closer = LexerEvent.FindClosingBracket( tokens, offset + 1 );
|
||||
|
||||
if ( closer.type != LexerEvent.FindResultType.Found )
|
||||
{
|
||||
return result.AsError( offset, token, "Unmatched brackets.");
|
||||
}
|
||||
|
||||
var length = ( closer.index - start ) + 1;
|
||||
|
||||
var value = LexerEvent.GetMatchFromRange( tokens, start, length );
|
||||
|
||||
return result.AsValue( closer.index, value );
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
return result.AsError( offset, token, "Unexpected token.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public class GodotTextSceneLexer:Lexer
|
||||
{
|
||||
public static List<LexerEvent> Lex( string source )
|
||||
{
|
||||
var lexer = new GodotTextSceneLexer();
|
||||
var events = lexer.LexToList( source );
|
||||
|
||||
if ( lexer.hasError )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
events.ForEach( ev => { ev.GrabMatch( source ); } );
|
||||
|
||||
|
||||
return events;
|
||||
}
|
||||
|
||||
public static readonly LexerMatcher HeaderMatcher = LexerMatcher.CreateExtended(
|
||||
"Header", "\\[.+\\]"
|
||||
);
|
||||
|
||||
public static readonly LexerMatcher SeperatorMatcher = LexerMatcher.CreateExtended(
|
||||
"Seperator", "\\l\\l"
|
||||
);
|
||||
|
||||
// ((?:\w|_|\/)+) = .+?(\r\n|\r|\n)
|
||||
// ((?:\\w|_|\\/)+) = .+?(\\r\\n|\\r|\\n)
|
||||
public static readonly LexerMatcher MemberMatcher = LexerMatcher.CreateExtended(
|
||||
"Member", "(?:\\w|_|\\/)+ = .+?"
|
||||
);
|
||||
|
||||
// ".+?"\: .+?,(\r\n|\r|\n)
|
||||
// \".+?\"\\: .+?,\\l
|
||||
public static readonly LexerMatcher SubMemberMatcher = LexerMatcher.CreateExtended(
|
||||
"SubMember", "\".+?\"\\: .+?"
|
||||
);
|
||||
|
||||
public static readonly LexerMatcher SubMemberStartMatcher = LexerMatcher.CreateExtended(
|
||||
"SubMemberStart", ".+\\[\\{"
|
||||
);
|
||||
|
||||
public static readonly LexerMatcher SubMemberEndMatcher = LexerMatcher.CreateExtended(
|
||||
"SubMemberEnd", "\\}\\]"
|
||||
);
|
||||
|
||||
public GodotTextSceneLexer()
|
||||
{
|
||||
AddAllMatchers(
|
||||
GodotTextSceneLexer.HeaderMatcher,
|
||||
GodotTextSceneLexer.SeperatorMatcher,
|
||||
GodotTextSceneLexer.SubMemberStartMatcher,
|
||||
GodotTextSceneLexer.SubMemberEndMatcher,
|
||||
GodotTextSceneLexer.SubMemberMatcher,
|
||||
GodotTextSceneLexer.MemberMatcher,
|
||||
LexerMatcherLibrary.AnySymbolMatcher
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
using Godot;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public class SceneFileParser
|
||||
{
|
||||
public string source;
|
||||
public SceneFile sceneFile;
|
||||
|
||||
public void Parse( string source )
|
||||
{
|
||||
this.source = source;
|
||||
|
||||
var lines = RegexUtility.SplitLines( source );
|
||||
var lexer = new GodotTextSceneLexer();
|
||||
|
||||
var lineIndex = 1;
|
||||
|
||||
sceneFile = new SceneFile();
|
||||
|
||||
lines.ForEach(
|
||||
( ln )=>
|
||||
{
|
||||
var matcher = lexer.GetMatcher( ln );
|
||||
|
||||
if ( matcher == null )
|
||||
{
|
||||
sceneFile.entries.Add( SceneFile.Seperator() );
|
||||
}
|
||||
else
|
||||
{
|
||||
var linePreview = ln;
|
||||
sceneFile.entries.Add( SceneFile.Create( matcher.type, ln ) );
|
||||
}
|
||||
|
||||
|
||||
lineIndex ++;
|
||||
}
|
||||
);
|
||||
|
||||
sceneFile.CreateObjects();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
using Godot;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public class SceneFile
|
||||
{
|
||||
public static SceneFileEntry Create( string type, string line )
|
||||
{
|
||||
var entry = new SceneFileEntry();
|
||||
entry.type = type;
|
||||
entry.line = line;
|
||||
|
||||
entry.Parse();
|
||||
return entry;
|
||||
}
|
||||
|
||||
public static SceneFileEntry Seperator()
|
||||
{
|
||||
return Create( GodotTextSceneLexer.SeperatorMatcher.type, "" );
|
||||
}
|
||||
|
||||
public List<SceneFileEntry> entries = new List<SceneFileEntry>();
|
||||
public List<SceneFileObject> objects = new List<SceneFileObject>();
|
||||
|
||||
public GDSceneSFO gdScene;
|
||||
public NodeSFO rootNode;
|
||||
public List<NodeSFO> nodes = new List<NodeSFO>();
|
||||
public Dictionary<string,NodeSFO> nodeMap = new Dictionary<string, NodeSFO>();
|
||||
public List<ExtResourceSFO> extResources = new List<ExtResourceSFO>();
|
||||
public List<SubResourceSFO> subResourceSFOs = new List<SubResourceSFO>();
|
||||
|
||||
public SceneFile GetSerializableJSONVersion()
|
||||
{
|
||||
var file = new SceneFile();
|
||||
file.entries = entries;
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
public void CreateObjects()
|
||||
{
|
||||
entries.ForEach(
|
||||
( e )=>
|
||||
{
|
||||
if ( ! e.hasHeader )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var sfo = SceneFileObjectFactory.Create( e );
|
||||
|
||||
if ( sfo == null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( sfo is GDSceneSFO )
|
||||
{
|
||||
gdScene = (GDSceneSFO) sfo;
|
||||
}
|
||||
else if ( sfo is NodeSFO )
|
||||
{
|
||||
var node = (NodeSFO) sfo;
|
||||
nodes.Add( node );
|
||||
|
||||
if ( node.elementPath == "." )
|
||||
{
|
||||
rootNode = node;
|
||||
}
|
||||
|
||||
nodeMap[ node.elementPath ] = node;
|
||||
|
||||
// RJLog.Log( "'" + node.elementPath + "'", node.name.value );
|
||||
|
||||
}
|
||||
else if ( sfo is ExtResourceSFO )
|
||||
{
|
||||
extResources.Add( (ExtResourceSFO) sfo );
|
||||
}
|
||||
else if ( sfo is SubResourceSFO )
|
||||
{
|
||||
subResourceSFOs.Add( (SubResourceSFO) sfo );
|
||||
}
|
||||
|
||||
objects.Add( sfo );
|
||||
}
|
||||
);
|
||||
|
||||
nodes.ForEach(
|
||||
( n )=>
|
||||
{
|
||||
n.ResolveParent( nodeMap, rootNode );
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
using Godot;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public class SceneFileEntry
|
||||
{
|
||||
public string type;
|
||||
public string line;
|
||||
public SceneFileHeader header;
|
||||
public SceneFileNamedValue member;
|
||||
public SceneFileNamedValue subMember;
|
||||
public bool hasError = false;
|
||||
|
||||
|
||||
public bool hasHeader => header != null;
|
||||
|
||||
public bool IsHeaderType( string type )
|
||||
{
|
||||
return header != null && header.type == type;
|
||||
}
|
||||
|
||||
public void Parse()
|
||||
{
|
||||
if ( type == GodotTextSceneLexer.HeaderMatcher.type )
|
||||
{
|
||||
var headerParser = new SceneFileHeaderParser();
|
||||
headerParser.Parse( this );
|
||||
|
||||
if ( headerParser.hasError )
|
||||
{
|
||||
hasError = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
using Godot;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public class SceneFileNamedValue
|
||||
{
|
||||
public string name;
|
||||
public string value;
|
||||
|
||||
public static SceneFileNamedValue Create( string name, string value )
|
||||
{
|
||||
var nv = new SceneFileNamedValue();
|
||||
nv.name = name;
|
||||
nv.value = value;
|
||||
return nv;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,219 @@
|
|||
using Godot;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
[Tool]
|
||||
[GlobalClass]
|
||||
public partial class SceneFileReader:Node
|
||||
{
|
||||
[Export]
|
||||
public string path = "";
|
||||
|
||||
[Export]
|
||||
public bool load = false;
|
||||
|
||||
[Export]
|
||||
public bool exportJSON = false;
|
||||
|
||||
[Export]
|
||||
public bool exportHTML = false;
|
||||
|
||||
|
||||
public override void _Process( double delta )
|
||||
{
|
||||
LoadScene();
|
||||
}
|
||||
|
||||
void LoadScene()
|
||||
{
|
||||
if ( ! load )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
load = false;
|
||||
|
||||
var text = FilesSync.LoadUTF8( path );
|
||||
|
||||
var parser = new SceneFileParser();
|
||||
|
||||
parser.Parse( text );
|
||||
|
||||
if ( exportJSON )
|
||||
{
|
||||
FilesSync.SaveJSON( path + ".json", parser.sceneFile.GetSerializableJSONVersion() );
|
||||
}
|
||||
|
||||
if ( exportHTML )
|
||||
{
|
||||
var nodes = parser.sceneFile.nodes;
|
||||
RJLog.Log( "Nodes:", nodes.Count );
|
||||
|
||||
var doc = new HtmlDocument();
|
||||
var html = doc.documentElement;
|
||||
var body = html.querySelector( HtmlElementNodeName.body );
|
||||
var head = html.querySelector( HtmlElementNodeName.head );
|
||||
|
||||
head.AddScript(
|
||||
@"
|
||||
|
||||
function main()
|
||||
{
|
||||
let elements = document.querySelectorAll( '.closeable' );
|
||||
|
||||
for ( let i = 0; i < elements.length; i++ )
|
||||
{
|
||||
let element = elements[ i ];
|
||||
|
||||
element.addEventListener( 'click',
|
||||
( ev )=>
|
||||
{
|
||||
|
||||
let target = element.getAttribute( 'data-close-target' );
|
||||
|
||||
let targetElement = element;
|
||||
|
||||
let parentRegex = /^\.\.\s/;
|
||||
|
||||
while ( parentRegex.test( target ) )
|
||||
{
|
||||
target = target.replace( parentRegex, '' );
|
||||
targetElement = targetElement.parentElement;
|
||||
}
|
||||
|
||||
let rootRegex = /^\.\.\.\s/;
|
||||
|
||||
if ( rootRegex.test( target ) )
|
||||
{
|
||||
target = target.replace( rootRegex, '' );
|
||||
targetElement = document.documentElement;
|
||||
}
|
||||
|
||||
let closeTarget = element.parentElement.querySelector( target );
|
||||
|
||||
console.log( ev, target, closeTarget);
|
||||
closeTarget.style.display = closeTarget.style.display === 'none' ? 'block' : 'none';
|
||||
|
||||
element.setAttribute( 'data-close-state', closeTarget.style.display );
|
||||
|
||||
ev.preventDefault();
|
||||
return false;
|
||||
},
|
||||
true
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener( 'load', () => { main(); });
|
||||
|
||||
"
|
||||
);
|
||||
|
||||
head.AddStyle(
|
||||
@"
|
||||
body
|
||||
{
|
||||
overflow-x: hidden;
|
||||
margin: 2em 0em;
|
||||
font-family: Helvetica, Arial, sans;
|
||||
background: hsl(0,0%,10%);
|
||||
color: hsl(0,0%,80%)
|
||||
}
|
||||
|
||||
.closeable
|
||||
{
|
||||
cursor: pointer;
|
||||
opacity:1;
|
||||
transition: opacity 300ms ease;
|
||||
}
|
||||
|
||||
.closeable[data-close-state='none']
|
||||
{
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.node
|
||||
{
|
||||
display: block;
|
||||
position: relative;
|
||||
left: 2em;
|
||||
}
|
||||
|
||||
gd-name
|
||||
{
|
||||
border-radius: 0.5em;
|
||||
padding: 1em 1em;
|
||||
background-color: hsl(0,0%,20%);
|
||||
margin: 0.5em 1em;
|
||||
display: inline-block;
|
||||
font-weight: bold;
|
||||
|
||||
}
|
||||
|
||||
gd-type
|
||||
{
|
||||
display: inline-block;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
" );
|
||||
|
||||
|
||||
|
||||
var elementMap = new Dictionary<string,HtmlElementNode>();
|
||||
|
||||
var GD_Node = HtmlElementNodeName.CreateNodeName( "gd-node" );
|
||||
var GD_Name = HtmlElementNodeName.CreateNodeName( "gd-name" );
|
||||
var GD_Type = HtmlElementNodeName.CreateNodeName( "gd-type" );
|
||||
var GD_Children = HtmlElementNodeName.CreateNodeName( "gd-children" );
|
||||
|
||||
for ( int i = 0; i < nodes.Count; i++ )
|
||||
{
|
||||
var node = nodes[ i ];
|
||||
|
||||
//RJLog.Log( i, node.name.value );
|
||||
|
||||
var attachmentElement = body;
|
||||
|
||||
var elementPath = node.elementPath;
|
||||
|
||||
var parent = node.parent.value;
|
||||
|
||||
if ( parent != null && elementMap.ContainsKey( parent ) )
|
||||
{
|
||||
attachmentElement = elementMap[ parent ].querySelector( GD_Children );
|
||||
}
|
||||
|
||||
var nodeElement = doc.Create( GD_Node );
|
||||
|
||||
nodeElement.SetAttribute( "class", "node" );
|
||||
|
||||
var nameElement = nodeElement.AddElement( GD_Name, node.name.value );
|
||||
nameElement.SetAttribute( "class", "closeable" );
|
||||
nameElement.SetAttribute( "data-close-target", ".. " + GD_Children.selector );
|
||||
|
||||
nodeElement.AddElement( GD_Type, node.type.value );
|
||||
|
||||
nodeElement.AddElement( GD_Children );
|
||||
|
||||
|
||||
|
||||
elementMap[ elementPath ] = nodeElement;
|
||||
|
||||
// RJLog.Log( "'" + elementPath + "'", node.name.value );
|
||||
|
||||
attachmentElement.AppendChild( nodeElement );
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
FilesSync.SaveUTF8( path + ".html", new HtmlSerializer().Serialize( doc.documentElement ) );
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using System;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
|
@ -220,7 +220,7 @@ namespace Rokojori
|
|||
|
||||
if ( its > max )
|
||||
{
|
||||
throw new System.Exception();
|
||||
throw new Exception();
|
||||
}
|
||||
|
||||
node = LastChild( node );
|
||||
|
@ -240,7 +240,76 @@ namespace Rokojori
|
|||
return NextNonChild( node );
|
||||
}
|
||||
|
||||
public void Iterate( N node, System.Action<N> callback, bool childrenOnly = false )
|
||||
public int GetDepth( N node, Dictionary<N, int> depthMap = null )
|
||||
{
|
||||
if ( depthMap == null )
|
||||
{
|
||||
var depth = 0;
|
||||
var it = Parent( node );
|
||||
var maxDepth = 1000;
|
||||
|
||||
while ( it != null )
|
||||
{
|
||||
depth ++;
|
||||
|
||||
if ( depth == maxDepth )
|
||||
{
|
||||
RJLog.Log( "reached max depth", it );
|
||||
return depth;
|
||||
}
|
||||
|
||||
it = Parent( it );
|
||||
}
|
||||
|
||||
return depth;
|
||||
}
|
||||
|
||||
if ( depthMap.ContainsKey( node ) )
|
||||
{
|
||||
return depthMap[ node ];
|
||||
}
|
||||
|
||||
var parent = Parent( node );
|
||||
|
||||
if ( parent == null )
|
||||
{
|
||||
depthMap[ node ] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( depthMap.ContainsKey( parent ) )
|
||||
{
|
||||
var parentDepth = depthMap[ parent ];
|
||||
var nodeDepth = parentDepth + 1;
|
||||
|
||||
depthMap[ node ] = nodeDepth;
|
||||
|
||||
return nodeDepth;
|
||||
}
|
||||
|
||||
|
||||
depthMap[ node ] = GetDepth( node );
|
||||
|
||||
return depthMap[ node ];
|
||||
}
|
||||
|
||||
public void DepthIterate( N node, Action<N, int> callback, bool childrenOnly = false, Dictionary<N, int> depthMap = null )
|
||||
{
|
||||
if ( depthMap == null )
|
||||
{
|
||||
depthMap = new Dictionary<N, int>();
|
||||
}
|
||||
|
||||
var iterationCallback = ( N node )=>
|
||||
{
|
||||
var depth = GetDepth( node, depthMap );
|
||||
callback( node, depth );
|
||||
};
|
||||
|
||||
Iterate( node, iterationCallback, childrenOnly );
|
||||
}
|
||||
|
||||
public void Iterate( N node, Action<N> callback, bool childrenOnly = false )
|
||||
{
|
||||
var end = IterationEndOf( node );
|
||||
var it = node;
|
||||
|
@ -257,7 +326,7 @@ namespace Rokojori
|
|||
}
|
||||
}
|
||||
|
||||
public N Find( N node, System.Predicate<N> predicate, bool childrenOnly )
|
||||
public N Find( N node, Predicate<N> predicate, bool childrenOnly )
|
||||
{
|
||||
var end = IterationEndOf( node );
|
||||
var it = node;
|
||||
|
@ -280,9 +349,9 @@ namespace Rokojori
|
|||
return null;
|
||||
}
|
||||
|
||||
public void Filter( List<N> list, N node, System.Predicate<N> predicate, bool childrenOnly )
|
||||
public void Filter( List<N> list, N node, Predicate<N> predicate, bool childrenOnly )
|
||||
{
|
||||
System.Action<N> addToList = ( N n ) =>
|
||||
Action<N> addToList = ( N n ) =>
|
||||
{
|
||||
if ( predicate( n ) )
|
||||
{
|
||||
|
@ -293,9 +362,9 @@ namespace Rokojori
|
|||
Iterate( node, addToList, childrenOnly );
|
||||
}
|
||||
|
||||
public void FilterAndMap<U>( List<U> list, N node, System.Predicate<N> predicate, System.Func<N,U> mapper, bool childrenOnly )
|
||||
public void FilterAndMap<U>( List<U> list, N node, Predicate<N> predicate, Func<N,U> mapper, bool childrenOnly )
|
||||
{
|
||||
System.Action<N> addToList = ( N n ) =>
|
||||
Action<N> addToList = ( N n ) =>
|
||||
{
|
||||
if ( predicate( n ) )
|
||||
{
|
||||
|
@ -306,9 +375,9 @@ namespace Rokojori
|
|||
Iterate( node, addToList, childrenOnly );
|
||||
}
|
||||
|
||||
public void Map<U>( List<U> list, N node, System.Predicate<N> predicate, System.Func<N,U> mapper, bool childrenOnly )
|
||||
public void Map<U>( List<U> list, N node, Predicate<N> predicate, Func<N,U> mapper, bool childrenOnly )
|
||||
{
|
||||
System.Action<N> addToList = ( N n ) =>
|
||||
Action<N> addToList = ( N n ) =>
|
||||
{
|
||||
list.Add( mapper( n ) );
|
||||
};
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public class HtmlAttributeNode:HtmlNode
|
||||
{
|
||||
public HtmlAttributeNode( HtmlDocument document, HtmlElementNode parent, string name, string value ):base( document, HtmlNode.NodeType.Attribute )
|
||||
{
|
||||
_name = name;
|
||||
_value = value;
|
||||
_parent = parent;
|
||||
}
|
||||
|
||||
HtmlElementNode _parent;
|
||||
string _name;
|
||||
string _value;
|
||||
|
||||
public string name => _name;
|
||||
public string value => _value;
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public class HtmlDocument
|
||||
{
|
||||
HtmlElementNode _documentElement;
|
||||
public HtmlElementNode documentElement => _documentElement;
|
||||
|
||||
public HtmlDocument( bool addHeadAndBody = true )
|
||||
{
|
||||
_documentElement = HtmlElementNodeName.html.Create( this );
|
||||
|
||||
if ( addHeadAndBody )
|
||||
{
|
||||
_documentElement.AppendChild( HtmlElementNodeName.head.Create( this ) );
|
||||
_documentElement.AppendChild( HtmlElementNodeName.body.Create( this ) );
|
||||
}
|
||||
}
|
||||
|
||||
public HtmlElementNode Create( HtmlElementNodeName nodeName, string text = null )
|
||||
{
|
||||
var element = nodeName.Create( this );
|
||||
|
||||
if ( text != null )
|
||||
{
|
||||
element.AddText( text );
|
||||
}
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
public HtmlTextNode CreateText( string text )
|
||||
{
|
||||
return new HtmlTextNode( this, text );
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,140 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public class HtmlElementNode:HtmlNode
|
||||
{
|
||||
public HtmlElementNode( HtmlDocument document, string nodeName ):base( document, HtmlNode.NodeType.Element )
|
||||
{
|
||||
_nodeName = nodeName;
|
||||
}
|
||||
|
||||
string _nodeName;
|
||||
public string nodeName => _nodeName;
|
||||
|
||||
List<HtmlNode> _children = new List<HtmlNode>();
|
||||
public int numChildren => _children.Count;
|
||||
|
||||
public HtmlNode GetChildAt( int index )
|
||||
{
|
||||
return _children[ index ];
|
||||
}
|
||||
|
||||
public bool HasOnlyTextNodes()
|
||||
{
|
||||
for ( int i = 0; i < _children.Count; i++ )
|
||||
{
|
||||
if ( _children[ i ].nodeType != NodeType.Text )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return _children.Count > 0;
|
||||
}
|
||||
|
||||
public void RemoveChild( HtmlNode node )
|
||||
{
|
||||
var childIndex = _children.IndexOf( node );
|
||||
|
||||
if ( childIndex == -1 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
node._SetParent( null );
|
||||
_children.RemoveAt( childIndex );
|
||||
}
|
||||
|
||||
public void AppendChild( HtmlNode node )
|
||||
{
|
||||
if ( node.parentNode == this )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( node.parentNode != null )
|
||||
{
|
||||
var element = node.parentNode as HtmlElementNode;
|
||||
element.RemoveChild( node );
|
||||
}
|
||||
|
||||
_children.Add( node );
|
||||
|
||||
node._SetParent( this );
|
||||
|
||||
}
|
||||
|
||||
public HtmlTextNode AddText( string text )
|
||||
{
|
||||
var textNode = document.CreateText( text );
|
||||
AppendChild( textNode );
|
||||
|
||||
return textNode;
|
||||
}
|
||||
|
||||
public HtmlElementNode AddScript( string script )
|
||||
{
|
||||
return AddElement( HtmlElementNodeName.script, script );
|
||||
}
|
||||
|
||||
public HtmlElementNode AddStyle( string style )
|
||||
{
|
||||
return AddElement( HtmlElementNodeName.style, style );
|
||||
}
|
||||
|
||||
public HtmlElementNode AddElement( HtmlElementNodeName name, string text = null )
|
||||
{
|
||||
var en = document.Create( name, text );
|
||||
AppendChild( en );
|
||||
return en;
|
||||
}
|
||||
|
||||
public void SetAttribute( string name, string value )
|
||||
{
|
||||
var att = new HtmlAttributeNode( document, this, name, value );
|
||||
_attributes.Add( att );
|
||||
}
|
||||
|
||||
|
||||
List<HtmlAttributeNode> _attributes = new List<HtmlAttributeNode>();
|
||||
|
||||
public int numAttributes => _attributes.Count;
|
||||
|
||||
public HtmlAttributeNode GetAttributeAt( int index )
|
||||
{
|
||||
return _attributes[ index ];
|
||||
}
|
||||
|
||||
public HtmlElementNode querySelector( string selector )
|
||||
{
|
||||
var nodeName = HtmlElementNodeName.CreateNodeName( selector );
|
||||
|
||||
return querySelector( nodeName );
|
||||
}
|
||||
|
||||
public HtmlElementNode querySelector( HtmlElementSelector selector )
|
||||
{
|
||||
|
||||
var element = HtmlWalker.instance.Find( this,
|
||||
n =>
|
||||
{
|
||||
var element = n as HtmlElementNode;
|
||||
|
||||
if ( element == null )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return selector.Selects( element );
|
||||
},
|
||||
|
||||
false
|
||||
);
|
||||
|
||||
return element == null ? null : ( element as HtmlElementNode );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public class HtmlElementNodeName:HtmlElementSelector
|
||||
{
|
||||
public static readonly HtmlElementNodeName html = CreateNodeName( "html" );
|
||||
public static readonly HtmlElementNodeName head = CreateNodeName( "head" );
|
||||
public static readonly HtmlElementNodeName body = CreateNodeName( "body" );
|
||||
public static readonly HtmlElementNodeName br = CreateNodeName( "br" );
|
||||
public static readonly HtmlElementNodeName a = CreateNodeName( "a" );
|
||||
public static readonly HtmlElementNodeName style = CreateNodeName( "style" );
|
||||
public static readonly HtmlElementNodeName script = CreateNodeName( "script" );
|
||||
|
||||
string _nodeName;
|
||||
|
||||
public string selector => _nodeName;
|
||||
|
||||
public static HtmlElementNodeName CreateNodeName( string type )
|
||||
{
|
||||
var elementNodeType = new HtmlElementNodeName();
|
||||
elementNodeType._nodeName = type;
|
||||
|
||||
return elementNodeType;
|
||||
}
|
||||
|
||||
public HtmlElementNode Create( HtmlDocument document )
|
||||
{
|
||||
return new HtmlElementNode( document, _nodeName );
|
||||
}
|
||||
|
||||
public bool Selects( HtmlElementNode elementNode )
|
||||
{
|
||||
return elementNode.nodeName == _nodeName;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Text;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public interface HtmlElementSelector
|
||||
{
|
||||
bool Selects( HtmlElementNode elementNode );
|
||||
|
||||
string selector { get; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public abstract class HtmlNode
|
||||
{
|
||||
public enum NodeType
|
||||
{
|
||||
Element = 1,
|
||||
Attribute = 2,
|
||||
Text = 3,
|
||||
CDataSection = 4,
|
||||
ProcessingInstruction = 7,
|
||||
Comment = 8,
|
||||
Document = 9,
|
||||
DocumentType = 10,
|
||||
DocumentFragment = 11
|
||||
}
|
||||
|
||||
NodeType _nodeType;
|
||||
public NodeType nodeType => _nodeType;
|
||||
|
||||
HtmlDocument _document;
|
||||
public HtmlDocument document => _document;
|
||||
|
||||
protected HtmlNode _parentNode;
|
||||
public HtmlNode parentNode => _parentNode;
|
||||
public HtmlElementNode parentElement => _parentNode as HtmlElementNode;
|
||||
public void _SetParent( HtmlNode node )
|
||||
{
|
||||
_parentNode = node;
|
||||
}
|
||||
|
||||
public virtual string nodeValue => null;
|
||||
public virtual string textContent => "";
|
||||
|
||||
public HtmlNode( HtmlDocument document, NodeType type )
|
||||
{
|
||||
_document = document;
|
||||
_nodeType = type;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,174 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Text;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public class HtmlSerializer
|
||||
{
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
HtmlWalker walker = new HtmlWalker();
|
||||
string indent = " ";
|
||||
Dictionary<HtmlNode, int> depthMap = new Dictionary<HtmlNode, int>();
|
||||
Dictionary<int, string> indentMap = new Dictionary<int, string>();
|
||||
List<HtmlElementNode> stack = new List<HtmlElementNode>();
|
||||
|
||||
|
||||
public static string Escape( string rawText )
|
||||
{
|
||||
rawText = RegexUtility.Replace( rawText, "&", "&" );
|
||||
rawText = RegexUtility.Replace( rawText, "<", "<" );
|
||||
rawText = RegexUtility.Replace( rawText, ">", ">" );
|
||||
rawText = RegexUtility.Replace( rawText, "\'", "'" );
|
||||
rawText = RegexUtility.Replace( rawText, "\"", """ );
|
||||
|
||||
return rawText;
|
||||
}
|
||||
|
||||
public string Serialize( HtmlNode node )
|
||||
{
|
||||
|
||||
sb.Append( "<!DOCTYPE html>" );
|
||||
walker.DepthIterate( node,
|
||||
|
||||
( n, d ) =>
|
||||
{
|
||||
var depth = GetDepth( n );
|
||||
ClosePreviousElements( depth );
|
||||
|
||||
var element = n as HtmlElementNode;
|
||||
|
||||
if ( element != null )
|
||||
{
|
||||
sb.Append( "\n" );
|
||||
sb.Append( GetIndent( depth ) );
|
||||
|
||||
sb.Append( "<" + element.nodeName );
|
||||
|
||||
for ( int i = 0; i < element.numAttributes; i++ )
|
||||
{
|
||||
var attribute = element.GetAttributeAt( i );
|
||||
|
||||
sb.Append( " " );
|
||||
sb.Append( attribute.name );
|
||||
sb.Append( "=\"" );
|
||||
sb.Append( Escape( attribute.value ) );
|
||||
sb.Append( "\"");
|
||||
}
|
||||
|
||||
sb.Append( ">" );
|
||||
|
||||
stack.Add( element );
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if (
|
||||
HtmlElementNodeName.style.Selects( n.parentElement ) ||
|
||||
HtmlElementNodeName.script.Selects( n.parentElement )
|
||||
)
|
||||
{
|
||||
sb.Append( n.nodeValue );
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.Append( Escape( n.nodeValue ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
},
|
||||
|
||||
false,
|
||||
depthMap
|
||||
);
|
||||
|
||||
ClosePreviousElements( -1 );
|
||||
|
||||
return sb.ToString();
|
||||
|
||||
}
|
||||
|
||||
string GetIndent( int depth )
|
||||
{
|
||||
|
||||
if ( indentMap.ContainsKey( depth ) )
|
||||
{
|
||||
return indentMap[ depth ];
|
||||
}
|
||||
|
||||
if ( depth == 0 )
|
||||
{
|
||||
indentMap[ 0 ] = "";
|
||||
return "";
|
||||
}
|
||||
|
||||
if ( indentMap.ContainsKey( depth - 1 ) )
|
||||
{
|
||||
var smallerIndent = indentMap[ depth -1 ];
|
||||
indentMap[ depth ] = smallerIndent + indent;
|
||||
return indentMap[ depth ];
|
||||
}
|
||||
|
||||
var sb = new StringBuilder();
|
||||
|
||||
for ( int i = 0; i < depth; i++ )
|
||||
{
|
||||
sb.Append( indent );
|
||||
}
|
||||
|
||||
indentMap[ depth ] = sb.ToString();
|
||||
return indentMap[ depth ];
|
||||
|
||||
}
|
||||
|
||||
int GetDepth( HtmlNode n )
|
||||
{
|
||||
return walker.GetDepth( n, depthMap );
|
||||
}
|
||||
|
||||
void ClosePreviousElements( int currentDepth )
|
||||
{
|
||||
for ( int i = stack.Count - 1; i >= 0; i-- )
|
||||
{
|
||||
var stackDepth = GetDepth( stack[ i ] );
|
||||
|
||||
if ( stackDepth >= currentDepth )
|
||||
{
|
||||
var element = stack[ i ];
|
||||
stack.RemoveAt( i );
|
||||
|
||||
if ( NeedsLineBreak( element ) )
|
||||
{
|
||||
sb.Append( "\n" );
|
||||
sb.Append( GetIndent( stackDepth ) );
|
||||
}
|
||||
|
||||
sb.Append( "</" + element.nodeName + ">" );
|
||||
}
|
||||
else
|
||||
{
|
||||
i = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool NeedsLineBreak( HtmlElementNode elementNode )
|
||||
{
|
||||
if ( elementNode.numChildren == 0 ||
|
||||
|
||||
elementNode.HasOnlyTextNodes() &&
|
||||
! ( HtmlElementNodeName.script.Selects( elementNode ) ||
|
||||
HtmlElementNodeName.style.Selects( elementNode )
|
||||
)
|
||||
)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public class HtmlTextNode:HtmlNode
|
||||
{
|
||||
public HtmlTextNode( HtmlDocument document, string textContent ):base( document, HtmlNode.NodeType.Text )
|
||||
{
|
||||
_textContent = textContent;
|
||||
}
|
||||
|
||||
string _textContent;
|
||||
|
||||
public override string nodeValue => _textContent;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public class HtmlWalker: TreeWalker<HtmlNode>
|
||||
{
|
||||
private static HtmlWalker _instance = new HtmlWalker();
|
||||
public static HtmlWalker instance => _instance;
|
||||
|
||||
public override int NumChildren( HtmlNode node )
|
||||
{
|
||||
var elementNode = node as HtmlElementNode;
|
||||
|
||||
if ( elementNode != null )
|
||||
{
|
||||
return elementNode.numChildren;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public override HtmlNode ChildAt( HtmlNode node, int index )
|
||||
{
|
||||
var elementNode = node as HtmlElementNode;
|
||||
|
||||
if ( elementNode != null )
|
||||
{
|
||||
return elementNode.GetChildAt( index );
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public override HtmlNode Parent( HtmlNode node )
|
||||
{
|
||||
return node.parentNode;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -35,6 +35,24 @@ namespace Rokojori
|
|||
{
|
||||
return node.GlobalBasis.X;
|
||||
}
|
||||
|
||||
public static Vector3 GetYPlaneForward( Node3D node )
|
||||
{
|
||||
var forward = GetGlobalForward( node );
|
||||
|
||||
forward.Y = 0;
|
||||
|
||||
return forward.Normalized();
|
||||
}
|
||||
|
||||
public static Vector3 GetYPlaneRight( Node3D node )
|
||||
{
|
||||
var right = GetGlobalRight( node );
|
||||
|
||||
right.Y = 0;
|
||||
|
||||
return right.Normalized();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -225,5 +225,15 @@ namespace Rokojori
|
|||
}
|
||||
|
||||
|
||||
public static float TimeLerp( float from, float to, float t, float timeDelta )
|
||||
{
|
||||
return Mathf.Lerp( from, to, 1f - Mathf.Pow( t, timeDelta ) );
|
||||
}
|
||||
|
||||
public static float PolarAxis( bool negative, bool positive )
|
||||
{
|
||||
return ( negative ? -1 : 0 ) + ( positive ? 1 : 0 );
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
|
||||
using Godot;
|
||||
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
[GlobalClass,Icon("res://Scripts/Rokojori/Rokojori-Action-Library/Icons/RJSensor.svg")]
|
||||
public partial class CombineSensor : RJSensor
|
||||
{
|
||||
[Export]
|
||||
public RJSensor[] sensors;
|
||||
|
||||
[Export]
|
||||
public float axisActivationTreshold = 0.75f;
|
||||
|
||||
float _value = 0;
|
||||
bool _wasActive = false;
|
||||
bool _isActive = false;
|
||||
|
||||
public override float GetValue()
|
||||
{
|
||||
return _value;
|
||||
}
|
||||
|
||||
public override bool IsActive()
|
||||
{
|
||||
return _isActive;
|
||||
}
|
||||
|
||||
public override bool WasActive()
|
||||
{
|
||||
return _wasActive;
|
||||
}
|
||||
|
||||
public override void UpdateValue( float value )
|
||||
{
|
||||
_value = value;
|
||||
|
||||
_wasActive = _isActive;
|
||||
_isActive = _value > axisActivationTreshold;
|
||||
}
|
||||
|
||||
public override void _Process( double delta )
|
||||
{
|
||||
var value = 0f;
|
||||
|
||||
for ( int i = 0; i < sensors.Length; i++ )
|
||||
{
|
||||
value = Mathf.Max( value, sensors[ i ].GetValue() );
|
||||
}
|
||||
|
||||
UpdateValue( value );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
|
||||
using Godot;
|
||||
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public class Sensors
|
||||
{
|
||||
public static bool IsActive( RJSensor sensor )
|
||||
{
|
||||
return sensor == null ? false : sensor.IsActive();
|
||||
}
|
||||
|
||||
public static float GetValue( RJSensor sensor, float scale = 1 )
|
||||
{
|
||||
return sensor == null ? 0 : sensor.GetValue() * scale;
|
||||
}
|
||||
|
||||
public static float PolarAxis( RJSensor negative, RJSensor positive )
|
||||
{
|
||||
return GetValue( negative, -1 ) + GetValue( positive, 1 );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,142 @@
|
|||
#include "res://Scripts/Rokojori/Rokojori-Action-Library/Runtime/Shading/Library/Math.gdshaderinc"
|
||||
|
||||
const float HCV_EPSILON = 1e-10;
|
||||
const float HSL_EPSILON = 1e-10;
|
||||
|
||||
vec3 RGBtoHCV( vec3 rgb )
|
||||
{
|
||||
vec4 P = ( rgb.g < rgb.b ) ? vec4( rgb.bg, -1.0, 2.0/3.0 ) : vec4( rgb.gb, 0.0, -1.0/3.0 );
|
||||
vec4 Q = ( rgb.r < P.x ) ? vec4( P.xyw, rgb.r ) : vec4( rgb.r, P.yzx );
|
||||
float C = Q.x - min( Q.w, Q.y );
|
||||
float H = abs( (Q.w - Q.y ) / ( 6.0 * C + HCV_EPSILON ) + Q.z );
|
||||
return vec3( H, C, Q.x );
|
||||
}
|
||||
|
||||
|
||||
vec3 RGBtoHSL( vec3 rgb )
|
||||
{
|
||||
vec3 HCV = RGBtoHCV( rgb );
|
||||
float L = HCV.z - HCV.y * 0.5;
|
||||
float S = HCV.y / ( 1.0 - abs( L * 2.0 - 1.0 ) + HSL_EPSILON );
|
||||
return vec3( HCV.x, S, L );
|
||||
}
|
||||
|
||||
vec3 hueToRGB( float hue )
|
||||
{
|
||||
float R = abs( hue * 6.0 - 3.0 ) - 1.0;
|
||||
float G = 2.0 - abs( hue * 6.0 - 2.0 );
|
||||
float B = 2.0 - abs( hue * 6.0 - 4.0 );
|
||||
return clamp( vec3( R,G,B ),0,1 );
|
||||
}
|
||||
|
||||
vec3 HSLtoRGB( vec3 hsl )
|
||||
{
|
||||
vec3 rgb = hueToRGB( hsl.x );
|
||||
float C = ( 1.0 - abs( 2.0 * hsl.z - 1.0 )) * hsl.y;
|
||||
return ( rgb - 0.5 ) * C + hsl.z;
|
||||
}
|
||||
|
||||
vec3 toLinear( vec3 sRGB )
|
||||
{
|
||||
return mix( pow( (sRGB + vec3( 0.055 )) * ( 1.0 / ( 1.0 + 0.055 )),vec3( 2.4 )),sRGB * ( 1.0 / 12.92 ),lessThan( sRGB,vec3( 0.04045 )) );
|
||||
}
|
||||
|
||||
float modPolarDegrees( float value )
|
||||
{
|
||||
return mod( value + 180.0, 360.0 ) - 180.0;
|
||||
}
|
||||
|
||||
float hue360ToYB( float hue )
|
||||
{
|
||||
return modPolarDegrees( hue - 240.0 );
|
||||
}
|
||||
|
||||
float ybToHue360( float yb )
|
||||
{
|
||||
return mod( yb + 240.0, 360.0 );
|
||||
}
|
||||
|
||||
float changeHue360( float hue, float change )
|
||||
{
|
||||
float yb = hue360ToYB( hue );
|
||||
|
||||
float absYB = abs( yb );
|
||||
|
||||
absYB = clamp( absYB + change, 0.0, 180.0 );
|
||||
|
||||
float realYB = sign( yb ) * absYB;
|
||||
|
||||
return ybToHue360( realYB );
|
||||
}
|
||||
|
||||
vec3 shiftHSL360( vec3 hslWithH360, vec3 offset, float blendRadius )
|
||||
{
|
||||
float distanceToYellow = min( 1.0, abs( hslWithH360.x - 60.0 ) / blendRadius );
|
||||
float distanceToBlue = min( 1.0, abs( hslWithH360.x - 240.0 ) / blendRadius );
|
||||
|
||||
hslWithH360.x = changeHue360( hslWithH360.x, offset.x );
|
||||
hslWithH360.y = clamp( hslWithH360.y + offset.y, 0, 1 );
|
||||
hslWithH360.z = clamp( hslWithH360.z + offset.z, 0, 1 );
|
||||
|
||||
return hslWithH360;
|
||||
}
|
||||
|
||||
|
||||
vec3 shiftHSL( vec3 hsl, vec3 offset, float blendRadius )
|
||||
{
|
||||
hsl.x *= 360.0;
|
||||
offset.x *= 360.0;
|
||||
hsl = shiftHSL360( hsl, offset, blendRadius );
|
||||
hsl.x /= 360.0;
|
||||
|
||||
return hsl;
|
||||
}
|
||||
|
||||
vec3 RGBtoHSV( vec3 c )
|
||||
{
|
||||
vec4 K = vec4( 0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0 );
|
||||
vec4 p = mix( vec4( c.bg, K.wz ), vec4( c.gb, K.xy ), step( c.b, c.g ));
|
||||
vec4 q = mix( vec4( p.xyw, c.r ), vec4( c.r, p.yzx ), step( p.x, c.r ));
|
||||
|
||||
float d = q.x - min( q.w, q.y );
|
||||
float e = 1.0e-10;
|
||||
|
||||
return vec3( abs( q.z + ( q.w - q.y ) / ( 6.0 * d + e )), d / ( q.x + e ), q.x );
|
||||
}
|
||||
|
||||
vec3 HSVtoRGB( vec3 c )
|
||||
{
|
||||
vec4 K = vec4( 1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0 );
|
||||
vec3 p = abs( fract( c.xxx + K.xyz ) * 6.0 - K.www );
|
||||
|
||||
return c.z * mix( K.xxx, clamp( p - K.xxx, 0.0, 1.0 ), c.y );
|
||||
}
|
||||
|
||||
vec3 mix3( vec3 a, vec3 b, vec3 c, float t )
|
||||
{
|
||||
float weightA = mapClamped( t, 0, 0.5, 1, 0 );
|
||||
float weightB = triangle( t );
|
||||
float weightC = mapClamped( t, 0.5, 1, 0, 1 );
|
||||
|
||||
return a * weightA + b * weightB + c * weightC;
|
||||
}
|
||||
|
||||
vec4 mix3_v4( vec4 a, vec4 b, vec4 c, float t )
|
||||
{
|
||||
float weightA = mapClamped( t, 0, 0.5, 1, 0 );
|
||||
float weightB = triangle( t );
|
||||
float weightC = mapClamped( t, 0.5, 1, 0, 1 );
|
||||
|
||||
return a * weightA + b * weightB + c * weightC;
|
||||
}
|
||||
|
||||
vec4 scaleRGB( vec4 rgba, float scale )
|
||||
{
|
||||
return vec4( rgba.rgb * scale, rgba.a );
|
||||
}
|
||||
|
||||
vec4 fade( vec4 rgba, float fade )
|
||||
{
|
||||
return vec4( rgba.rgb, rgba.a * fade );
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
float clamp01( float value )
|
||||
{
|
||||
return clamp( value, 0.0, 1.0 );
|
||||
}
|
||||
|
||||
vec4 clamp01_v4( vec4 value )
|
||||
{
|
||||
value.r = clamp01( value.r );
|
||||
value.g = clamp01( value.g );
|
||||
value.b = clamp01( value.b );
|
||||
value.a = clamp01( value.a );
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
float normalizeToRange( float value, float min, float max )
|
||||
{
|
||||
return ( value - min ) / ( max - min );
|
||||
}
|
||||
|
||||
float normalizeToRange01( float value, float min, float max )
|
||||
{
|
||||
return clamp01( normalizeToRange( value, min, max ) );
|
||||
}
|
||||
|
||||
float map( float value, float inMin, float inMax, float outMin, float outMax )
|
||||
{
|
||||
return mix( outMin, outMax, normalizeToRange( value, inMin, inMax ) );
|
||||
}
|
||||
|
||||
float mapClamped( float value, float inMin, float inMax, float outMin, float outMax )
|
||||
{
|
||||
return mix( outMin, outMax, normalizeToRange01( value, inMin, inMax ) );
|
||||
}
|
||||
|
||||
float triangle( float value )
|
||||
{
|
||||
float inverted = 1.0 - value;
|
||||
|
||||
return min( value, inverted ) * 2.0;
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
shader_type canvas_item;
|
||||
|
||||
#include "res://Scripts/Rokojori/Rokojori-Action-Library/Runtime/Shading/Library/Colors.gdshaderinc"
|
||||
#include "res://Scripts/Rokojori/Rokojori-Action-Library/Runtime/Shading/Library/Math.gdshaderinc"
|
||||
|
||||
uniform sampler2D screenTexture:
|
||||
hint_screen_texture,
|
||||
repeat_disable,
|
||||
filter_linear_mipmap;
|
||||
|
||||
uniform sampler2D rChannelCurve;
|
||||
uniform float rChannelEffectStrength: hint_range(0,1) = 1;
|
||||
|
||||
uniform sampler2D gChannelCurve;
|
||||
uniform float gChannelEffectStrength: hint_range(0,1) = 1;
|
||||
|
||||
uniform sampler2D bChannelCurve;
|
||||
uniform float bChannelEffectStrength: hint_range(0,1) = 1;
|
||||
|
||||
uniform sampler2D hChannelCurve;
|
||||
uniform float hChannelEffectStrength: hint_range(0,1) = 1;
|
||||
|
||||
uniform sampler2D sChannelCurve;
|
||||
uniform float sChannelEffectStrength: hint_range(0,1) = 1;
|
||||
|
||||
uniform sampler2D lChannelCurve;
|
||||
uniform float lChannelEffectStrength: hint_range(0,1) = 1;
|
||||
|
||||
uniform sampler2D lumaTemparatureShiftCurve;
|
||||
uniform float warmenShift: hint_range(-1,1) = 0;
|
||||
uniform float saturationShift: hint_range(-1,1) = 0;
|
||||
uniform float luminanceShift: hint_range(-1,1) = 0;
|
||||
uniform float lumaTemparatureShiftEffectStrength: hint_range(0,1) = 1;
|
||||
|
||||
|
||||
uniform sampler2D lumaSaturationCurve;
|
||||
uniform float lumaSaturationEffectStrength: hint_range(0,1) = 1;
|
||||
|
||||
uniform float effectStrength : hint_range(0,1) = 1;
|
||||
|
||||
void fragment()
|
||||
{
|
||||
vec4 rgb = texture( screenTexture, UV );
|
||||
vec4 originalRGB = rgb;
|
||||
|
||||
rgb.r = mix( rgb.r, texture( rChannelCurve, vec2( rgb.r, 0.0 ) ).x, rChannelEffectStrength );
|
||||
rgb.g = mix( rgb.g, texture( gChannelCurve, vec2( rgb.g, 0.0 ) ).x, gChannelEffectStrength );
|
||||
rgb.b = mix( rgb.b, texture( bChannelCurve, vec2( rgb.b, 0.0 ) ).x, bChannelEffectStrength );
|
||||
|
||||
rgb = clamp01_v4( rgb );
|
||||
|
||||
vec3 hsl = RGBtoHSL( rgb.rgb );
|
||||
|
||||
hsl.r = mix( hsl.r, hsl.r + texture( hChannelCurve, vec2( hsl.r, 0.0 ) ).x - 0.5, hChannelEffectStrength );
|
||||
hsl.r = mod( hsl.r, 1.0 );
|
||||
hsl.g = mix( hsl.g, texture( sChannelCurve, vec2( hsl.g, 0.0 ) ).x, sChannelEffectStrength );
|
||||
hsl.b = mix( hsl.b, texture( lChannelCurve, vec2( hsl.b, 0.0 ) ).x, lChannelEffectStrength );
|
||||
|
||||
vec3 lumaTemparatureShift = vec3( warmenShift, -saturationShift, luminanceShift );
|
||||
float lumaTemparatureShiftAmount = texture( lumaTemparatureShiftCurve, vec2( hsl.b, 0 ) ).x * 2.0 - 1.0;
|
||||
lumaTemparatureShiftAmount = lumaTemparatureShiftAmount * lumaTemparatureShiftEffectStrength;
|
||||
hsl = shiftHSL( hsl, lumaTemparatureShift * lumaTemparatureShiftAmount, 10 );
|
||||
|
||||
hsl.g = mix( hsl.g, hsl.g + texture( lumaSaturationCurve, vec2( hsl.b, 0.0 ) ).x - 0.5, hChannelEffectStrength );
|
||||
rgb = vec4( HSLtoRGB( hsl ), rgb.a );
|
||||
|
||||
COLOR = mix( originalRGB, rgb, effectStrength );
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
shader_type canvas_item;
|
||||
|
||||
#include "res://Scripts/Rokojori/Rokojori-Action-Library/Runtime/Shading/Library/Colors.gdshaderinc"
|
||||
#include "res://Scripts/Rokojori/Rokojori-Action-Library/Runtime/Shading/Library/Math.gdshaderinc"
|
||||
|
||||
uniform sampler2D screenTexture:
|
||||
hint_screen_texture,
|
||||
repeat_disable,
|
||||
filter_linear_mipmap;
|
||||
|
||||
|
||||
uniform sampler2D overlay;
|
||||
uniform float effectStrength: hint_range(0,1) = 1;
|
||||
|
||||
|
||||
void fragment()
|
||||
{
|
||||
vec4 rgb = texture( screenTexture, UV );
|
||||
vec4 originalRGB = rgb;
|
||||
|
||||
vec4 overlayColor = texture( overlay, UV );
|
||||
vec4 additiveOverlayColor = overlayColor + rgb;
|
||||
vec4 multipliedOverlayColor = overlayColor * rgb;
|
||||
|
||||
float overlayBlendType = length( overlayColor.rgb );
|
||||
vec4 mixed = mix3_v4( multipliedOverlayColor, rgb, additiveOverlayColor, overlayBlendType );
|
||||
|
||||
rgb = mixed;
|
||||
COLOR = mix( originalRGB, mixed, effectStrength );
|
||||
}
|
|
@ -42,6 +42,30 @@ namespace Rokojori
|
|||
AddMatcher( type, new Regex( regex ), mode, nextMode );
|
||||
}
|
||||
|
||||
public LexerMatcher GetMatcher( string source, string mode ="" )
|
||||
{
|
||||
var matchers = _modes[ mode ];
|
||||
var offset = 0;
|
||||
|
||||
for ( var i = 0; i < matchers.Count; i++ )
|
||||
{
|
||||
var matcher = matchers[ i ];
|
||||
var matchLength = matcher.MatchLength( source, offset );
|
||||
|
||||
if ( matchLength > 0 )
|
||||
{
|
||||
return matcher;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void GrabMatches( List<LexerEvent> events, string source )
|
||||
{
|
||||
events.ForEach( ev => { ev.GrabMatch( source ); } );
|
||||
}
|
||||
|
||||
public void Lex( string source, System.Action<LexerEvent> callback, int offset = 0, string mode = "" )
|
||||
{
|
||||
var ERROR_FLAG = -1;
|
||||
|
@ -49,13 +73,18 @@ namespace Rokojori
|
|||
|
||||
var lexerEvent = new LexerEvent( "", 0, -2 );
|
||||
|
||||
while ( offset < source.Length )
|
||||
var numTries = 0;
|
||||
var maxTries = 1000;
|
||||
|
||||
while ( offset < source.Length && numTries < maxTries)
|
||||
{
|
||||
numTries ++;
|
||||
|
||||
if ( ! _modes.ContainsKey( mode ) )
|
||||
{
|
||||
var errorMessage = "@Lexer-Error. Mode not found: '" + mode + "'";
|
||||
RJLog.Log( errorMessage, "@", offset );
|
||||
lexerEvent.set( errorMessage, offset, ERROR_FLAG );
|
||||
lexerEvent.Set( errorMessage, offset, ERROR_FLAG );
|
||||
_hasError = true;
|
||||
callback( lexerEvent );
|
||||
|
||||
|
@ -72,7 +101,7 @@ namespace Rokojori
|
|||
|
||||
if ( matchLength > 0 )
|
||||
{
|
||||
lexerEvent.set( matcher.type, offset, matchLength );
|
||||
lexerEvent.Set( matcher.type, offset, matchLength );
|
||||
//Logs.Log(matcher.type, ">>", "'"+source.Substring( offset, matchLength )+"'", "@", offset, matchLength );
|
||||
callback( lexerEvent );
|
||||
|
||||
|
@ -94,7 +123,7 @@ namespace Rokojori
|
|||
{
|
||||
var errorMessage = "@Lexer-Error. No match: '" + mode + "'";
|
||||
RJLog.Log(errorMessage, "@", offset );
|
||||
lexerEvent.set( errorMessage, offset, ERROR_FLAG );
|
||||
lexerEvent.Set( errorMessage, offset, ERROR_FLAG );
|
||||
_hasError = true;
|
||||
callback( lexerEvent );
|
||||
|
||||
|
@ -103,7 +132,13 @@ namespace Rokojori
|
|||
|
||||
}
|
||||
|
||||
lexerEvent.set( mode, offset, DONE_FLAG );
|
||||
if ( numTries >= maxTries )
|
||||
{
|
||||
lexerEvent.Set( mode, offset, ERROR_FLAG );
|
||||
callback( lexerEvent );
|
||||
}
|
||||
|
||||
lexerEvent.Set( mode, offset, DONE_FLAG );
|
||||
callback( lexerEvent );
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
using System.Text;
|
||||
|
||||
|
||||
namespace Rokojori
|
||||
|
@ -17,7 +17,7 @@ namespace Rokojori
|
|||
|
||||
public LexerEvent( string type, int offset, int length )
|
||||
{
|
||||
set( type, offset, length );
|
||||
Set( type, offset, length );
|
||||
}
|
||||
|
||||
public string type { get { return _type; } }
|
||||
|
@ -34,7 +34,7 @@ namespace Rokojori
|
|||
get { return this.length == -2; }
|
||||
}
|
||||
|
||||
public void set( string type, int offset, int length )
|
||||
public void Set( string type, int offset, int length )
|
||||
{
|
||||
this._type = type;
|
||||
this._offset = offset;
|
||||
|
@ -65,5 +65,132 @@ namespace Rokojori
|
|||
_match = source.Substring( offset, length );
|
||||
}
|
||||
|
||||
public bool Is( string type, string match = null )
|
||||
{
|
||||
var typeCorrect = type == null || type == this.type;
|
||||
|
||||
if ( ! typeCorrect )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return match == null || match == this.match;
|
||||
}
|
||||
|
||||
public bool Is( LexerMatcher matcher, string match = null )
|
||||
{
|
||||
return Is( matcher == null ? null : matcher.type, match );
|
||||
}
|
||||
|
||||
|
||||
public enum FindResultType
|
||||
{
|
||||
Found,
|
||||
KeepSearching,
|
||||
NotFound,
|
||||
Error
|
||||
}
|
||||
|
||||
public class FindResult
|
||||
{
|
||||
public FindResultType type = FindResultType.NotFound;
|
||||
public int index;
|
||||
}
|
||||
|
||||
public static string GetMatchFromRange( List<LexerEvent> tokens, int offset, int length )
|
||||
{
|
||||
var match = new StringBuilder();
|
||||
|
||||
for ( int i = 0; i < length; i++ )
|
||||
{
|
||||
match.Append( tokens[ offset + i ].match );
|
||||
}
|
||||
|
||||
return match.ToString();
|
||||
}
|
||||
|
||||
|
||||
public static FindResult Find( List<LexerEvent> tokens, int offset, System.Func<LexerEvent,FindResultType> evaluator )
|
||||
{
|
||||
var result = new FindResult();
|
||||
|
||||
for ( int i = offset; i < tokens.Count; i++ )
|
||||
{
|
||||
var tokenResult = evaluator( tokens[ i ] );
|
||||
|
||||
if ( tokenResult == FindResultType.Error ||
|
||||
tokenResult == FindResultType.Found
|
||||
)
|
||||
{
|
||||
result.type = tokenResult;
|
||||
result.index = i;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static FindResult FindClosingBracket( List<LexerEvent> tokens, int offset )
|
||||
{
|
||||
var openTypes = new List<string>(){ "(","[","{" };
|
||||
var closingTypes = new List<string>(){ ")","]","}" };
|
||||
|
||||
var token = tokens[ offset ];
|
||||
|
||||
var bracketIndex = openTypes.IndexOf( token.match );
|
||||
|
||||
if ( bracketIndex == -1 )
|
||||
{
|
||||
var result = new FindResult();
|
||||
result.type = FindResultType.NotFound;
|
||||
result.index = offset;
|
||||
return result;
|
||||
}
|
||||
|
||||
var opener = openTypes[ bracketIndex ];
|
||||
var closer = closingTypes[ bracketIndex ];
|
||||
|
||||
var counter = ( LexerEvent le ) =>
|
||||
{
|
||||
if ( le.Is( LexerMatcherLibrary.BracketMatcher, closer ) )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( le.Is( LexerMatcherLibrary.BracketMatcher, opener ) )
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
return FindCloser( tokens, offset, counter );
|
||||
}
|
||||
|
||||
public static FindResult FindCloser( List<LexerEvent> tokens, int offset, System.Func<LexerEvent,int> counter )
|
||||
{
|
||||
var result = new FindResult();
|
||||
var currentValue = 0;
|
||||
|
||||
for ( int i = offset; i < tokens.Count; i++ )
|
||||
{
|
||||
var countResult = counter( tokens[ i ] );
|
||||
|
||||
currentValue += countResult;
|
||||
|
||||
if ( currentValue == 0 )
|
||||
{
|
||||
result.type = FindResultType.Found;
|
||||
result.index = i;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -23,24 +23,24 @@ namespace Rokojori
|
|||
public CSharpLexer()
|
||||
{
|
||||
AddAllMatchers(
|
||||
LexerMatcherLibrary.SINGLE_LINE_COMMENT_MATCHER,
|
||||
LexerMatcherLibrary.MULTI_LINE_COMMENT_MATCHER,
|
||||
LexerMatcherLibrary.DOUBLE_QUOTED_STRING_MATCHER,
|
||||
LexerMatcherLibrary.SINGLE_QUOTED_STRING_MATCHER,
|
||||
LexerMatcherLibrary.C_INSTRUCTION_MATCHER,
|
||||
LexerMatcherLibrary.NUMBER_MATCHER,
|
||||
LexerMatcherLibrary.NULL_MATCHER,
|
||||
LexerMatcherLibrary.BOOL_MATCHER,
|
||||
LexerMatcherLibrary.BREAK_MATCHER,
|
||||
LexerMatcherLibrary.WHITESPACE_MATCHER,
|
||||
LexerMatcherLibrary.LOGIC_MATCHER,
|
||||
LexerMatcherLibrary.BRACKET_MATCHER,
|
||||
LexerMatcherLibrary.ACCESS_MODIFIER_MATCHER,
|
||||
LexerMatcherLibrary.CLASS_MATCHER,
|
||||
LexerMatcherLibrary.OPERATOR_MATCHER,
|
||||
LexerMatcherLibrary.CFUNCTION_MATCHER,
|
||||
LexerMatcherLibrary.CWORD_MATCHER,
|
||||
LexerMatcherLibrary.ANY_SYMBOL_MATCHER
|
||||
LexerMatcherLibrary.SingleLineCommentMatcher,
|
||||
LexerMatcherLibrary.MultiLineCommentMatcher,
|
||||
LexerMatcherLibrary.DoubleQuotedStringMatcher,
|
||||
LexerMatcherLibrary.SingleQuotedStringMatcher,
|
||||
LexerMatcherLibrary.CInstructionMatcher,
|
||||
LexerMatcherLibrary.NumberMatcher,
|
||||
LexerMatcherLibrary.NullMatcher,
|
||||
LexerMatcherLibrary.BoolMatcher,
|
||||
LexerMatcherLibrary.BreakMatcher,
|
||||
LexerMatcherLibrary.WhiteSpaceMatcher,
|
||||
LexerMatcherLibrary.LogicMatcher,
|
||||
LexerMatcherLibrary.BracketMatcher,
|
||||
LexerMatcherLibrary.AccessModifierMatcher,
|
||||
LexerMatcherLibrary.ClassMatcher,
|
||||
LexerMatcherLibrary.OperatorMatcher,
|
||||
LexerMatcherLibrary.CFunctionMatcher,
|
||||
LexerMatcherLibrary.CwordMatcher,
|
||||
LexerMatcherLibrary.AnySymbolMatcher
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,6 +42,11 @@ namespace Rokojori
|
|||
_matcher = RegexUtility.MakeSticky( new Regex( matcher ) );
|
||||
}
|
||||
|
||||
public static LexerMatcher CreateExtended( string type, string matcher, string mode = "", string nextMode = "" )
|
||||
{
|
||||
return new LexerMatcher( type, RegexExtensions.Extend( matcher ), mode, nextMode );
|
||||
}
|
||||
|
||||
public LexerMatcher CloneWithMode( string mode, string nextMode )
|
||||
{
|
||||
return new LexerMatcher( _type, _matcher, mode, nextMode );
|
||||
|
|
|
@ -6,93 +6,90 @@ namespace Rokojori
|
|||
{
|
||||
public class LexerMatcherLibrary
|
||||
{
|
||||
public static readonly LexerMatcher CWORD_MATCHER =
|
||||
new LexerMatcher( "CWORD", @"[a-zA-Z_]\w*" );
|
||||
public static readonly LexerMatcher CwordMatcher =
|
||||
new LexerMatcher( "CWord", @"[a-zA-Z_]\w*" );
|
||||
|
||||
public static readonly LexerMatcher CFUNCTION_MATCHER =
|
||||
new LexerMatcher( "CFUNCTION", @"[a-zA-Z_]\w*(?=\s*\()" );
|
||||
public static readonly LexerMatcher CFunctionMatcher =
|
||||
new LexerMatcher( "CFunction", @"[a-zA-Z_]\w*(?=\s*\()" );
|
||||
|
||||
// public static readonly LexerMatcher LexerMatcherCLASSNAME_MATCHER =
|
||||
// new LexerMatcher( "CLASSNAME", @"(?<=(?:(?:class|interface|struct)\s+))[a-zA-Z_]\w*" );
|
||||
public static readonly LexerMatcher JSWordMatcher =
|
||||
new LexerMatcher( "JSWord", @"[a-zA-Z_\$]\w*" );
|
||||
|
||||
public static readonly LexerMatcher JSWORD_MATCHER =
|
||||
new LexerMatcher( "JSWORD", @"[a-zA-Z_\$]\w*" );
|
||||
|
||||
public static readonly LexerMatcher PHPWORD_MATCHER =
|
||||
new LexerMatcher( "PHPWORD", @"\$?[a-zA-Z_]\w*" );
|
||||
public static readonly LexerMatcher PHPWordMatcher =
|
||||
new LexerMatcher( "PHPWord", @"\$?[a-zA-Z_]\w*" );
|
||||
|
||||
|
||||
public static readonly LexerMatcher CSS_CLASS_SELECTOR_MATCHER =
|
||||
new LexerMatcher( "CSS_CLASS_SELECTOR", @"\.[a-zA-Z_](\w|\-)*" );
|
||||
public static readonly LexerMatcher CSS_ClassSelectorMatcher =
|
||||
new LexerMatcher( "CSS_ClassSelector", @"\.[a-zA-Z_](\w|\-)*" );
|
||||
|
||||
public static readonly LexerMatcher CSS_ID_SELECTOR_MATCHER =
|
||||
new LexerMatcher( "CSS_ID_SELECTOR", @"\#[a-zA-Z_](\w|\-)*" );
|
||||
public static readonly LexerMatcher CSS_IDSelectorMatcher =
|
||||
new LexerMatcher( "CSS_IDSelector", @"\#[a-zA-Z_](\w|\-)*" );
|
||||
|
||||
public static readonly LexerMatcher CSS_WORD_MATCHER =
|
||||
new LexerMatcher( "CSS_WORD", @"[a-zA-Z_](\w|\-)*" );
|
||||
public static readonly LexerMatcher CSS_WordMatcher =
|
||||
new LexerMatcher( "CSS_Word", @"[a-zA-Z_](\w|\-)*" );
|
||||
|
||||
|
||||
public static readonly LexerMatcher HTML_CUSTOM_ELEMENT_MATCHER =
|
||||
new LexerMatcher( "HTML_CUSTOM_ELEMENT", @"[a-zA-Z]\w*\-(\w|\-)+" );
|
||||
public static readonly LexerMatcher HTML_CustomElementMatcher =
|
||||
new LexerMatcher( "HTML_CustomElement", @"[a-zA-Z]\w*\-(\w|\-)+" );
|
||||
|
||||
public static readonly LexerMatcher DOUBLE_QUOTED_STRING_MATCHER =
|
||||
new LexerMatcher( "DOUBLE_QUOTED_STRING", "\"(?:[^\"\\\\]|\\\\.)*\"" );
|
||||
public static readonly LexerMatcher DoubleQuotedStringMatcher =
|
||||
new LexerMatcher( "DoubleQuotedString", "\"(?:[^\"\\\\]|\\\\.)*\"" );
|
||||
|
||||
public static readonly LexerMatcher SINGLE_QUOTED_STRING_MATCHER =
|
||||
new LexerMatcher( "SINGLE_QUOTED_STRING", @"'(?:[^'\\]|\\.)*'" );
|
||||
public static readonly LexerMatcher SingleQuotedStringMatcher =
|
||||
new LexerMatcher( "SingleQuotedString", @"'(?:[^'\\]|\\.)*'" );
|
||||
|
||||
public static readonly LexerMatcher NUMBER_MATCHER =
|
||||
new LexerMatcher( "NUMBER", @"(?=\.\d|\d)(?:\d+)?(?:\.?\d*)(?:[eE][+-]?\d+)?" );
|
||||
public static readonly LexerMatcher NumberMatcher =
|
||||
new LexerMatcher( "Number", @"(?=\.\d|\d)(?:\d+)?(?:\.?\d*)(?:[eE][+-]?\d+)?" );
|
||||
|
||||
public static readonly LexerMatcher WHITESPACE_MATCHER =
|
||||
new LexerMatcher( "WHITESPACE", @"\s+" );
|
||||
public static readonly LexerMatcher WhiteSpaceMatcher =
|
||||
new LexerMatcher( "WhiteSpace", @"\s+" );
|
||||
|
||||
public static readonly LexerMatcher BREAK_MATCHER =
|
||||
new LexerMatcher( "BREAK", @"(\r\n|\r|\n)" );
|
||||
public static readonly LexerMatcher BreakMatcher =
|
||||
new LexerMatcher( "Break", @"(\r\n|\r|\n)" );
|
||||
|
||||
|
||||
public static readonly LexerMatcher NULL_MATCHER =
|
||||
new LexerMatcher( "NULL", "null" );
|
||||
public static readonly LexerMatcher NullMatcher =
|
||||
new LexerMatcher( "Null", "null" );
|
||||
|
||||
public static readonly LexerMatcher BOOL_MATCHER =
|
||||
new LexerMatcher( "BOOL", "true|false" );
|
||||
public static readonly LexerMatcher BoolMatcher =
|
||||
new LexerMatcher( "Bool", "true|false" );
|
||||
|
||||
public static readonly LexerMatcher LOGIC_MATCHER =
|
||||
new LexerMatcher( "LOGIC", "if|else|switch|do|while|for|break|continue|return" );
|
||||
public static readonly LexerMatcher LogicMatcher =
|
||||
new LexerMatcher( "Logic", "if|else|switch|do|while|for|break|continue|return" );
|
||||
|
||||
public static readonly LexerMatcher OPERATOR_MATCHER =
|
||||
new LexerMatcher( "OPERATOR", "(?:\\=\\=)|(?:\\+\\+)|(?:\\-\\-)|\\+|\\-|\\*|\\/|\\^|\\||\\~|\\&|\\%|\\<|\\>|\\=|\\!|\\.|\\:|\\,|\\;" );
|
||||
public static readonly LexerMatcher OperatorMatcher =
|
||||
new LexerMatcher( "Operator", "(?:\\=\\=)|(?:\\+\\+)|(?:\\-\\-)|\\+|\\-|\\*|\\/|\\^|\\||\\~|\\&|\\%|\\<|\\>|\\=|\\!|\\.|\\:|\\,|\\;" );
|
||||
|
||||
public static readonly LexerMatcher BRACKET_MATCHER =
|
||||
new LexerMatcher( "BRACKET", @"\(|\)|\[|\]|\{|\}" );
|
||||
public static readonly LexerMatcher BracketMatcher =
|
||||
new LexerMatcher( "Bracket", @"\(|\)|\[|\]|\{|\}" );
|
||||
|
||||
public static readonly LexerMatcher BLOCKSTART_MATCHER =
|
||||
new LexerMatcher( "BLOCKSTART", @"\{" );
|
||||
public static readonly LexerMatcher BlockStartMatcher =
|
||||
new LexerMatcher( "BlockStart", @"\{" );
|
||||
|
||||
public static readonly LexerMatcher BLOCKEND_MATCHER =
|
||||
new LexerMatcher( "BLOCKEND", @"\}" );
|
||||
public static readonly LexerMatcher BlockEndMatcher =
|
||||
new LexerMatcher( "BlockStart", @"\}" );
|
||||
|
||||
public static readonly LexerMatcher CLASS_MATCHER =
|
||||
new LexerMatcher( "CLASS", @"\bclass\b" );
|
||||
public static readonly LexerMatcher ClassMatcher =
|
||||
new LexerMatcher( "Class", @"\bclass\b" );
|
||||
|
||||
public static readonly LexerMatcher ACCESS_MODIFIER_MATCHER =
|
||||
new LexerMatcher( "ACCESS_MODIFIER", @"\b(?:public|protected|private)\b" );
|
||||
public static readonly LexerMatcher AccessModifierMatcher =
|
||||
new LexerMatcher( "AccessModifier", @"\b(?:public|protected|private)\b" );
|
||||
|
||||
|
||||
public static readonly LexerMatcher SINGLE_LINE_COMMENT_MATCHER =
|
||||
new LexerMatcher( "SINGLE_LINE_COMMENT", @"//.*" );
|
||||
public static readonly LexerMatcher SingleLineCommentMatcher =
|
||||
new LexerMatcher( "SingleLineComment", @"//.*" );
|
||||
|
||||
public static readonly LexerMatcher C_INSTRUCTION_MATCHER =
|
||||
new LexerMatcher( "C_INSTRUCTION", @"\#.*" );
|
||||
public static readonly LexerMatcher CInstructionMatcher =
|
||||
new LexerMatcher( "CInstruction", @"\#.*" );
|
||||
|
||||
public static readonly LexerMatcher MULTI_LINE_COMMENT_MATCHER =
|
||||
new LexerMatcher( "MULTI_LINE_COMMENT", @"\/\*(.|(\r\n|\r|\n))*?\*\/" );
|
||||
public static readonly LexerMatcher MultiLineCommentMatcher =
|
||||
new LexerMatcher( "MultiLineComment", @"\/\*(.|(\r\n|\r|\n))*?\*\/" );
|
||||
|
||||
public static readonly LexerMatcher ANY_SYMBOL_MATCHER =
|
||||
new LexerMatcher( "ANY_SYMBOL", @"." );
|
||||
public static readonly LexerMatcher AnySymbolMatcher =
|
||||
new LexerMatcher( "AnySymbol", @"." );
|
||||
|
||||
public static readonly LexerMatcher HASH_TAG =
|
||||
new LexerMatcher( "HASH_TAG", @"\#(\w|-|\d)+" );
|
||||
public static readonly LexerMatcher HashTag =
|
||||
new LexerMatcher( "HashTag", @"\#(\w|-|\d)+" );
|
||||
|
||||
public static readonly LexerMatcher URL =
|
||||
new LexerMatcher( "URL", @"https?\:\/\/(\w|\.|\-|\?|\=|\+|\/)+" );
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Text;
|
||||
|
||||
using System.Globalization;
|
||||
using Godot;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public class RegexExtensions
|
||||
{
|
||||
public static string Extend( string source )
|
||||
{
|
||||
//RJLog.Log( "Original:", source );
|
||||
|
||||
// l: Linebreak
|
||||
source = RegexUtility.Replace( source, @"\\l", @"(?:\r\n|\r|\n)" );
|
||||
|
||||
// v: Variable
|
||||
source = RegexUtility.Replace( source, @"\\l", @"(?:\w|_)+" );
|
||||
|
||||
//RJLog.Log( "Extended:", source );
|
||||
|
||||
return source;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -384,6 +384,14 @@ namespace Rokojori
|
|||
return Split( source, new Regex( regex ) );
|
||||
}
|
||||
|
||||
public static List<string> SplitLines( string source )
|
||||
{
|
||||
var array = Regex.Split( source, "\r\n|\r|\n" );
|
||||
var list = new List<string>();
|
||||
list.AddRange( array );
|
||||
return list;
|
||||
}
|
||||
|
||||
public static string Remove( string source, string regex )
|
||||
{
|
||||
return Replace( source, regex, "" );
|
||||
|
|
|
@ -14,6 +14,7 @@ namespace Rokojori
|
|||
{
|
||||
[Export]
|
||||
public Vector3 target;
|
||||
|
||||
[Export]
|
||||
public float yaw = 0;
|
||||
|
||||
|
|
|
@ -0,0 +1,226 @@
|
|||
|
||||
using System.Diagnostics;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using Godot;
|
||||
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
[Tool]
|
||||
[GlobalClass]
|
||||
public partial class StrategyTopDownCamera:VirtualCamera3D
|
||||
{
|
||||
[Export]
|
||||
public Vector3 target;
|
||||
|
||||
[Export]
|
||||
public float yaw = 0;
|
||||
|
||||
[Export]
|
||||
public float pitch = 0;
|
||||
|
||||
[Export]
|
||||
public float distance = 10;
|
||||
float smoothDistance = 10;
|
||||
|
||||
[ExportCategory("Move")]
|
||||
|
||||
[Export]
|
||||
public RJSensor moveUpButton;
|
||||
[Export]
|
||||
public RJSensor moveDownButton;
|
||||
[Export]
|
||||
public RJSensor moveRightButton;
|
||||
[Export]
|
||||
public RJSensor moveLeftButton;
|
||||
|
||||
[Export]
|
||||
public float buttonMoveSpeed = 1f;
|
||||
|
||||
|
||||
[Export]
|
||||
public RJSensor mouseMoveButton;
|
||||
|
||||
[Export]
|
||||
public float mouseMoveSpeed = 0.001f;
|
||||
|
||||
[Export]
|
||||
public bool flipHorizontal = false;
|
||||
|
||||
[Export]
|
||||
public bool flipVertical = false;
|
||||
|
||||
[Export]
|
||||
public bool moveAtBorders = true;
|
||||
|
||||
[Export]
|
||||
public float moveAtBorderSpeed = 0.001f;
|
||||
|
||||
[Export]
|
||||
public float borderSizePercentage = 5;
|
||||
|
||||
[ExportCategory("Orbit")]
|
||||
|
||||
[Export]
|
||||
public RJSensor orbitRightButton;
|
||||
|
||||
[Export]
|
||||
public RJSensor orbitLeftButton;
|
||||
|
||||
[Export]
|
||||
public RJSensor orbitMouseButton;
|
||||
|
||||
[Export]
|
||||
public float mouseOrbitSpeedScale = -0.5f;
|
||||
|
||||
[Export]
|
||||
public float orbitSpeed = 0.001f;
|
||||
|
||||
|
||||
[ExportCategory("Zoom")]
|
||||
|
||||
[Export]
|
||||
public float zoomStepInPercentage = 10;
|
||||
|
||||
[Export]
|
||||
public float minDistance = 0.001f;
|
||||
|
||||
[Export]
|
||||
public float maxDistance = 200f;
|
||||
|
||||
[Export]
|
||||
public RJSensor zoomInButton;
|
||||
|
||||
[Export]
|
||||
public RJSensor[] zoomInModifierButtons;
|
||||
|
||||
[Export]
|
||||
public RJSensor zoomOutButton;
|
||||
|
||||
[Export]
|
||||
public RJSensor[] zoomOutModifierButtons;
|
||||
|
||||
[Export]
|
||||
public float zoomSmoothingCoefficient = 0.1f;
|
||||
Smoother smoother = new Smoother();
|
||||
|
||||
public override void _Process( double delta )
|
||||
{
|
||||
Move();
|
||||
Orbit( (float) delta );
|
||||
Zoom();
|
||||
|
||||
Apply( (float) delta );
|
||||
|
||||
if ( ! hasMotionDelta )
|
||||
{
|
||||
motionDelta.X = 0;
|
||||
motionDelta.Y = 0;
|
||||
}
|
||||
|
||||
hasMotionDelta = false;
|
||||
}
|
||||
|
||||
bool hasMotionDelta = false;
|
||||
Vector2 motionDelta = Vector2.Zero;
|
||||
|
||||
float borderMoveHorizontal = 0;
|
||||
float borderMoveVertical = 0;
|
||||
|
||||
float GetBorderSize()
|
||||
{
|
||||
var size = GetViewport().GetVisibleRect().Size;
|
||||
|
||||
var borderX = ( size.X * borderSizePercentage ) / 100f;
|
||||
var borderY = ( size.Y * borderSizePercentage ) / 100f;
|
||||
|
||||
return Mathf.Min( borderX, borderY );
|
||||
}
|
||||
|
||||
public override void _Input( InputEvent inputEvent )
|
||||
{
|
||||
if ( inputEvent is InputEventMouseMotion )
|
||||
{
|
||||
var eventMouseMotion = inputEvent as InputEventMouseMotion;
|
||||
motionDelta = eventMouseMotion.ScreenRelative;
|
||||
|
||||
if ( moveAtBorders )
|
||||
{
|
||||
var position = eventMouseMotion.Position;
|
||||
|
||||
var screenSize = GetViewport().GetVisibleRect().Size;
|
||||
var borderSize = GetBorderSize();
|
||||
|
||||
borderMoveHorizontal = - MathX.PolarAxis( position.X < borderSize, position.X > screenSize.X - borderSize );
|
||||
borderMoveVertical = - MathX.PolarAxis( position.Y < borderSize, position.Y > screenSize.Y - borderSize );
|
||||
}
|
||||
|
||||
hasMotionDelta = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void Move()
|
||||
{
|
||||
var deltaX = 0f;
|
||||
var deltaY = 0f;
|
||||
|
||||
if ( Sensors.IsActive( mouseMoveButton ) )
|
||||
{
|
||||
deltaX = motionDelta.X * mouseMoveSpeed;
|
||||
deltaY = motionDelta.Y * mouseMoveSpeed;
|
||||
}
|
||||
else
|
||||
{
|
||||
deltaX = Sensors.PolarAxis( moveLeftButton, moveRightButton ) + borderMoveHorizontal * moveAtBorderSpeed;
|
||||
deltaY = Sensors.PolarAxis( moveUpButton, moveDownButton ) + borderMoveVertical * moveAtBorderSpeed;
|
||||
}
|
||||
|
||||
var forward = Math3D.GetYPlaneForward( this );
|
||||
var right = Math3D.GetYPlaneRight( this );
|
||||
|
||||
var flipH = flipHorizontal ? -1 : 1;
|
||||
var flipV = flipVertical ? -1 : 1;
|
||||
|
||||
var xAmount = deltaX * smoothDistance * right * flipH;
|
||||
var zAmount = deltaY * smoothDistance * forward * flipV;
|
||||
|
||||
target += ( xAmount + zAmount );
|
||||
|
||||
}
|
||||
|
||||
void Orbit( float delta )
|
||||
{
|
||||
var direction = Sensors.PolarAxis( orbitLeftButton, orbitRightButton );
|
||||
|
||||
if ( Sensors.IsActive( orbitMouseButton ) )
|
||||
{
|
||||
yaw += motionDelta.X * mouseOrbitSpeedScale;
|
||||
}
|
||||
|
||||
yaw += direction * orbitSpeed * delta;
|
||||
}
|
||||
|
||||
void Zoom()
|
||||
{
|
||||
var zoomButtonAxis = Sensors.PolarAxis( zoomOutButton, zoomInButton );
|
||||
|
||||
distance *= Mathf.Pow( 1 + zoomStepInPercentage / 100f, zoomButtonAxis );
|
||||
|
||||
distance = Mathf.Clamp( distance, minDistance, maxDistance );
|
||||
}
|
||||
|
||||
|
||||
void Apply( float delta )
|
||||
{
|
||||
smoothDistance = smoother.SmoothWithCoefficient( smoothDistance, distance, zoomSmoothingCoefficient, delta );
|
||||
GlobalRotation = new Vector3( Mathf.DegToRad( pitch ), Mathf.DegToRad( yaw ), 0 );
|
||||
|
||||
var forward = Math3D.GetGlobalForward( this ) * smoothDistance;
|
||||
GlobalPosition = target - forward;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -69,6 +69,7 @@ namespace Rokojori
|
|||
var position = new Vector3();
|
||||
var up = new Vector3();
|
||||
var forward = new Vector3();
|
||||
var fov = 0f;
|
||||
|
||||
_cameraSlots.ForEach(
|
||||
c =>
|
||||
|
@ -100,10 +101,12 @@ namespace Rokojori
|
|||
position += priority * c.camera.GetCameraPosition();
|
||||
up += priority * vUp;
|
||||
forward += priority * vForward;
|
||||
fov += priority * c.camera.GetCameraFOV();
|
||||
}
|
||||
);
|
||||
|
||||
position /= sumPriority;
|
||||
fov /= sumPriority;
|
||||
|
||||
if ( forward.LengthSquared() == 0 )
|
||||
{
|
||||
|
@ -126,6 +129,7 @@ namespace Rokojori
|
|||
|
||||
camera.GlobalPosition = position;
|
||||
camera.LookAt( position - forward, up );
|
||||
camera.Fov = fov;
|
||||
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue