rokojori_action_library/Runtime/Procedural/Textures/TextureStack/TextureStackPlacement.cs

107 lines
3.4 KiB
C#
Raw Normal View History

using Godot;
using System;
using Rokojori.Extensions;
namespace Rokojori
{
/** One blit a layer contributes - where it goes, and how the shader should
read its content there.
A plain layer produces exactly one of these. A layer with
TextureStackStamps produces one per stamp, plus the extra copies edge
wrapping needs.
Layers fill in <code>rect</code> <marked>unclipped</marked> and leave
uvRect alone; TextureStackCompositor then clips the rect against the
output and derives uvRect from the two. That split is what lets a stamp
hang off the output's edge: the blit shrinks to the visible part, but
uvRect tells the shader which slice of the stamp that part is, so the
content and the masks stay aligned with the whole stamp instead of being
squeezed into the sliver. Without it, UV being rect-local (spike gate G6)
would silently scale every clipped placement.
*/
public struct TextureStackPlacement
{
/** Identity uvRect: this blit covers the whole placement. */
public static readonly Vector4 fullUVRect = new Vector4( 0, 0, 1, 1 );
/** Image space. Set by the layer unclipped, replaced by the compositor with
the part that actually lies inside the output.
*/
public Rect2I rect;
/** What rect was before clipping. Layers that generate content at the
placement's resolution - a nested stack - have to work at this size and
then show the uvRect slice of it, or their own full-texture layers would
fill the visible sliver instead of the whole placement.
*/
public Rect2I unclippedRect;
/** offset.xy / scale.zw - the slice of the placement that rect covers.
Filled in by the compositor.
*/
public Vector4 uvRect;
/** Extra content rotation in radians, on top of the layer's own. Non-zero
only for scattered stamps.
Note this rotates the content *inside* an axis-aligned rect, so a
non-square stamp gets cropped at its corners - keep scattered stamps
square, or leave rotation variation at 0.
*/
public float rotation;
/** Which stamp this is, 0 for a plain layer. Wrapped copies keep the index
of the stamp they belong to, so they draw identically.
*/
public int index;
public static TextureStackPlacement At( Rect2I rect, int index = 0, float rotation = 0 )
{
var placement = new TextureStackPlacement();
placement.rect = rect;
placement.unclippedRect = rect;
placement.uvRect = fullUVRect;
placement.rotation = rotation;
placement.index = index;
return placement;
}
/** Clips against the output and works out which slice of the original rect
survived. Returns false when nothing of it is visible.
*/
public bool ClipTo( Rect2I bounds )
{
var unclipped = rect;
unclippedRect = unclipped;
if ( unclipped.Size.X <= 0 || unclipped.Size.Y <= 0 )
{
return false;
}
var clipped = unclipped.Intersection( bounds );
if ( clipped.Size.X <= 0 || clipped.Size.Y <= 0 )
{
return false;
}
rect = clipped;
uvRect = new Vector4(
( clipped.Position.X - unclipped.Position.X ) / (float) unclipped.Size.X,
( clipped.Position.Y - unclipped.Position.Y ) / (float) unclipped.Size.Y,
clipped.Size.X / (float) unclipped.Size.X,
clipped.Size.Y / (float) unclipped.Size.Y
);
return true;
}
}
}