using Godot; using System; using Rokojori.Extensions; namespace Rokojori { /** Blend modes for a TextureStackLayer. The first four are *native* modes: BlitMaterial carries them as a runtime blend_mode, so they need no shader at all and no ping-pong buffer - the hardware blends the layer straight onto the accumulation. The remaining six have no hardware equivalent and are computed in TextureStackComposite.gdshader, which needs the accumulation handed in as a source texture (see TextureStackCompositor.NeedsCompositeShader). The formulas mirror the CPU predecessor in Procedural/Textures/TextureCombiner ( TextureCombinerBlendMode / TextureCombinerBlendModeAlgorithm / ColorX.Blend* ). Two copies of the same math exist on purpose - see the note in TextureStack.gdshaderinc - so a fix to one belongs in the other as well. Order matches the int values the composite shader switches on. Do not renumber without updating TextureStack.gdshaderinc. */ public enum TextureStackBlendMode { // Native - BlitMaterial.BlendModeEnum, no shader needed. Mix = 0, Add = 1, Sub = 2, Multiply = 3, // In-shader only, require the accumulation as a source. Screen = 4, Overlay = 5, HardLight = 6, SoftLight = 7, Color = 8, Hue = 9 } public static class TextureStackBlendModeX { /** True for the four modes BlitMaterial can do in hardware. Note this says nothing about whether the *layer* can take the native path - a mask, clip-to-below or a non-trivial alpha requirement still forces the composite shader. TextureStackCompositor decides that. */ public static bool IsNative( this TextureStackBlendMode mode ) { return mode == TextureStackBlendMode.Mix || mode == TextureStackBlendMode.Add || mode == TextureStackBlendMode.Sub || mode == TextureStackBlendMode.Multiply; } /** Spike finding G5/constraint 2: the hardware blend applies to alpha too, so Add and Sub drive the target's alpha somewhere unintended even with a fully opaque source. Only safe where the target's alpha does not matter. */ public static bool NativePreservesAlpha( this TextureStackBlendMode mode ) { return mode == TextureStackBlendMode.Mix; } public static BlitMaterial.BlendModeEnum ToBlitBlendMode( this TextureStackBlendMode mode ) { switch ( mode ) { case TextureStackBlendMode.Mix: return BlitMaterial.BlendModeEnum.Mix; case TextureStackBlendMode.Add: return BlitMaterial.BlendModeEnum.Add; case TextureStackBlendMode.Sub: return BlitMaterial.BlendModeEnum.Sub; case TextureStackBlendMode.Multiply: return BlitMaterial.BlendModeEnum.Mul; } return BlitMaterial.BlendModeEnum.Mix; } } }