Welcome, Guest
Username Password: Remember me

TOPIC: Transparency in Videos

Re: Transparency in Videos 4 days ago #203240

  • schrauber
  • OFFLINE
  • Platinum Boarder
  • Posts: 3224
  • 4 days ago
I think it should be implemented as an additional shader in the code. For this we have to deal with the actual main program of effects: the "Technique" at the bottom.

First you should test the pattern code to be adapted to Lightworks in a new effect, without the transparency effect.

The program from the linked website doesn't seem to provide real texture coordinates, so they have to be calculated there:
oid mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    // Normalized pixel coordinates (from 0 to 1)
    vec2 uv = fragCoord/iResolution.xy;


This is easier in Lightworks:
float4 ps_liquidWarp (float2 uv : TEXCOORD0) : COLOR
{


At the bottom is:
    // Output to screen
    fragColor = vec4(col,1.0);


For Lightworks this should look like this:
return float4(col,1.0);


But jwrl also developed similar effects whose code should be easier to implement.
fx-planet.ovh/effects/78/
Mainly automatically translated
--------------------------------------------
Windows 10, 64 Bit
Intel i5-4440 (3,1 GHz) ; Intel HD Graphics 4600
Last Edit: 4 days ago by schrauber.

Re: Transparency in Videos 4 days ago #203242

  • hugly
  • OFFLINE
  • Platinum Boarder
  • Posts: 20134
  • 4 days ago
Thank you.

Beside of "iChannel0", "iResolution.xy " is a another external global which has to be adapted somehow (it represents _OutputWidth, _OutputHeight I think) and I'm not sure if "tex2Dlod()" does the same as "textureLod()".

After digging a bit deeper into it I found additional difficulties and, I think, porting the effect based on my current knowledge is to complicated for me. I'll will give the existing effects from jwrl a shot, thanks for pointing me there. FractalMatte3 looks nice. I'll try that.

Thanks again.
It's better to travel well than to arrive...

Re: Transparency in Videos 3 days, 23 hours ago #203247

  • schrauber
  • OFFLINE
  • Platinum Boarder
  • Posts: 3224
  • 3 days, 23 hours ago
Okay.

A special thing of shader effect programming is that if you select `if ( ... ` two code, the GPU still processes both code. The result of the unnecessary calculation is not used, but the GPU load is higher.
Even functions that are called in the shader under only one `if ( ...` condition, are still processed by the GPU as soon as the "Technique" starts this shader.

With the simple codes that we have used so far this is not so important yet, but if at some point it can be more useful not to switch larger functionalities in the shader, but to select different shaders in the "Technique". These shaders can also be connected to complex internal routings with internal renderings in the "Technique".
It is even possible to create several internal shader routings, between which the user can switch in the effect settings.

github.com/FxSchrauber/Code_for_developing_Lightworks_effects/blob/master/Basics/Techniques/README.md
Mainly automatically translated
--------------------------------------------
Windows 10, 64 Bit
Intel i5-4440 (3,1 GHz) ; Intel HD Graphics 4600
Last Edit: 3 days, 23 hours ago by schrauber.

Re: Transparency in Videos 3 days, 6 hours ago #203330

  • hugly
  • OFFLINE
  • Platinum Boarder
  • Posts: 20134
  • 3 days, 6 hours ago
schrauber wrote:
It is even possible to create several internal shader routings, between which the user can switch in the effect settings.

I have seen this in the original Masked Blend effect and I understand that it's a good approach to switch between unrelated code-blocks without a main distributor and a lot of if's. I can even understand that some kind of parallel processing on separated data could be established that way, theoretically. What I don't understand is the benefit of separately compiled functions, if they call each other in a well defined logical order on the same data base, i.e. one function produces output which is used as input for the next one, and so forth?
It's better to travel well than to arrive...
Last Edit: 3 days, 6 hours ago by hugly.

Re: Transparency in Videos 3 days, 6 hours ago #203332

  • schrauber
  • OFFLINE
  • Platinum Boarder
  • Posts: 3224
  • 3 days, 6 hours ago
Do you mean functions that are called by the Shader or do you mean by "functions" the shaders themselves that are called by the "Technique"?
Mainly automatically translated
--------------------------------------------
Windows 10, 64 Bit
Intel i5-4440 (3,1 GHz) ; Intel HD Graphics 4600

Re: Transparency in Videos 3 days, 5 hours ago #203334

  • hugly
  • OFFLINE
  • Platinum Boarder
  • Posts: 20134
  • 3 days, 5 hours ago
I have no idea about the internals. What I understand from the code is that, same as in the C-language, every code block is a function. In C-language, by convention, a function named "main()" is used as single entry point to the compiled program. Here, the entry point seems to depend on 'Technique', which means that there can be more than one (typical for parallel processing). For one function compiled under 'Technique', that's clear to me (even for independent functions it is), but what if there are more (functions under 'Technique') and the data flow depends on each other.
It's better to travel well than to arrive...
Last Edit: 3 days, 5 hours ago by hugly.

Re: Transparency in Videos 3 days, 5 hours ago #203338

  • hugly
  • OFFLINE
  • Platinum Boarder
  • Posts: 20134
  • 3 days, 5 hours ago
To dive not too deep into grey theory, I'll merge an existing effect which operates on an independent database with EasyOverlay, and post the code so you can explain the missing links based on that.

That will take a while.
It's better to travel well than to arrive...
Last Edit: 3 days, 5 hours ago by hugly.

Re: Transparency in Videos 3 days, 4 hours ago #203345

  • schrauber
  • OFFLINE
  • Platinum Boarder
  • Posts: 3224
  • 3 days, 4 hours ago
Okay, you mean the shaders.

The pattern functions we have used are not used by the technique, so for some time now we have been placing them in different places in the code for better differentiation, and using different prefixes ps_ for shaders, and fn_ for functions used by shaders.

hugly wrote:
What I don't understand is the benefit of separately compiled functions, if they call each other in a well defined logical order on the same data base, i.e. one function produces output which is used as input for the next one, and so forth?


There are several reasons.

Often you need an internally rendered texture to get samples of different shaders in the next one. For example, blur effects where the texture becomes blurrier with each shader pass.

Another reason that is often used in slightly older effects is that a shader can't process an unlimited amount of code. In this case, especially before LW 14.5, the code was split into several shaders. Under Windows this depends on the shader profile set in the Technique. With 3.0 is not so problematic.
Functions called by the shader are not a solution to extend the shader limit, because this code has to be added to the shader limit as well (maybe even a bit more). If a shader reaches the limit, the GPU load can double with a few lines of code. Especially in this case switching to a higher shader model will reduce the GPU load considerably. But it is also a question of compatibility with older Lightworks versions.

If the limit of the shader is exceeded, the effect is not compiled.

However, it is a balancing of advantages and disadvantages.
Processing code completely in a single shader has the advantage that even with an 8-bit GPU precision setting, 32 bits per color can be calculated internally.
Also, already calculated variables can be used throughout the code without having to recalculate them in the next shader.
In addition, the internal rendering and sampling for the next shader also requires an additional GPU load.

However, switching from independent shaders has the big advantage that unneeded code does not burden the GPU.

Of course, it's better to see code examples.
Mainly automatically translated
--------------------------------------------
Windows 10, 64 Bit
Intel i5-4440 (3,1 GHz) ; Intel HD Graphics 4600
Last Edit: 3 days, 4 hours ago by schrauber.

Re: Transparency in Videos 3 days, 4 hours ago #203347

  • hugly
  • OFFLINE
  • Platinum Boarder
  • Posts: 20134
  • 3 days, 4 hours ago
I merged jwrl's FractalMatte3.fx with EasyOverlayNext2. Made some minor changes and commented them with " /**change**/ ".

If I compile it with techniques in this order, it shows the result of EasyOverlayNext2:

technique ps { pass SinglePass { PixelShader = compile PROFILE oa_main(); } }
technique FractalMatte3
{
   pass P_1
   < string Script = "RenderColorTarget0 = Matte;"; >
   { PixelShader = compile PROFILE ps_fractal (); }

   pass P_2
   { PixelShader = compile PROFILE ps_FractalMatte (); }}


Compiling in this order shows the behaviour of FractalMatte3.

technique FractalMatte3
{
   pass P_1
   < string Script = "RenderColorTarget0 = Matte;"; >
   { PixelShader = compile PROFILE ps_fractal (); }

   pass P_2
   { PixelShader = compile PROFILE ps_FractalMatte (); }}
technique ps { pass SinglePass { PixelShader = compile PROFILE oa_main(); } }

Consequently, both blocks work properly. My question is how to modify the code in order to see the behaviour of EasyOverlay and to use the results of FractalMatte3 only as background if 'Select Bg' is switched to 'Fractal Matte'?

That's the code:

// @Maintainer hugly
// @Released 2019-08-12
// @Author hugly, schrauber
// @Created 2019-08-09
// @see

/**
'EasyOverlay' is a luminance keyer for overlays which show luminance for transparency, i.e. full transparency appears as solid black in the overlay. The keyer works also on overlays with alpha channel. It reveals transparency using a black&white mask created from the foreground.

The presets should work for most material of that kind with good looking results. If adjustments should be necessary, start with 'MaskGain'. 'Fg Lift' influences overall brightness of the overly while preserving the highlights. 'Fg Opacity' is e.g. useful to dissolve from/to the overerlay using keyframes.
*/

//--------------------------------------------------------------//
// EasyOverlay.fx
//
// Version history:
// next2 
//		static background patterns and alpha export
// next3
// 		dynamic background: jwrl's FractalMatte3fx
//--------------------------------------------------------------//

int _LwksEffectInfo
<  string EffectGroup = "GenericPixelShader";
   string Description = "EasyOverlayNext3";
   string Category    = "Key";
   string SubCategory = "Key Extras";
   string Notes       = "For overlays where luminance represents transparancy";
> = 0;

//--------------------------------------------------------------//
// Globals
//--------------------------------------------------------------//

#define PI  3.141592654
float _OutputAspectRatio;

//--------------------------------------------------------------//
// Parameters
//--------------------------------------------------------------//

float MaskGain
<  string Description = "Mask Gain";
   float MinVal = 0.0;
   float MaxVal = 6.0;
> = 3;

float FgLift
<  string Description = "Fg Lift";
   float MinVal =  -1.0;
   float MaxVal =   1.0;
> = 0;

float FgOpacity
<  string Description = "Fg Opacity";
   float MinVal = 0.0;
   float MaxVal = 1.0;
> = 1;

int SelectBg
<
   string Description = "Select Bg";
   string Enum = "Bg Input,"
                 "50% Diamond Pattern,"
				 "90% Luminance,"
				 "10% Luminance,"
                 "Alpha Channel,"
				 "FractalMatte";
> = 0;

/** bool EnableBgPattern
<	
	string Description = "Enable Bg Pattern";
> = false;
*/

//--------------------------------------------------------------//
// Inputs
//--------------------------------------------------------------//

texture fg;
texture bg;

sampler FgSampler   = sampler_state { Texture = <fg>; };
sampler BgSampler   = sampler_state { Texture = <bg>; };

//--------------------------------------------------------------//
// Code
//--------------------------------------------------------------//

float4 setFgLift (float4 x, float lift)
{  lift *= 0.55;
   float3 gamma1 = 1.0 - pow ( 1.0 - x.rgb, 1.0 / max ((1.0 - lift), 1E-6));
   float3 gamma2 =       pow ( x.rgb , 1.0      / max (lift + 1.0, 1E-6));
   float3 gamma = (lift > 0) ? gamma1 : gamma2;
   gamma =  saturate (lerp ( gamma , (gamma1 + gamma2) / 2.0, 0.8));
   return float4 (gamma.rgb, x.a);
}

float3 fn_diamondPattern (float2 uv, float3 color1, float3 color2, float numberH, float edgeSharpness)
{  
   float2 mix = float2 (uv.x + (uv.y / _OutputAspectRatio) , 0.0);
   mix.y = uv.x - (uv.y / _OutputAspectRatio);
   mix = sin (mix * PI * numberH ) * edgeSharpness / numberH;
   mix =  clamp( mix, -0.5, 0.5) + 0.5;
   return (lerp (color1, color2, lerp( mix.y , 1.0 - mix.y, mix.x)));
}

float4 oa_main( float2 xy0 : TEXCOORD0, float2 xy1 : TEXCOORD1, float2 xy2 : TEXCOORD2 ) : COLOR 
{  
   float4 fg = tex2D( FgSampler, xy1 );
   float4 bg = tex2D( BgSampler, xy2 );
   float4 mask = fg; 

   fg = setFgLift (fg, FgLift);
   float alpha = mask.a * min ((( mask.r + mask.g + mask.b ) / 3.0) * MaskGain, 1.0);		

   if (SelectBg == 1) bg = float4 (fn_diamondPattern (xy0, 0.4, 0.6, 120, 1000.0), 1.0);
   if (SelectBg == 2) bg = float4 (0.90.xxx, 1.0);
   if (SelectBg == 3) bg = float4 (0.10.xxx, 1.0);

   float4 ret = lerp( bg, fg, alpha * FgOpacity);

   if (SelectBg == 4)
      ret = float4 (fg.rgb, alpha * FgOpacity);
   else
		ret.a = 1.0;
   return ret;
}


//-----------------------------------------------------------------------------------------//
// FractalMatte Start
//-----------------------------------------------------------------------------------------//
//-----------------------------------------------------------------------------------------//
// Inputs
//-----------------------------------------------------------------------------------------//

// texture Fg; /**change**/

texture Matte : RenderColorTarget;

//-----------------------------------------------------------------------------------------//
// Samplers 
//-----------------------------------------------------------------------------------------//

// sampler s_Input = sampler_state { Texture = <Fg>; }; /**change**/
sampler s_Input = sampler_state { Texture = <fg>; };
sampler s_Matte = sampler_state { Texture = <Matte>; };

//-----------------------------------------------------------------------------------------//
// Parameters
//-----------------------------------------------------------------------------------------//

float Opacity
<
   string Description = "Opacity";   
   string Group = "Matte"; /**change**/
   float MinVal = 0.0;
   float MaxVal = 1.0;
> = 1.0;

float FracOffs
<
   string Description = "Fractal offset";   
   string Group = "Matte"; /**change**/
   float MinVal = 0.00;
   float MaxVal = 1.00;
> = 0.0;

float FracRate
<
   string Description = "Fractal rate";   
   string Group = "Matte"; /**change**/
   float MinVal = 0.00;
   float MaxVal = 1.00;
> = 0.5;

float4 Colour
<
   string Description = "Mix colour";
   string Group = "Matte"; /**change**/
   bool SupportsAlpha = true;
> = { 1.0, 0.77, 0.19, 1.0 };

float ColourMix
<
   string Description = "Mix level";
   string Group = "Matte"; /**change**/
   float MinVal = 0.0;
   float MaxVal = 1.0;
> = 0.0;

float HueParam
<
   string Description = "Hue";
   string Group = "Matte"; /**change**/
   float MinVal = -1.0;
   float MaxVal = 1.0;
> = 0.0;

float SatParam
<
   string Description = "Saturation";
   string Group = "Matte"; /**change**/
   float MinVal = -1.0;
   float MaxVal = 1.0;
> = 0.0;

float Gain
<
   string Description = "Gain";
   string Group = "Matte"; /**change**/
   float MinVal = 0.00;
   float MaxVal = 4.00;
> = 1.0;

float Gamma
<
   string Description = "Gamma";
   string Group = "Matte"; /**change**/
   float MinVal = 0.0;
   float MaxVal = 4.00;
> = 1.00;

float Brightness
<
   string Description = "Brightness";
   string Group = "Matte"; /**change**/
   float MinVal = -1.00;
   float MaxVal = 1.00;
> = 0.0;

float Contrast
<
   string Description = "Contrast";
   string Group = "Matte"; /**change**/
   float MinVal = 0.00;
   float MaxVal = 4.00;
> = 1.0;

//-----------------------------------------------------------------------------------------//
// Definitions and declarations
//-----------------------------------------------------------------------------------------//

#define PI_2     6.283185

#define INVSQRT3 0.57735

#define R_WEIGHT 0.2989
#define G_WEIGHT 0.5866
#define B_WEIGHT 0.1145

float _Progress;

//-----------------------------------------------------------------------------------------//
// Shaders
//-----------------------------------------------------------------------------------------//

float4 ps_fractal (float2 xy : TEXCOORD) : COLOR
{
   float speed = _Progress * FracRate;
   float4 retval = 1.0.xxxx;
   float3 f = float3 (xy, FracOffs);

   for (int i = 0; i < 75; i++) {
      f.xzy = float3 (1.3, 0.999, 0.7) * (abs ((abs (f) / dot (f, f) - float3 (1.0, 1.0, speed * 0.5))));
   }

   retval.rgb = f;

   return retval;
}

float4 ps_FractalMatte (float2 uv : TEXCOORD, float2 xy : TEXCOORD1) : COLOR /**change**/
{
   float4 Fgd    = tex2D (s_Input, xy);
   float4 retval = tex2D (s_Matte, uv);

   float luma   = dot (retval.rgb, float3 (R_WEIGHT, G_WEIGHT, B_WEIGHT));
   float buffer = dot (Colour.rgb, float3 (R_WEIGHT, G_WEIGHT, B_WEIGHT));

   buffer = saturate (buffer - 0.5);
   buffer = 1 / (buffer + 0.5);

   float4 temp = Colour * luma * buffer;

   retval = lerp (retval, temp, ColourMix);
   luma = (retval.r + retval.g + retval.b) / 3.0;

   float RminusG = retval.r - retval.g;
   float RminusB = retval.r - retval.b;
   float GammVal = (Gamma > 1.0) ? Gamma : Gamma * 0.9 + 0.1;
   float Hue_Val = acos ((RminusG + RminusB) / (2.0 * sqrt (RminusG * RminusG + RminusB * (retval.g - retval.b)))) / PI_2;
   float Sat_Val = 1.0 - min (min (retval.r, retval.g), retval.b) / luma;

   if (retval.b > retval.g) Hue_Val = 1.0 - Hue_Val;

   Hue_Val = frac (Hue_Val + (HueParam * 0.5));
   Sat_Val = saturate (Sat_Val * (SatParam + 1.0));

   float Hrange = Hue_Val * 3.0;
   float Hoffst = (2.0 * floor (Hrange) + 1.0) / 6.0;

   buffer = INVSQRT3 * tan ((Hue_Val - Hoffst) * PI_2);
   temp.x = (1.0 - Sat_Val) * luma;
   temp.y = ((3.0 * (buffer + 1.0)) * luma - (3.0 * buffer + 1.0) * temp.x) / 2.0;
   temp.z = 3.0 * luma - temp.y - temp.x;

   retval = (Hrange < 1.0) ? temp.zyxw : (Hrange < 2.0) ? temp.xzyw : temp.yxzw;
   temp   = (((pow (retval, 1.0 / GammVal) * Gain) + Brightness.xxxx - 0.5.xxxx) * Contrast) + 0.5.xxxx;
   retval = lerp (Fgd, temp, Opacity);

   retval.a = Fgd.a;

   return retval;
}
//-----------------------------------------------------------------------------------------//
// Fractal Matte END
//-----------------------------------------------------------------------------------------//

//-----------------------------------------------------------------------------------------//
// Techniques
//-----------------------------------------------------------------------------------------//
technique ps { pass SinglePass { PixelShader = compile PROFILE oa_main(); } }
technique FractalMatte3
{
   pass P_1
   < string Script = "RenderColorTarget0 = Matte;"; >
   { PixelShader = compile PROFILE ps_fractal (); }

   pass P_2
   { PixelShader = compile PROFILE ps_FractalMatte (); } /**change**/
}


Edit: I missed to mark the change of the name of the main function of FractalMatte at two locations, that's corrected. Hopefully, I didn't miss to mark some other change (I didn't touch code within functions at all).
It's better to travel well than to arrive...
Last Edit: 3 days, 3 hours ago by hugly.

Re: Transparency in Videos 3 days, 3 hours ago #203349

  • hugly
  • OFFLINE
  • Platinum Boarder
  • Posts: 20134
  • 3 days, 3 hours ago
Slightly off topic:

I found something potentially interesting, a GLSL to HLSL cross compiler:

github.com/septag/glslcc

Don't know if this will help solving the problems I had when trying to port the GLSL code from shadertoys, but maybe worth a try.
It's better to travel well than to arrive...

Re: Transparency in Videos 3 days, 1 hour ago #203359

  • schrauber
  • OFFLINE
  • Platinum Boarder
  • Posts: 3224
  • 3 days, 1 hour ago
Ok, I copied your code into my own GitHub repository, then replaced the code with my changes. This has the advantage that GitHub can automatically highlight all changes in color (history).

Here is the version I changed: github.com/FxSchrauber/lwks-fx/blob/master/Test%20code%20in%20common%20development/test-20190815.fx

Click on "History" to see my changes.

Note that this code is not yet optimized for GPU efficiency (we can do that in the next step).

From FractalMatte I have removed the foreground, and many related settings, because in this case your own ps_oa - shader is responsible for mixing the foreground with the background.

For the Technique, I have chosen a layout in which each shader pass is displayed in one line. On the left side, the texture buffer is defined where the output of the pixel shader occurs. If there is not, then this shader directly to the effect output.
The shader is defined on the right-hand side and with which PROFILE it should work.


technique test01
{
   pass P_1  < string Script = "RenderColorTarget0 = Fractal;"; > { PixelShader = compile PROFILE ps_fractal (); }
   pass P_2  < string Script = "RenderColorTarget0 = Matte;"  ; > { PixelShader = compile PROFILE ps_FractalMatte (); }
   pass P_3                                                       { PixelShader = compile PROFILE ps_oa(); } 
}


EDIT: If you want to continue working on it directly in GitHub, I could arrange for GitHub to send you an invitation as a contributor.
Alternatively, you can do it in your own repository, etc.
Mainly automatically translated
--------------------------------------------
Windows 10, 64 Bit
Intel i5-4440 (3,1 GHz) ; Intel HD Graphics 4600
Last Edit: 3 days ago by schrauber.

Re: Transparency in Videos 3 days ago #203366

  • hugly
  • OFFLINE
  • Platinum Boarder
  • Posts: 20134
  • 3 days ago
That looks good. Thank you.

Your explanation above helps , but I'll have to look more intensively into the code to understand the changes and the resulting flow. That will take a while.

I'm not familiar with working on Github. In a later stage I can image that I'll start learning it, but for the moment I'd like to stay with my local tools. Step by step.

Currently, FractalMatte is driven by progress, the duration of the effect influences speed of variation of the image. Is there any variable representing a time base which could be used to control the variation in order to make it independent from the duration of the effect (maybe even framrate)?

Is there a way to start a group on the panel (here "Matte") collapsed or, even better, to show it only if "SelectBg" shows "FractalMatte"?
It's better to travel well than to arrive...
Last Edit: 3 days ago by hugly.

Re: Transparency in Videos 2 days, 23 hours ago #203370

  • schrauber
  • OFFLINE
  • Platinum Boarder
  • Posts: 3224
  • 2 days, 23 hours ago
hugly wrote:
Currently, FractalMatte is driven by progress, the duration of the effect influences speed of variation of the image. Is there any variable representing a time base which could be used to control the variation in order to make it independent from the duration of the effect (maybe even framrate)?

Yes, since 14.5 there are "Auto-synced parameters" which contain the effect runtime in frames or seconds.
This allows you to correct this mathematically.

hugly wrote:
Is there a way to start a group on the panel (here "Matte") collapsed or, even better, to show it only if "SelectBg" shows "FractalMatte"?
Unfortunately not to my knowledge
Mainly automatically translated
--------------------------------------------
Windows 10, 64 Bit
Intel i5-4440 (3,1 GHz) ; Intel HD Graphics 4600
Last Edit: 2 days, 23 hours ago by schrauber.

Re: Transparency in Videos 2 days, 23 hours ago #203372

  • hugly
  • OFFLINE
  • Platinum Boarder
  • Posts: 20134
  • 2 days, 23 hours ago
schrauber wrote:
Yes, since 14.5 there are "Auto-synced parameters" which contain the effect runtime in frames or seconds.

I forgot that you've linked to those already earlier.

float _Progress;
float _OutputWidth;
float _OutputHeight;
float _OutputAspectRatio;
float _OutputFPS;
float _Length;
float _LengthFrames;


I'll try to find a good looking result independent from effects duration based on those. Will report how that works.
It's better to travel well than to arrive...
Last Edit: 2 days, 23 hours ago by hugly.

Re: Transparency in Videos 2 days, 23 hours ago #203373

  • hugly
  • OFFLINE
  • Platinum Boarder
  • Posts: 20134
  • 2 days, 23 hours ago
However, due to some limitations it will be difficult to implement variations on a constant time base which shows in preview what I will see in export, for all cases.

github.com/FxSchrauber/Code_for_developing_Lightworks_effects/blob/master/Basics/Variables_etc/Auto_synced/_Length.md
It's better to travel well than to arrive...
Last Edit: 2 days, 23 hours ago by hugly.
Time to create page: 0.48 seconds
Scroll To Top