// Generated by ShaderCompiler (--emit-fixed-function gu). Do not edit manually.
#pragma once

#if defined(WITH_RHI_GU)

#include "../../nCine/Graphics/RHI/FixedFunctionPass.h"

#include <cmath>
#include <cstddef>

// The including device file provides the concrete EffectContext (see the contract in
// FixedFunctionPass.h) with a "using EffectContext = ...;" alias BEFORE this include.

namespace nCine::RHI::GU
{
	/**
		One generated fixed-function effect: the (program, variant) it implements, whether any of
		its passes can write an offset colour (the PVR compiles specular into the base polygon
		header, so this is needed before any pass runs), which optional EffectContext facilities
		the function can ever call (so Dispatch skips the setup for the rest), and either its
		function or the backend pipeline stage a "pipeline <name>;" block bound it to (never
		both). Byte-identical bodies are emitted once and shared by all their rows.

		Defined at namespace scope (unlike the functions and the table below) so the backend's
		ShaderProgram can forward-declare it and store a resolved entry pointer; only this
		translation unit ever sees the definition.
	*/
	struct FixedFunctionGeneratedEffect { const char* Program; const char* Variant; bool UsesOffsetColor; FixedFunctionRequirements Requirements; FixedFunctionIntrinsic Intrinsic; void (*Fn)(EffectContext&); };

	namespace
	{
		// Minimal GLSL-style float-vector runtime for the generated effect functions. Defined in the
		// generated header (not shipped as an engine header) so the artifact stays self-contained:
		// FixedFunctionPass.h remains the only contract between the generator and the backends.
		namespace ff
		{
			struct vec2
			{
				float x, y;
				vec2() : x(0.0f), y(0.0f) {}
				explicit vec2(float s) : x(s), y(s) {}
				vec2(float x_, float y_) : x(x_), y(y_) {}
			};
			struct vec3
			{
				float x, y, z;
				vec3() : x(0.0f), y(0.0f), z(0.0f) {}
				explicit vec3(float s) : x(s), y(s), z(s) {}
				vec3(float x_, float y_, float z_) : x(x_), y(y_), z(z_) {}
				vec3(const vec2& v, float z_) : x(v.x), y(v.y), z(z_) {}
				vec3(float x_, const vec2& v) : x(x_), y(v.x), z(v.y) {}
				vec2 xy() const { return vec2(x, y); }
			};
			struct vec4
			{
				float x, y, z, w;
				vec4() : x(0.0f), y(0.0f), z(0.0f), w(0.0f) {}
				explicit vec4(float s) : x(s), y(s), z(s), w(s) {}
				vec4(float x_, float y_, float z_, float w_) : x(x_), y(y_), z(z_), w(w_) {}
				vec4(const vec2& v, float z_, float w_) : x(v.x), y(v.y), z(z_), w(w_) {}
				vec4(float x_, const vec2& v, float w_) : x(x_), y(v.x), z(v.y), w(w_) {}
				vec4(float x_, float y_, const vec2& v) : x(x_), y(y_), z(v.x), w(v.y) {}
				vec4(const vec2& a, const vec2& b) : x(a.x), y(a.y), z(b.x), w(b.y) {}
				vec4(const vec3& v, float w_) : x(v.x), y(v.y), z(v.z), w(w_) {}
				vec4(float x_, const vec3& v) : x(x_), y(v.x), z(v.y), w(v.z) {}
				vec2 xy() const { return vec2(x, y); }
				vec2 zw() const { return vec2(z, w); }
				vec3 xyz() const { return vec3(x, y, z); }
				vec3 yzw() const { return vec3(y, z, w); }
			};

			inline vec2 operator+(const vec2& a, const vec2& b) { return vec2(a.x + b.x, a.y + b.y); }
			inline vec2 operator-(const vec2& a, const vec2& b) { return vec2(a.x - b.x, a.y - b.y); }
			inline vec2 operator*(const vec2& a, const vec2& b) { return vec2(a.x * b.x, a.y * b.y); }
			inline vec2 operator/(const vec2& a, const vec2& b) { return vec2(a.x / b.x, a.y / b.y); }
			inline vec2 operator+(const vec2& a, float s) { return vec2(a.x + s, a.y + s); }
			inline vec2 operator-(const vec2& a, float s) { return vec2(a.x - s, a.y - s); }
			inline vec2 operator*(const vec2& a, float s) { return vec2(a.x * s, a.y * s); }
			inline vec2 operator/(const vec2& a, float s) { return vec2(a.x / s, a.y / s); }
			inline vec2 operator+(float s, const vec2& a) { return vec2(s + a.x, s + a.y); }
			inline vec2 operator-(float s, const vec2& a) { return vec2(s - a.x, s - a.y); }
			inline vec2 operator*(float s, const vec2& a) { return vec2(s * a.x, s * a.y); }
			inline vec2 operator/(float s, const vec2& a) { return vec2(s / a.x, s / a.y); }
			inline vec2 operator-(const vec2& a) { return vec2(-a.x, -a.y); }
			inline vec2& operator+=(vec2& a, const vec2& b) { a.x += b.x; a.y += b.y; return a; }
			inline vec2& operator-=(vec2& a, const vec2& b) { a.x -= b.x; a.y -= b.y; return a; }
			inline vec2& operator*=(vec2& a, const vec2& b) { a.x *= b.x; a.y *= b.y; return a; }
			inline vec2& operator/=(vec2& a, const vec2& b) { a.x /= b.x; a.y /= b.y; return a; }
			inline vec2& operator+=(vec2& a, float s) { a.x += s; a.y += s; return a; }
			inline vec2& operator-=(vec2& a, float s) { a.x -= s; a.y -= s; return a; }
			inline vec2& operator*=(vec2& a, float s) { a.x *= s; a.y *= s; return a; }
			inline vec2& operator/=(vec2& a, float s) { a.x /= s; a.y /= s; return a; }

			inline vec3 operator+(const vec3& a, const vec3& b) { return vec3(a.x + b.x, a.y + b.y, a.z + b.z); }
			inline vec3 operator-(const vec3& a, const vec3& b) { return vec3(a.x - b.x, a.y - b.y, a.z - b.z); }
			inline vec3 operator*(const vec3& a, const vec3& b) { return vec3(a.x * b.x, a.y * b.y, a.z * b.z); }
			inline vec3 operator/(const vec3& a, const vec3& b) { return vec3(a.x / b.x, a.y / b.y, a.z / b.z); }
			inline vec3 operator+(const vec3& a, float s) { return vec3(a.x + s, a.y + s, a.z + s); }
			inline vec3 operator-(const vec3& a, float s) { return vec3(a.x - s, a.y - s, a.z - s); }
			inline vec3 operator*(const vec3& a, float s) { return vec3(a.x * s, a.y * s, a.z * s); }
			inline vec3 operator/(const vec3& a, float s) { return vec3(a.x / s, a.y / s, a.z / s); }
			inline vec3 operator+(float s, const vec3& a) { return vec3(s + a.x, s + a.y, s + a.z); }
			inline vec3 operator-(float s, const vec3& a) { return vec3(s - a.x, s - a.y, s - a.z); }
			inline vec3 operator*(float s, const vec3& a) { return vec3(s * a.x, s * a.y, s * a.z); }
			inline vec3 operator/(float s, const vec3& a) { return vec3(s / a.x, s / a.y, s / a.z); }
			inline vec3 operator-(const vec3& a) { return vec3(-a.x, -a.y, -a.z); }
			inline vec3& operator+=(vec3& a, const vec3& b) { a.x += b.x; a.y += b.y; a.z += b.z; return a; }
			inline vec3& operator-=(vec3& a, const vec3& b) { a.x -= b.x; a.y -= b.y; a.z -= b.z; return a; }
			inline vec3& operator*=(vec3& a, const vec3& b) { a.x *= b.x; a.y *= b.y; a.z *= b.z; return a; }
			inline vec3& operator/=(vec3& a, const vec3& b) { a.x /= b.x; a.y /= b.y; a.z /= b.z; return a; }
			inline vec3& operator+=(vec3& a, float s) { a.x += s; a.y += s; a.z += s; return a; }
			inline vec3& operator-=(vec3& a, float s) { a.x -= s; a.y -= s; a.z -= s; return a; }
			inline vec3& operator*=(vec3& a, float s) { a.x *= s; a.y *= s; a.z *= s; return a; }
			inline vec3& operator/=(vec3& a, float s) { a.x /= s; a.y /= s; a.z /= s; return a; }

			inline vec4 operator+(const vec4& a, const vec4& b) { return vec4(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w); }
			inline vec4 operator-(const vec4& a, const vec4& b) { return vec4(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w); }
			inline vec4 operator*(const vec4& a, const vec4& b) { return vec4(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w); }
			inline vec4 operator/(const vec4& a, const vec4& b) { return vec4(a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w); }
			inline vec4 operator+(const vec4& a, float s) { return vec4(a.x + s, a.y + s, a.z + s, a.w + s); }
			inline vec4 operator-(const vec4& a, float s) { return vec4(a.x - s, a.y - s, a.z - s, a.w - s); }
			inline vec4 operator*(const vec4& a, float s) { return vec4(a.x * s, a.y * s, a.z * s, a.w * s); }
			inline vec4 operator/(const vec4& a, float s) { return vec4(a.x / s, a.y / s, a.z / s, a.w / s); }
			inline vec4 operator+(float s, const vec4& a) { return vec4(s + a.x, s + a.y, s + a.z, s + a.w); }
			inline vec4 operator-(float s, const vec4& a) { return vec4(s - a.x, s - a.y, s - a.z, s - a.w); }
			inline vec4 operator*(float s, const vec4& a) { return vec4(s * a.x, s * a.y, s * a.z, s * a.w); }
			inline vec4 operator/(float s, const vec4& a) { return vec4(s / a.x, s / a.y, s / a.z, s / a.w); }
			inline vec4 operator-(const vec4& a) { return vec4(-a.x, -a.y, -a.z, -a.w); }
			inline vec4& operator+=(vec4& a, const vec4& b) { a.x += b.x; a.y += b.y; a.z += b.z; a.w += b.w; return a; }
			inline vec4& operator-=(vec4& a, const vec4& b) { a.x -= b.x; a.y -= b.y; a.z -= b.z; a.w -= b.w; return a; }
			inline vec4& operator*=(vec4& a, const vec4& b) { a.x *= b.x; a.y *= b.y; a.z *= b.z; a.w *= b.w; return a; }
			inline vec4& operator/=(vec4& a, const vec4& b) { a.x /= b.x; a.y /= b.y; a.z /= b.z; a.w /= b.w; return a; }
			inline vec4& operator+=(vec4& a, float s) { a.x += s; a.y += s; a.z += s; a.w += s; return a; }
			inline vec4& operator-=(vec4& a, float s) { a.x -= s; a.y -= s; a.z -= s; a.w -= s; return a; }
			inline vec4& operator*=(vec4& a, float s) { a.x *= s; a.y *= s; a.z *= s; a.w *= s; return a; }
			inline vec4& operator/=(vec4& a, float s) { a.x /= s; a.y /= s; a.z /= s; a.w /= s; return a; }

			inline float min(float a, float b) { return (b < a ? b : a); }
			inline int min(int a, int b) { return (b < a ? b : a); }
			inline float max(float a, float b) { return (a < b ? b : a); }
			inline int max(int a, int b) { return (a < b ? b : a); }
			inline float clamp(float v, float lo, float hi) { return min(max(v, lo), hi); }
			inline int clamp(int v, int lo, int hi) { return min(max(v, lo), hi); }
			inline float mix(float a, float b, float t) { return a + (b - a) * t; }
			inline float floor(float v) { return std::floor(v); }
			inline float ceil(float v) { return std::ceil(v); }
			inline float abs(float v) { return std::abs(v); }
			inline float sqrt(float v) { return std::sqrt(v); }
			inline float sin(float v) { return std::sin(v); }
			inline float cos(float v) { return std::cos(v); }

			inline vec2 min(const vec2& a, const vec2& b) { return vec2(min(a.x, b.x), min(a.y, b.y)); }
			inline vec3 min(const vec3& a, const vec3& b) { return vec3(min(a.x, b.x), min(a.y, b.y), min(a.z, b.z)); }
			inline vec4 min(const vec4& a, const vec4& b) { return vec4(min(a.x, b.x), min(a.y, b.y), min(a.z, b.z), min(a.w, b.w)); }
			inline vec2 min(const vec2& a, float s) { return vec2(min(a.x, s), min(a.y, s)); }
			inline vec3 min(const vec3& a, float s) { return vec3(min(a.x, s), min(a.y, s), min(a.z, s)); }
			inline vec4 min(const vec4& a, float s) { return vec4(min(a.x, s), min(a.y, s), min(a.z, s), min(a.w, s)); }
			inline vec2 max(const vec2& a, const vec2& b) { return vec2(max(a.x, b.x), max(a.y, b.y)); }
			inline vec3 max(const vec3& a, const vec3& b) { return vec3(max(a.x, b.x), max(a.y, b.y), max(a.z, b.z)); }
			inline vec4 max(const vec4& a, const vec4& b) { return vec4(max(a.x, b.x), max(a.y, b.y), max(a.z, b.z), max(a.w, b.w)); }
			inline vec2 max(const vec2& a, float s) { return vec2(max(a.x, s), max(a.y, s)); }
			inline vec3 max(const vec3& a, float s) { return vec3(max(a.x, s), max(a.y, s), max(a.z, s)); }
			inline vec4 max(const vec4& a, float s) { return vec4(max(a.x, s), max(a.y, s), max(a.z, s), max(a.w, s)); }
			inline vec2 clamp(const vec2& v, const vec2& lo, const vec2& hi) { return min(max(v, lo), hi); }
			inline vec3 clamp(const vec3& v, const vec3& lo, const vec3& hi) { return min(max(v, lo), hi); }
			inline vec4 clamp(const vec4& v, const vec4& lo, const vec4& hi) { return min(max(v, lo), hi); }
			inline vec2 clamp(const vec2& v, float lo, float hi) { return min(max(v, lo), hi); }
			inline vec3 clamp(const vec3& v, float lo, float hi) { return min(max(v, lo), hi); }
			inline vec4 clamp(const vec4& v, float lo, float hi) { return min(max(v, lo), hi); }
			inline vec2 mix(const vec2& a, const vec2& b, float t) { return vec2(mix(a.x, b.x, t), mix(a.y, b.y, t)); }
			inline vec3 mix(const vec3& a, const vec3& b, float t) { return vec3(mix(a.x, b.x, t), mix(a.y, b.y, t), mix(a.z, b.z, t)); }
			inline vec4 mix(const vec4& a, const vec4& b, float t) { return vec4(mix(a.x, b.x, t), mix(a.y, b.y, t), mix(a.z, b.z, t), mix(a.w, b.w, t)); }
			inline vec2 mix(const vec2& a, const vec2& b, const vec2& t) { return vec2(mix(a.x, b.x, t.x), mix(a.y, b.y, t.y)); }
			inline vec3 mix(const vec3& a, const vec3& b, const vec3& t) { return vec3(mix(a.x, b.x, t.x), mix(a.y, b.y, t.y), mix(a.z, b.z, t.z)); }
			inline vec4 mix(const vec4& a, const vec4& b, const vec4& t) { return vec4(mix(a.x, b.x, t.x), mix(a.y, b.y, t.y), mix(a.z, b.z, t.z), mix(a.w, b.w, t.w)); }
			inline vec2 floor(const vec2& v) { return vec2(floor(v.x), floor(v.y)); }
			inline vec3 floor(const vec3& v) { return vec3(floor(v.x), floor(v.y), floor(v.z)); }
			inline vec4 floor(const vec4& v) { return vec4(floor(v.x), floor(v.y), floor(v.z), floor(v.w)); }
			inline vec2 ceil(const vec2& v) { return vec2(ceil(v.x), ceil(v.y)); }
			inline vec3 ceil(const vec3& v) { return vec3(ceil(v.x), ceil(v.y), ceil(v.z)); }
			inline vec4 ceil(const vec4& v) { return vec4(ceil(v.x), ceil(v.y), ceil(v.z), ceil(v.w)); }

			// Pass-field stores (FixedFunctionPass keeps plain float arrays so the runtime side
			// carries no vector types) and the instance-colour load of the COLOR built-in
			inline void Store(float* dst, const vec2& v) { dst[0] = v.x; dst[1] = v.y; }
			inline void Store(float* dst, const vec3& v) { dst[0] = v.x; dst[1] = v.y; dst[2] = v.z; }
			inline void Store(float* dst, const vec4& v) { dst[0] = v.x; dst[1] = v.y; dst[2] = v.z; dst[3] = v.w; }
			inline vec4 LoadColor(const float* c) { return vec4(c[0], c[1], c[2], c[3]); }

			// Extended-vocabulary bridges (backend-specific blocks only): resolved-uniform loads and
			// the strip-builder vertex setters, spelled over the EffectContext's scalar methods so the
			// contract in FixedFunctionPass.h stays free of these vector types
			inline vec2 UniformVec2(EffectContext& ctx, const char* name) { float v[2] = { 0.0f, 0.0f }; ctx.LoadUniform(name, v, 2); return vec2(v[0], v[1]); }
			inline vec4 UniformVec4(EffectContext& ctx, const char* name) { float v[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; ctx.LoadUniform(name, v, 4); return vec4(v[0], v[1], v[2], v[3]); }
			inline void StripPosition(EffectContext& ctx, int i, const vec2& p) { ctx.SetStripVertexPosition(i, p.x, p.y); }
			inline void StripUv(EffectContext& ctx, int i, const vec2& uv) { ctx.SetStripVertexUv(i, uv.x, uv.y); }
			inline void StripColor(EffectContext& ctx, int i, const vec4& c) { ctx.SetStripVertexColor(i, c.x, c.y, c.z, c.w); }
		}

		// BatchedShieldFire - from BatchedShieldFire.shader:fixed_function()
		// Shared by: BatchedShieldFire, ShieldFire [ShieldFire.shader:fixed_function()]
		void BatchedShieldFire_Effect(EffectContext& ctx)
		{
			using namespace ff;
			const vec4 COLOR = LoadColor(ctx.Color());
			float darkness = COLOR.z;
			FixedFunctionPass p;
			Store(p.Color, vec4(0.0f, 0.0f, 0.0f, COLOR.w * 0.5f));
			Store(p.OffsetColor, vec3(darkness, darkness * 0.45f, darkness * 0.1f));
			p.HasOffsetColor = true;
			ctx.SubmitQuad(p);
		}

		// BatchedShieldLightning - from BatchedShieldLightning.shader:fixed_function()
		// Shared by: BatchedShieldLightning, ShieldLightning [ShieldLightning.shader:fixed_function()]
		void BatchedShieldLightning_Effect(EffectContext& ctx)
		{
			using namespace ff;
			const vec4 COLOR = LoadColor(ctx.Color());
			float darkness = COLOR.z;
			FixedFunctionPass p;
			Store(p.Color, vec4(0.0f, 0.0f, 0.0f, COLOR.w * 0.5f));
			Store(p.OffsetColor, vec3(darkness * 0.6f, darkness * 0.8f, darkness));
			p.HasOffsetColor = true;
			ctx.SubmitQuad(p);
		}

		// Colorized - from Colorized.shader:fixed_function(pvr, gu, gs)
		// Shared by: Colorized, BatchedColorized
		void Colorized_Effect(EffectContext& ctx)
		{
			using namespace ff;
			const vec4 COLOR = LoadColor(ctx.Color());
			vec3 gain = 1.5f * (1.0f + (COLOR.xyz() - 0.5f) * 4.0f);
			float alpha = 1.0f + (COLOR.w - 0.5f) * 4.0f;
			int passes = clamp(int(ceil(max(0.0f, max(max(gain.x, gain.y), gain.z)))), 1, 3);
			for (int i = 0; i < passes; i++) {
				FixedFunctionPass p;
				Store(p.Color, vec4(gain - float(i), alpha));
				if (i > 0) {
					p.Blend = FixedFunctionPass::BlendMode::Additive;
				}
				ctx.SubmitQuad(p);
			}
		}

		// DefaultBatchedSpritesNoTexture - from DefaultBatchedSpritesNoTexture.shader:fixed_function()
		// Shared by: DefaultBatchedSpritesNoTexture, DefaultSprite [DefaultSprite.shader:fixed_function()], DefaultBatchedSprites [DefaultSprite.shader:fixed_function()], DefaultSpriteNoTexture [DefaultSpriteNoTexture.shader:fixed_function()], PaletteRemap [PaletteRemap.shader:fixed_function()], BatchedPaletteRemap [PaletteRemap.shader:fixed_function()]
		void DefaultBatchedSpritesNoTexture_Effect(EffectContext& ctx)
		{
			using namespace ff;
			const vec4 COLOR = LoadColor(ctx.Color());
			FixedFunctionPass p;
			Store(p.Color, COLOR);
			ctx.SubmitQuad(p);
		}

		// FrozenMask - from FrozenMask.shader:fixed_function(pvr, gu, gs)
		// Shared by: FrozenMask, FrozenMask (USE_PALETTE), BatchedFrozenMask, BatchedFrozenMask (USE_PALETTE)
		void FrozenMask_Effect(EffectContext& ctx)
		{
			using namespace ff;
			const vec4 COLOR = LoadColor(ctx.Color());
			float t = clamp(COLOR.w, 0.0f, 1.0f);
			FixedFunctionPass sprite;
			ctx.SubmitQuad(sprite);
			if (t > 0.0f) {
				FixedFunctionPass ice;
				Store(ice.Color, vec4(0.0f, 0.0f, 0.0f, 0.8f * t));
				Store(ice.OffsetColor, vec3(0.1f, 0.51f, 0.7f));
				ice.HasOffsetColor = true;
				ctx.SubmitQuad(ice);
			}
		}

		// Outline - from Outline.shader:fixed_function()
		// Shared by: Outline, BatchedOutline, OutlinePalette [OutlinePalette.shader:fixed_function()], BatchedOutlinePalette [OutlinePalette.shader:fixed_function()]
		void Outline_Effect(EffectContext& ctx)
		{
			using namespace ff;
			const vec4 COLOR = LoadColor(ctx.Color());
			if (COLOR.w > 0.0f && ctx.HasTexelStep()) {
				vec2 step = vec2(ctx.TexelStepX(), ctx.TexelStepY());
				for (int oy = -1; oy <= 1; oy++) {
					for (int ox = -1; ox <= 1; ox++) {
						if (ox != 0 || oy != 0) {
							FixedFunctionPass p;
							Store(p.Color, vec4(0.0f, 0.0f, 0.0f, COLOR.w));
							Store(p.OffsetColor, vec3(COLOR.z));
							p.HasOffsetColor = true;
							Store(p.ScreenOffset, step * vec2(float(ox), float(oy)));
							ctx.SubmitQuad(p);
						}
					}
				}
			}
			FixedFunctionPass sprite;
			ctx.SubmitQuad(sprite);
		}

		// PartialWhiteMask - from PartialWhiteMask.shader:fixed_function(pvr, gu, gs)
		// Shared by: PartialWhiteMask, PartialWhiteMask (USE_PALETTE), BatchedPartialWhiteMask, BatchedPartialWhiteMask (USE_PALETTE)
		void PartialWhiteMask_Effect(EffectContext& ctx)
		{
			using namespace ff;
			const vec4 COLOR = LoadColor(ctx.Color());
			FixedFunctionPass p;
			Store(p.Color, COLOR);
			Store(p.OffsetColor, vec3(96.0f / 255.0f));
			p.HasOffsetColor = true;
			ctx.SubmitQuad(p);
		}

		// TexturedBackground - from TexturedBackground.shader:fixed_function(pvr, gu, gs)
		// Shared by: TexturedBackground, TexturedBackground (DITHER), TexturedBackgroundCircle [TexturedBackgroundCircle.shader:fixed_function(pvr, gu, gs)], TexturedBackgroundCircle (DITHER) [TexturedBackgroundCircle.shader:fixed_function(pvr, gu, gs)]
		void TexturedBackground_Effect(EffectContext& ctx)
		{
			using namespace ff;
			if (!ctx.HasUniform("uViewSize") || !ctx.HasUniform("uShift") || !ctx.HasUniform("uHorizonColor")) {
				FixedFunctionPass fallback;
				ctx.SubmitQuad(fallback);
			} else {
				vec2 viewSize = UniformVec2(ctx, "uViewSize");
				vec2 shift = UniformVec2(ctx, "uShift");
				vec4 horizon = UniformVec4(ctx, "uHorizonColor");
				float correction = viewSize.y > 0.0f ? viewSize.x * 9.0f / (viewSize.y * 16.0f) : 1.0f;
				float shiftU = shift.x / 256.0f;
				float shiftV = shift.y / 256.0f;
				float leftX = vec2(ctx.QuadOriginX(), ctx.QuadOriginY()).x;
				float spanX = vec2(ctx.QuadAxisXx(), ctx.QuadAxisXy()).x;
				float topY = vec2(ctx.QuadOriginX(), ctx.QuadOriginY()).y;
				float spanY = vec2(ctx.QuadAxisYx(), ctx.QuadAxisYy()).y;
				FixedFunctionPass warp;
				FixedFunctionPass horizonPass;
				horizonPass.Blend = FixedFunctionPass::BlendMode::Alpha;
				for (int topHalf = 0; topHalf < 2; topHalf++) {
					float yShift = float(topHalf);
					for (int band = 0; band < 16; band++) {
						float t0 = (float(topHalf) + float(band) / 16.0f) * 0.5f;
						float t1 = (float(topHalf) + float(band + 1) / 16.0f) * 0.5f;
						float split = -1.0f;
						float vStart = shiftV + (t0 - yShift) * 1.4f * (1.3f - abs(2.0f * t0 - 1.0f));
						float vEnd = shiftV + (t1 - yShift) * 1.4f * (1.3f - abs(2.0f * t1 - 1.0f));
						if (floor(vStart) != floor(vEnd)) {
							float boundary = floor(vEnd);
							float lo = t0;
							float hi = t1;
							for (int i = 0; i < 12; i++) {
								float mid = 0.5f * (lo + hi);
								if (shiftV + (mid - yShift) * 1.4f * (1.3f - abs(2.0f * mid - 1.0f)) < boundary) {
									lo = mid;
								} else {
									hi = mid;
								}
							}
							split = 0.5f * (lo + hi);
						}
						for (int part = 0; part < 2; part++) {
							float bandT0 = part == 0 ? t0 : split;
							float bandT1 = part == 0 ? (split > 0.0f ? split : t1) : t1;
							if (!(part == 1 && split <= 0.0f || bandT1 <= bandT0)) {
								float y0 = topY + spanY * bandT0;
								float y1 = topY + spanY * bandT1;
								float d0 = 1.3f - abs(2.0f * bandT0 - 1.0f);
								float d1 = 1.3f - abs(2.0f * bandT1 - 1.0f);
								float v0 = shiftV + (bandT0 - yShift) * 1.4f * d0;
								float v1 = shiftV + (bandT1 - yShift) * 1.4f * d1;
								float vBase = floor(0.5f * (v0 + v1));
								v0 -= vBase;
								v1 -= vBase;
								float halfSpan0 = 0.5f * (0.5f + 1.5f * d0) * correction;
								float halfSpan1 = 0.5f * (0.5f + 1.5f * d1) * correction;
								float uLeft0 = shiftU - halfSpan0;
								float uRight0 = shiftU + halfSpan0;
								float uLeft1 = shiftU - halfSpan1;
								float uRight1 = shiftU + halfSpan1;
								int firstPiece = int(floor(min(uLeft0, uLeft1)));
								int lastPiece = int(ceil(max(uRight0, uRight1)));
								int emitted = 0;
								for (int piece = firstPiece; piece < lastPiece && emitted < 8; piece++) {
									float span0 = uRight0 - uLeft0;
									float span1 = uRight1 - uLeft1;
									float topA = span0 > 0.0f ? (float(piece) - uLeft0) / span0 : 0.0f;
									float topB = span0 > 0.0f ? (float(piece + 1) - uLeft0) / span0 : 0.0f;
									float botA = span1 > 0.0f ? (float(piece) - uLeft1) / span1 : 0.0f;
									float botB = span1 > 0.0f ? (float(piece + 1) - uLeft1) / span1 : 0.0f;
									if (!(topB <= 0.0f && botB <= 0.0f || topA >= 1.0f && botA >= 1.0f)) {
										emitted++;
										StripPosition(ctx, 0, vec2(leftX + topB * spanX, y0));
										StripPosition(ctx, 1, vec2(leftX + botB * spanX, y1));
										StripPosition(ctx, 2, vec2(leftX + topA * spanX, y0));
										StripPosition(ctx, 3, vec2(leftX + botA * spanX, y1));
										StripUv(ctx, 0, vec2(uLeft0 + topB * (uRight0 - uLeft0) - float(piece), v0));
										StripUv(ctx, 1, vec2(uLeft1 + botB * (uRight1 - uLeft1) - float(piece), v1));
										StripUv(ctx, 2, vec2(uLeft0 + topA * (uRight0 - uLeft0) - float(piece), v0));
										StripUv(ctx, 3, vec2(uLeft1 + botA * (uRight1 - uLeft1) - float(piece), v1));
										ctx.SubmitStrip(warp, 4);
									}
								}
								float alpha0 = clamp(d0 * d0 - 0.3f, 0.0f, 1.0f);
								float alpha1 = clamp(d1 * d1 - 0.3f, 0.0f, 1.0f);
								if (alpha0 > 0.0f || alpha1 > 0.0f) {
									StripPosition(ctx, 0, vec2(leftX + spanX, y0));
									StripPosition(ctx, 1, vec2(leftX + spanX, y1));
									StripPosition(ctx, 2, vec2(leftX, y0));
									StripPosition(ctx, 3, vec2(leftX, y1));
									StripColor(ctx, 0, vec4(horizon.xyz(), alpha0));
									StripColor(ctx, 1, vec4(horizon.xyz(), alpha1));
									StripColor(ctx, 2, vec4(horizon.xyz(), alpha0));
									StripColor(ctx, 3, vec4(horizon.xyz(), alpha1));
									ctx.SubmitStripShaded(horizonPass, 4);
								}
							}
						}
					}
				}
			}
		}

		// Transition - from Transition.shader:fixed_function(gx, gu, gs)
		void Transition_Effect(EffectContext& ctx)
		{
			using namespace ff;
			const vec4 COLOR = LoadColor(ctx.Color());
			vec2 axisX = vec2(ctx.QuadAxisXx(), ctx.QuadAxisXy());
			vec2 axisY = vec2(ctx.QuadAxisYx(), ctx.QuadAxisYy());
			vec2 centre = vec2(ctx.QuadOriginX(), ctx.QuadOriginY()) + 0.5f * (axisX + axisY);
			float extentX = abs(axisX.x) + abs(axisY.x);
			float extentY = abs(axisX.y) + abs(axisY.y);
			float radiusScale = max(extentX, extentY);
			float corner = 0.5f * sqrt(extentX * extentX + extentY * extentY) * 1.05f;
			float progress = COLOR.w;
			float outer = progress * radiusScale;
			float inner = max((progress - 0.22f) * radiusScale, 0.0f);
			if (outer < corner) {
				float ease1 = 2.0f * (1.0f / 3.0f) * (1.0f / 3.0f);
				float ease2 = 1.0f - 2.0f * (1.0f / 3.0f) * (1.0f / 3.0f);
				float edgeStep = (outer - inner) * (1.0f / 3.0f);
				float r1 = inner + edgeStep;
				float r2 = inner + 2.0f * edgeStep;
				FixedFunctionPass p;
				for (int i = 0; i < 64; i++) {
					float a0 = float(i) * (6.28318530718f / 64.0f);
					float a1 = float(i + 1) * (6.28318530718f / 64.0f);
					vec2 dir0 = vec2(cos(a0), sin(a0));
					vec2 dir1 = vec2(cos(a1), sin(a1));
					StripPosition(ctx, 0, centre + inner * dir0);
					StripPosition(ctx, 1, centre + inner * dir1);
					StripPosition(ctx, 2, centre + r1 * dir0);
					StripPosition(ctx, 3, centre + r1 * dir1);
					StripPosition(ctx, 4, centre + r2 * dir0);
					StripPosition(ctx, 5, centre + r2 * dir1);
					StripPosition(ctx, 6, centre + outer * dir0);
					StripPosition(ctx, 7, centre + outer * dir1);
					StripPosition(ctx, 8, centre + corner * dir0);
					StripPosition(ctx, 9, centre + corner * dir1);
					StripColor(ctx, 0, vec4(0.0f, 0.0f, 0.0f, 0.0f));
					StripColor(ctx, 1, vec4(0.0f, 0.0f, 0.0f, 0.0f));
					StripColor(ctx, 2, vec4(0.0f, 0.0f, 0.0f, ease1));
					StripColor(ctx, 3, vec4(0.0f, 0.0f, 0.0f, ease1));
					StripColor(ctx, 4, vec4(0.0f, 0.0f, 0.0f, ease2));
					StripColor(ctx, 5, vec4(0.0f, 0.0f, 0.0f, ease2));
					StripColor(ctx, 6, vec4(0.0f, 0.0f, 0.0f, 1.0f));
					StripColor(ctx, 7, vec4(0.0f, 0.0f, 0.0f, 1.0f));
					StripColor(ctx, 8, vec4(0.0f, 0.0f, 0.0f, 1.0f));
					StripColor(ctx, 9, vec4(0.0f, 0.0f, 0.0f, 1.0f));
					ctx.SubmitStripShaded(p, 10);
				}
			}
		}

		// WhiteMask - from WhiteMask.shader:fixed_function()
		// Shared by: WhiteMask, WhiteMask (USE_PALETTE), BatchedWhiteMask, BatchedWhiteMask (USE_PALETTE)
		void WhiteMask_Effect(EffectContext& ctx)
		{
			using namespace ff;
			const vec4 COLOR = LoadColor(ctx.Color());
			FixedFunctionPass p;
			Store(p.Color, vec4(0.0f, 0.0f, 0.0f, COLOR.w));
			Store(p.OffsetColor, COLOR.xyz());
			p.HasOffsetColor = true;
			ctx.SubmitQuad(p);
		}

		constexpr FixedFunctionGeneratedEffect FixedFunctionGeneratedEffects[] = {
			{ "BatchedShieldFire", "", true, FixedFunctionRequirements::None, FixedFunctionIntrinsic::None, &BatchedShieldFire_Effect },
			{ "BatchedShieldLightning", "", true, FixedFunctionRequirements::None, FixedFunctionIntrinsic::None, &BatchedShieldLightning_Effect },
			{ "Colorized", "", false, FixedFunctionRequirements::None, FixedFunctionIntrinsic::None, &Colorized_Effect },
			{ "BatchedColorized", "", false, FixedFunctionRequirements::None, FixedFunctionIntrinsic::None, &Colorized_Effect },
			{ "Combine", "", false, FixedFunctionRequirements::None, FixedFunctionIntrinsic::LightingCombine, nullptr },
			{ "CombineWithWater", "", false, FixedFunctionRequirements::None, FixedFunctionIntrinsic::LightingCombine, nullptr },
			{ "CombineWithWaterLow", "", false, FixedFunctionRequirements::None, FixedFunctionIntrinsic::LightingCombine, nullptr },
			{ "DefaultBatchedSpritesNoTexture", "", false, FixedFunctionRequirements::None, FixedFunctionIntrinsic::None, &DefaultBatchedSpritesNoTexture_Effect },
			{ "DefaultMeshSprite", "", false, FixedFunctionRequirements::None, FixedFunctionIntrinsic::LineStripMesh, nullptr },
			{ "DefaultSprite", "", false, FixedFunctionRequirements::None, FixedFunctionIntrinsic::None, &DefaultBatchedSpritesNoTexture_Effect },
			{ "DefaultBatchedSprites", "", false, FixedFunctionRequirements::None, FixedFunctionIntrinsic::None, &DefaultBatchedSpritesNoTexture_Effect },
			{ "DefaultSpriteNoTexture", "", false, FixedFunctionRequirements::None, FixedFunctionIntrinsic::None, &DefaultBatchedSpritesNoTexture_Effect },
			{ "FrozenMask", "", true, FixedFunctionRequirements::None, FixedFunctionIntrinsic::None, &FrozenMask_Effect },
			{ "FrozenMask", "USE_PALETTE", true, FixedFunctionRequirements::None, FixedFunctionIntrinsic::None, &FrozenMask_Effect },
			{ "BatchedFrozenMask", "", true, FixedFunctionRequirements::None, FixedFunctionIntrinsic::None, &FrozenMask_Effect },
			{ "BatchedFrozenMask", "USE_PALETTE", true, FixedFunctionRequirements::None, FixedFunctionIntrinsic::None, &FrozenMask_Effect },
			{ "Outline", "", true, FixedFunctionRequirements::NeedsTexelStep, FixedFunctionIntrinsic::None, &Outline_Effect },
			{ "BatchedOutline", "", true, FixedFunctionRequirements::NeedsTexelStep, FixedFunctionIntrinsic::None, &Outline_Effect },
			{ "OutlinePalette", "", true, FixedFunctionRequirements::NeedsTexelStep, FixedFunctionIntrinsic::None, &Outline_Effect },
			{ "BatchedOutlinePalette", "", true, FixedFunctionRequirements::NeedsTexelStep, FixedFunctionIntrinsic::None, &Outline_Effect },
			{ "PaletteRemap", "", false, FixedFunctionRequirements::None, FixedFunctionIntrinsic::None, &DefaultBatchedSpritesNoTexture_Effect },
			{ "BatchedPaletteRemap", "", false, FixedFunctionRequirements::None, FixedFunctionIntrinsic::None, &DefaultBatchedSpritesNoTexture_Effect },
			{ "PartialWhiteMask", "", true, FixedFunctionRequirements::None, FixedFunctionIntrinsic::None, &PartialWhiteMask_Effect },
			{ "PartialWhiteMask", "USE_PALETTE", true, FixedFunctionRequirements::None, FixedFunctionIntrinsic::None, &PartialWhiteMask_Effect },
			{ "BatchedPartialWhiteMask", "", true, FixedFunctionRequirements::None, FixedFunctionIntrinsic::None, &PartialWhiteMask_Effect },
			{ "BatchedPartialWhiteMask", "USE_PALETTE", true, FixedFunctionRequirements::None, FixedFunctionIntrinsic::None, &PartialWhiteMask_Effect },
			{ "ShieldFire", "", true, FixedFunctionRequirements::None, FixedFunctionIntrinsic::None, &BatchedShieldFire_Effect },
			{ "ShieldLightning", "", true, FixedFunctionRequirements::None, FixedFunctionIntrinsic::None, &BatchedShieldLightning_Effect },
			{ "TexturedBackground", "", false, FixedFunctionRequirements::NeedsUniforms | FixedFunctionRequirements::NeedsStripBuilder | FixedFunctionRequirements::NeedsQuadAxes, FixedFunctionIntrinsic::None, &TexturedBackground_Effect },
			{ "TexturedBackground", "DITHER", false, FixedFunctionRequirements::NeedsUniforms | FixedFunctionRequirements::NeedsStripBuilder | FixedFunctionRequirements::NeedsQuadAxes, FixedFunctionIntrinsic::None, &TexturedBackground_Effect },
			{ "TexturedBackgroundCircle", "", false, FixedFunctionRequirements::NeedsUniforms | FixedFunctionRequirements::NeedsStripBuilder | FixedFunctionRequirements::NeedsQuadAxes, FixedFunctionIntrinsic::None, &TexturedBackground_Effect },
			{ "TexturedBackgroundCircle", "DITHER", false, FixedFunctionRequirements::NeedsUniforms | FixedFunctionRequirements::NeedsStripBuilder | FixedFunctionRequirements::NeedsQuadAxes, FixedFunctionIntrinsic::None, &TexturedBackground_Effect },
			{ "TileMapMesh", "", false, FixedFunctionRequirements::None, FixedFunctionIntrinsic::TileMapMesh, nullptr },
			{ "TileMapMeshPalette", "", false, FixedFunctionRequirements::None, FixedFunctionIntrinsic::TileMapMesh, nullptr },
			{ "Transition", "", false, FixedFunctionRequirements::NeedsStripBuilder | FixedFunctionRequirements::NeedsQuadAxes, FixedFunctionIntrinsic::None, &Transition_Effect },
			{ "WhiteMask", "", true, FixedFunctionRequirements::None, FixedFunctionIntrinsic::None, &WhiteMask_Effect },
			{ "WhiteMask", "USE_PALETTE", true, FixedFunctionRequirements::None, FixedFunctionIntrinsic::None, &WhiteMask_Effect },
			{ "BatchedWhiteMask", "", true, FixedFunctionRequirements::None, FixedFunctionIntrinsic::None, &WhiteMask_Effect },
			{ "BatchedWhiteMask", "USE_PALETTE", true, FixedFunctionRequirements::None, FixedFunctionIntrinsic::None, &WhiteMask_Effect },
		};
		constexpr std::size_t FixedFunctionGeneratedEffectCount = sizeof(FixedFunctionGeneratedEffects) / sizeof(FixedFunctionGeneratedEffects[0]);
	}
}

#endif
