Files
2026-09-21 12:15:57 +03:00

202 lines
7.5 KiB
Plaintext

<#@ template language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ output extension=".cs" #>
<#
var sizes = new int[]
{
32, 64, 128, 512, 4096
};
#>
using Unity.Collections;
using Unity.Burst;
using Unity.Mathematics;
using Unity.Collections.LowLevel.Unsafe;
namespace LitMotion
{
internal static partial class FixedStringHelper
{
<# foreach(var size in sizes) { #>
[BurstCompile]
public static int GetUtf8CharCount(ref FixedString<#=size#>Bytes runes)
{
int length = 0;
var enumerator = runes.GetEnumerator();
while (enumerator.MoveNext()) length++;
return length;
}
static Unicode.Rune GetRuneOf(ref FixedString<#=size#>Bytes text, int charIndex)
{
int index = 0;
var enumerator = text.GetEnumerator();
while (enumerator.MoveNext())
{
if (index == charIndex) return enumerator.Current;
index++;
}
return Unicode.BadRune;
}
[BurstCompile]
public static void Interpolate(ref FixedString<#=size#>Bytes start, ref FixedString<#=size#>Bytes end, float t, ScrambleMode scrambleMode, bool richTextEnabled, ref Random randomState, ref FixedString64Bytes customScrambleChars, out FixedString<#=size#>Bytes result)
{
if (richTextEnabled)
{
RichTextParser.GetSymbols(ref start, Allocator.Temp, out var startTextSymbols, out var startTextUtf8Length);
RichTextParser.GetSymbols(ref end, Allocator.Temp, out var endTextSymbols, out var endTextUtf8Length);
FillRichText(ref startTextSymbols, ref endTextSymbols, startTextUtf8Length, endTextUtf8Length, t, scrambleMode, ref randomState, ref customScrambleChars, out result);
startTextSymbols.Dispose();
endTextSymbols.Dispose();
}
else
{
FillText(ref start, ref end, t, scrambleMode, ref randomState, ref customScrambleChars, out result);
}
}
unsafe static void FillText(
ref FixedString<#=size#>Bytes start,
ref FixedString<#=size#>Bytes end,
float t,
ScrambleMode scrambleMode,
ref Random randomState,
ref FixedString64Bytes customScrambleChars,
out FixedString<#=size#>Bytes result)
{
var startTextUtf8Length = GetUtf8CharCount(ref start);
var endTextUtf8Length = GetUtf8CharCount(ref end);
var length = math.max(startTextUtf8Length, endTextUtf8Length);
var currentTextLength = (int)math.round(length * t);
var enumeratorStart = start.GetEnumerator();
var enumeratorEnd = end.GetEnumerator();
result = new();
for (int i = 0; i < length; i++)
{
var startMoveNext = enumeratorStart.MoveNext();
var endMoveNext = enumeratorEnd.MoveNext();
if (i < currentTextLength)
{
if (endMoveNext)
{
result.Append(enumeratorEnd.Current);
}
}
else
{
if (startMoveNext)
{
result.Append(enumeratorStart.Current);
}
}
}
FillScrambleChars(ref result, scrambleMode, ref randomState, ref customScrambleChars, length - currentTextLength);
}
unsafe static void FillRichText(
ref UnsafeList<RichTextSymbol<#=size#>Bytes> startSymbols,
ref UnsafeList<RichTextSymbol<#=size#>Bytes> endSymbols,
int startTextUtf8Length,
int endTextUtf8Length,
float t,
ScrambleMode scrambleMode,
ref Random randomState,
ref FixedString64Bytes customScrambleChars,
out FixedString<#=size#>Bytes result)
{
var length = math.max(startTextUtf8Length, endTextUtf8Length);
var currentTextLength = (int)math.round(length * t);
var slicedText1 = SliceSymbols(ref endSymbols, 0, currentTextLength, out var length1);
var slicedText2 = SliceSymbols(ref startSymbols, currentTextLength + 1, length - 1, out var length2);
result = new FixedString<#=size#>Bytes();
result.Append(slicedText1);
result.Append(slicedText2);
FillScrambleChars(ref result, scrambleMode, ref randomState, ref customScrambleChars, length - (length1 + length2));
}
unsafe static void FillScrambleChars(
ref FixedString<#=size#>Bytes target,
ScrambleMode scrambleMode,
ref Random randomState,
ref FixedString64Bytes customScrambleChars,
int count)
{
if (scrambleMode == ScrambleMode.None) return;
if (randomState.state == 0) randomState.InitState();
if (scrambleMode == ScrambleMode.Custom)
{
var customScrambleCharsUtf8Length = GetUtf8CharCount(ref customScrambleChars);
for (int i = 0; i < count; i++)
{
target.Append(GetRuneOf(ref customScrambleChars, randomState.NextInt(0, customScrambleCharsUtf8Length)));
}
}
else
{
for (int i = 0; i < count; i++)
{
target.Append(GetScrambleChar(scrambleMode, ref randomState));
}
}
}
unsafe static FixedString<#=size#>Bytes SliceSymbols(ref UnsafeList<RichTextSymbol<#=size#>Bytes> symbols, int from, int to, out int resultRichTextLength)
{
var text = new FixedString<#=size#>Bytes();
RichTextSymbol<#=size#>Bytes* symbolsPtr = symbols.Ptr;
var offset = 0;
var tagIndent = 0;
resultRichTextLength = 0;
for (int i = 0; i < symbols.Length; i++)
{
RichTextSymbol<#=size#>Bytes* symbol = symbolsPtr + i;
switch (symbol->Type)
{
case RichTextSymbolType.Text:
var enumerator = symbol->Text.GetEnumerator();
while (enumerator.MoveNext())
{
var current = enumerator.Current;
if (from <= offset && offset < to)
{
text.Append(current);
resultRichTextLength++;
}
offset++;
if (offset >= to && tagIndent == 0) goto LOOP_END;
}
break;
case RichTextSymbolType.TagStart:
text.Append(symbol->Text);
tagIndent++;
break;
case RichTextSymbolType.TagEnd:
text.Append(symbol->Text);
tagIndent--;
if (offset >= to && tagIndent == 0) goto LOOP_END;
break;
}
}
LOOP_END:
return text;
}
<# } #>
}
}