# Test that varying structs work properly in conjunction with arrays.
#
# From the GLSL ES 3.00 specification, section 4.3.4 ("Input Variables"):
#
#     Fragment inputs can only be signed and unsigned integers and
#     integer vectors, float, floating-point vectors, matrices, or
#     arrays or structures of these.
#
# And from section 4.3.6 ("Output Variables"):
#
#     Vertex output variables ... can only be float, floating-point
#     vectors, matrices, signed or unsigned integers or integer
#     vectors, or arrays or structures of any these.
#
# This test verifies the proper functioning of varyings whose types
# are a struct containing an array, an array of structs, and various
# complex combinations of arrays and structs.
#
# Note: chapter 11 of the GLSL ES 3.00 spec ("Counting of Inputs and
# Outputs") specifies a packing algorithm which constitutes a minimum
# requirement for when a set of varyings must be supported by a
# conformant implementation.  Although that chapter has not yet been
# updated to reflect varying structs, Khronos's internal bugzilla
# indicates that structs should be flattened before applying the
# packing algorithm
# (https://cvs.khronos.org/bugzilla/show_bug.cgi?id=9828).  The
# varyings in this test flatten as follows:
#
# float     s1.f;             // A
# float[3]  s1.af[];          // B
# float[3]  as1[].f;          // C
# float[9]  as1[].af[];       // D
# float     s2.s1.f;          // E
# float[3]  s2.s1.af[];       // F
# float[2]  s2.as1[].f;       // G
# float[6]  s2.as1[].af[];    // H
# float[2]  as2[].s1.f;       // I
# float[6]  as2[].s1.af[];    // J
# float[4]  as2[].as1[].f;    // K
# float[12] as2[].as1[].af[]; // L
#
# And the flattened varyings would in turn be packed like so:
#    x y z w
#  0 L D J G
#  1 L D J G
#  2 L D J I
#  3 L D J I
#  4 L D J
#  5 L D J
#  6 L D B
#  7 L D B
#  8 L D B
#  9 L H C
# 10 L H C
# 11 L H C
# 12 K H F
# 13 K H F
# 14 K H F
# 15 K A E

[require]
GL ES >= 3.0
GLSL ES >= 3.00

[vertex shader]
#version 300 es

uniform float ref;

in vec4 vertex;
struct S1
{
	float f;
	float af[3];
};
struct S2
{
	S1 s1;
	S1 as1[2];
};
out S1 s1;
out S1 as1[3];
out S2 s2;
out S2 as2[2];

void main()
{
	gl_Position = vertex;
	float f = ref;
	s1.f = f++;
	s1.af[0] = f++;
	s1.af[1] = f++;
	s1.af[2] = f++;
	as1[0].f = f++;
	as1[0].af[0] = f++;
	as1[0].af[1] = f++;
	as1[0].af[2] = f++;
	as1[1].f = f++;
	as1[1].af[0] = f++;
	as1[1].af[1] = f++;
	as1[1].af[2] = f++;
	as1[2].f = f++;
	as1[2].af[0] = f++;
	as1[2].af[1] = f++;
	as1[2].af[2] = f++;
	s2.s1.f = f++;
	s2.s1.af[0] = f++;
	s2.s1.af[1] = f++;
	s2.s1.af[2] = f++;
	s2.as1[0].f = f++;
	s2.as1[0].af[0] = f++;
	s2.as1[0].af[1] = f++;
	s2.as1[0].af[2] = f++;
	s2.as1[1].f = f++;
	s2.as1[1].af[0] = f++;
	s2.as1[1].af[1] = f++;
	s2.as1[1].af[2] = f++;
	as2[0].s1.f = f++;
	as2[0].s1.af[0] = f++;
	as2[0].s1.af[1] = f++;
	as2[0].s1.af[2] = f++;
	as2[0].as1[0].f = f++;
	as2[0].as1[0].af[0] = f++;
	as2[0].as1[0].af[1] = f++;
	as2[0].as1[0].af[2] = f++;
	as2[0].as1[1].f = f++;
	as2[0].as1[1].af[0] = f++;
	as2[0].as1[1].af[1] = f++;
	as2[0].as1[1].af[2] = f++;
	as2[1].s1.f = f++;
	as2[1].s1.af[0] = f++;
	as2[1].s1.af[1] = f++;
	as2[1].s1.af[2] = f++;
	as2[1].as1[0].f = f++;
	as2[1].as1[0].af[0] = f++;
	as2[1].as1[0].af[1] = f++;
	as2[1].as1[0].af[2] = f++;
	as2[1].as1[1].f = f++;
	as2[1].as1[1].af[0] = f++;
	as2[1].as1[1].af[1] = f++;
	as2[1].as1[1].af[2] = f++;
}

[fragment shader]
#version 300 es
precision highp float;

uniform float ref;

struct S1
{
	float f;
	float af[3];
};
struct S2
{
	S1 s1;
	S1 as1[2];
};
in S1 s1;
in S1 as1[3];
in S2 s2;
in S2 as2[2];
out vec4 color;

#define CHECK(value, expected) \
	if (distance(value, expected) > 0.00001) \
		failed = true

void main()
{
	bool failed = false;
	float f = ref;

	CHECK(s1.f, f++);
	CHECK(s1.af[0], f++);
	CHECK(s1.af[1], f++);
	CHECK(s1.af[2], f++);
	CHECK(as1[0].f, f++);
	CHECK(as1[0].af[0], f++);
	CHECK(as1[0].af[1], f++);
	CHECK(as1[0].af[2], f++);
	CHECK(as1[1].f, f++);
	CHECK(as1[1].af[0], f++);
	CHECK(as1[1].af[1], f++);
	CHECK(as1[1].af[2], f++);
	CHECK(as1[2].f, f++);
	CHECK(as1[2].af[0], f++);
	CHECK(as1[2].af[1], f++);
	CHECK(as1[2].af[2], f++);
	CHECK(s2.s1.f, f++);
	CHECK(s2.s1.af[0], f++);
	CHECK(s2.s1.af[1], f++);
	CHECK(s2.s1.af[2], f++);
	CHECK(s2.as1[0].f, f++);
	CHECK(s2.as1[0].af[0], f++);
	CHECK(s2.as1[0].af[1], f++);
	CHECK(s2.as1[0].af[2], f++);
	CHECK(s2.as1[1].f, f++);
	CHECK(s2.as1[1].af[0], f++);
	CHECK(s2.as1[1].af[1], f++);
	CHECK(s2.as1[1].af[2], f++);
	CHECK(as2[0].s1.f, f++);
	CHECK(as2[0].s1.af[0], f++);
	CHECK(as2[0].s1.af[1], f++);
	CHECK(as2[0].s1.af[2], f++);
	CHECK(as2[0].as1[0].f, f++);
	CHECK(as2[0].as1[0].af[0], f++);
	CHECK(as2[0].as1[0].af[1], f++);
	CHECK(as2[0].as1[0].af[2], f++);
	CHECK(as2[0].as1[1].f, f++);
	CHECK(as2[0].as1[1].af[0], f++);
	CHECK(as2[0].as1[1].af[1], f++);
	CHECK(as2[0].as1[1].af[2], f++);
	CHECK(as2[1].s1.f, f++);
	CHECK(as2[1].s1.af[0], f++);
	CHECK(as2[1].s1.af[1], f++);
	CHECK(as2[1].s1.af[2], f++);
	CHECK(as2[1].as1[0].f, f++);
	CHECK(as2[1].as1[0].af[0], f++);
	CHECK(as2[1].as1[0].af[1], f++);
	CHECK(as2[1].as1[0].af[2], f++);
	CHECK(as2[1].as1[1].f, f++);
	CHECK(as2[1].as1[1].af[0], f++);
	CHECK(as2[1].as1[1].af[1], f++);
	CHECK(as2[1].as1[1].af[2], f++);

	if (failed)
		color = vec4(1.0, 0.0, 0.0, 1.0);
	else
		color = vec4(0.0, 1.0, 0.0, 1.0);
}

[test]
uniform float ref 137.035999074
draw rect -1 -1 2 2
probe all rgba 0.0 1.0 0.0 1.0
