xref: /aosp_15_r20/external/angle/src/libANGLE/GLES1Shaders.inc (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1//
2// Copyright 2018 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6
7// GLES1Shaders.inc: Defines GLES1 emulation shader.
8//
9// According to the GLES1 specification:
10//
11// We require simply that numbers' floating point parts contain enough bits and that their exponent
12// fields are large enough so that individual results of floating-point operations are accurate to
13// about 1 part in 10^5.  The maximum representable magnitude of a floating-point number used to
14// represent positional or normal coordinates must be at least 2^32; the maximum representable
15// magnitude for colors or texture coordinates must be at least 2^10.  The maximum representable
16// magnitude for all other floating-point values must be at least 2^32 .
17//
18// Internal computations can use either fixed-point or floating-point arithmetic.  Fixed-point
19// computations must be accurate to within ±2^-15.  The maximum representable magnitude for a
20// fixed-point number used to represent positional or normal coordinates must be at least 2^15; the
21// maximum representable magnitude for colors or texture coordinates must be at least 2^10.  The
22// maximum representable magnitude for all other fixed-point values must be at least 2^15
23//
24// Accordingly, ANGLE uses highp floats for position and normal data, mediump for color and texture
25// coordinates, and highp for everything else.
26
27// The following variables are added in GLES1Renderer::initializeRendererProgram
28// #define kTexUnits
29// bool clip_plane_enables
30// bool enable_alpha_test
31// bool enable_clip_planes
32// bool enable_color_material
33// bool enable_draw_texture
34// bool enable_fog
35// bool enable_lighting
36// bool enable_normalize
37// bool enable_rescale_normal
38// bool enable_texture_2d[kMaxTexUnits]
39// bool enable_texture_cube_map[kMaxTexUnits]
40// bool light_enables[kMaxLights]
41// bool light_model_two_sided
42// bool point_rasterization
43// bool point_sprite_coord_replace
44// bool point_sprite_enabled
45// bool shade_model_flat
46// uint texture_format[kMaxTexUnits];
47// uint texture_env_mode[kMaxTexUnits];
48// uint combine_rgb[kMaxTexUnits];
49// uint combine_alpha[kMaxTexUnits];
50// uint src0_rgb[kMaxTexUnits];
51// uint src0_alpha[kMaxTexUnits];
52// uint src1_rgb[kMaxTexUnits];
53// uint src1_alpha[kMaxTexUnits];
54// uint src2_rgb[kMaxTexUnits];
55// uint src2_alpha[kMaxTexUnits];
56// uint op0_rgb[kMaxTexUnits];
57// uint op0_alpha[kMaxTexUnits];
58// uint op1_rgb[kMaxTexUnits];
59// uint op1_alpha[kMaxTexUnits];
60// uint op2_rgb[kMaxTexUnits];
61// uint op2_alpha[kMaxTexUnits];
62// uint alpha_func;
63// uint fog_mode;
64
65constexpr char kGLES1TexUnitsDefine[] = R"(#define kTexUnits )";
66
67constexpr char kGLES1DrawVShaderHeader[] = R"(#version 300 es
68precision highp float;
69
70#define kMaxTexUnits 4u
71#define kMaxLights   8u
72)";
73
74constexpr char kGLES1DrawVShader[] = R"(
75
76in vec4 pos;
77in vec3 normal;
78in mediump vec4 color;
79in float pointsize;
80#if kTexUnits >= 1u
81in mediump vec4 texcoord0;
82#endif
83#if kTexUnits >= 2u
84in mediump vec4 texcoord1;
85#endif
86#if kTexUnits >= 3u
87in mediump vec4 texcoord2;
88#endif
89#if kTexUnits >= 4u
90in mediump vec4 texcoord3;
91#endif
92
93uniform mat4 projection;
94uniform mat4 modelview;
95uniform mat4 modelview_invtr;
96uniform mat4 texture_matrix[kMaxTexUnits];
97
98// Point rasterization//////////////////////////////////////////////////////////
99
100uniform float point_size_min;
101uniform float point_size_max;
102uniform vec3 point_distance_attenuation;
103
104// Shading: flat shading, lighting, and materials///////////////////////////////
105
106uniform mediump vec4 material_ambient;
107uniform mediump vec4 material_diffuse;
108uniform mediump vec4 material_specular;
109uniform mediump vec4 material_emissive;
110uniform float material_specular_exponent;
111
112uniform mediump vec4 light_model_scene_ambient;
113
114uniform mediump vec4 light_ambients[kMaxLights];
115uniform mediump vec4 light_diffuses[kMaxLights];
116uniform mediump vec4 light_speculars[kMaxLights];
117uniform vec4 light_positions[kMaxLights];
118uniform vec3 light_directions[kMaxLights];
119uniform float light_spotlight_exponents[kMaxLights];
120uniform float light_spotlight_cutoff_angles[kMaxLights];
121uniform float light_attenuation_consts[kMaxLights];
122uniform float light_attenuation_linears[kMaxLights];
123uniform float light_attenuation_quadratics[kMaxLights];
124
125// GL_OES_draw_texture uniforms/////////////////////////////////////////////////
126
127uniform vec4 draw_texture_coords;
128uniform vec2 draw_texture_dims;
129uniform mediump vec4 draw_texture_normalized_crop_rect[kMaxTexUnits];
130
131// Varyings/////////////////////////////////////////////////////////////////////
132
133out vec4 pos_varying;
134out vec3 normal_varying;
135out mediump vec4 color_varying;
136flat out mediump vec4 color_varying_flat;
137#if kTexUnits >= 1u
138out mediump vec3 texcoord0_varying;
139#endif
140#if kTexUnits >= 2u
141out mediump vec3 texcoord1_varying;
142#endif
143#if kTexUnits >= 3u
144out mediump vec3 texcoord2_varying;
145#endif
146#if kTexUnits >= 4u
147out mediump vec3 texcoord3_varying;
148#endif
149
150float posDot(vec3 a, vec3 b)
151{
152    return max(dot(a, b), 0.0);
153}
154
155mediump vec4 doLighting(mediump vec4 vertexColor)
156{
157    mediump vec4 materialAmbientActual = material_ambient;
158    mediump vec4 materialDiffuseActual = material_diffuse;
159
160    if (enable_color_material)
161    {
162        materialAmbientActual = vertexColor;
163        materialDiffuseActual = vertexColor;
164    }
165
166    mediump vec4 lightingResult = material_emissive + materialAmbientActual * light_model_scene_ambient;
167
168    for (uint i = 0u; i < kMaxLights; i++)
169    {
170
171        if (!light_enables[i])
172            continue;
173
174        mediump vec4 lightAmbient  = light_ambients[i];
175        mediump vec4 lightDiffuse  = light_diffuses[i];
176        mediump vec4 lightSpecular = light_speculars[i];
177        vec4 lightPos      = light_positions[i];
178        vec3 lightDir      = light_directions[i];
179        float attConst     = light_attenuation_consts[i];
180        float attLinear    = light_attenuation_linears[i];
181        float attQuadratic = light_attenuation_quadratics[i];
182        float spotAngle    = light_spotlight_cutoff_angles[i];
183        float spotExponent = light_spotlight_exponents[i];
184
185        vec3 toLight;
186        if (lightPos.w == 0.0)
187        {
188            toLight = lightPos.xyz;
189        }
190        else
191        {
192            toLight = (lightPos.xyz / lightPos.w - pos_varying.xyz);
193        }
194
195        float lightDist = length(toLight);
196        vec3 toLightNormalized = normalize(toLight);
197        vec3 h                 = toLightNormalized + vec3(0.0, 0.0, 1.0);
198        float ndotL            = posDot(normal_varying, toLightNormalized);
199        float ndoth            = posDot(normal_varying, normalize(h));
200
201        float specAtt;
202
203        if (ndotL != 0.0)
204        {
205            specAtt = 1.0;
206        }
207        else
208        {
209            specAtt = 0.0;
210        }
211
212        float att;
213
214        if (lightPos.w != 0.0)
215        {
216            float attDenom =
217                (attConst + attLinear * lightDist + attQuadratic * lightDist * lightDist);
218            att = 1.0 / attDenom;
219        }
220        else
221        {
222            att = 1.0;
223        }
224
225        mediump float spot;
226
227        mediump float spotAngleCos = cos(radians(spotAngle));
228        vec3 toSurfaceDir  = -toLightNormalized;
229        mediump float spotDot      = posDot(toSurfaceDir, normalize(lightDir));
230
231        if (spotAngle == 180.0 || lightPos.w == 0.0)
232        {
233            spot = 1.0;
234        }
235        else
236        {
237            if (spotDot < spotAngleCos)
238            {
239                spot = 0.0;
240            }
241            else
242            {
243                spot = pow(spotDot, spotExponent);
244            }
245        }
246
247        mediump vec4 contrib = materialAmbientActual * lightAmbient;
248        contrib += ndotL * materialDiffuseActual * lightDiffuse;
249        if (ndoth > 0.0 && material_specular_exponent > 0.0)
250        {
251            contrib += specAtt * pow(ndoth, material_specular_exponent) * material_specular *
252                       lightSpecular;
253        }
254        else
255        {
256            if (ndoth > 0.0)
257            {
258                contrib += specAtt * material_specular * lightSpecular;
259            }
260        }
261        contrib *= att * spot;
262        lightingResult += contrib;
263    }
264
265    return lightingResult;
266}
267
268const mediump vec4 drawTextureVertices[6] = vec4[](
269    vec4(0.0, 0.0, 0.0, 1.0),
270    vec4(1.0, 0.0, 0.0, 1.0),
271    vec4(1.0, 1.0, 0.0, 1.0),
272    vec4(0.0, 0.0, 0.0, 1.0),
273    vec4(1.0, 1.0, 0.0, 1.0),
274    vec4(0.0, 1.0, 0.0, 1.0));
275
276mediump vec4 drawTexturePosition(int vertexId)
277{
278    // The texture is drawn in the XY plane, so Z is constant.
279    vec2 positionXY = draw_texture_coords.xy + drawTextureVertices[vertexId].xy * draw_texture_dims;
280    return vec4(positionXY, draw_texture_coords.z, 1.0);
281}
282
283mediump vec3 drawTextureTexCoord(int vertexId, uint textureUnit)
284{
285    // The texture is drawn in the XY plane, so Z is 0.
286    mediump vec2 texCropPos = draw_texture_normalized_crop_rect[textureUnit].xy;
287    mediump vec2 texCropDim = draw_texture_normalized_crop_rect[textureUnit].zw;
288    mediump vec2 texCoords  = texCropPos + drawTextureVertices[vertexId].xy * texCropDim;
289
290    return vec3(texCoords, 0.0);
291}
292
293vec4 calcWorldPosition(vec4 posInput)
294{
295    return modelview * posInput;
296}
297
298vec4 calcNdcFromWorldPosition(vec4 worldPos)
299{
300    return projection * worldPos;
301}
302
303float calcPointSize(vec4 ndcPos)
304{
305    float dist         = length(ndcPos.z);
306    float attConst     = point_distance_attenuation[0];
307    float attLinear    = point_distance_attenuation[1];
308    float attQuad      = point_distance_attenuation[2];
309    float attPart      = attConst + attLinear * dist + attQuad * dist * dist;
310    float attPointSize = pointsize / pow(attPart, 0.5);
311
312    return clamp(attPointSize, point_size_min, point_size_max);
313}
314
315vec3 calcNormal(vec3 normalInput)
316{
317    mat3 mvInvTr3 = mat3(modelview_invtr);
318    vec3 result   = mvInvTr3 * normalInput;
319
320    if (enable_rescale_normal)
321    {
322        float rescale   = 1.0;
323        vec3 rescaleVec = vec3(mvInvTr3[2]);
324        float len       = length(rescaleVec);
325        if (len > 0.0)
326        {
327            rescale = 1.0 / len;
328        }
329        result *= rescale;
330    }
331
332    if (enable_normalize)
333    {
334        result = normalize(result);
335    }
336
337    return result;
338}
339
340void main()
341{
342    if (enable_draw_texture)
343    {
344        int vertexId        = gl_VertexID;
345        mediump vec4 posDrawTexture = drawTexturePosition(vertexId);
346
347        gl_Position = posDrawTexture;
348        pos_varying = posDrawTexture;
349
350        normal_varying = normal;
351
352        gl_PointSize = pointsize;
353
354#if kTexUnits >= 1u
355        texcoord0_varying = drawTextureTexCoord(vertexId, 0u);
356#endif
357#if kTexUnits >= 2u
358        texcoord1_varying = drawTextureTexCoord(vertexId, 1u);
359#endif
360#if kTexUnits >= 3u
361        texcoord2_varying = drawTextureTexCoord(vertexId, 2u);
362#endif
363#if kTexUnits >= 4u
364        texcoord3_varying = drawTextureTexCoord(vertexId, 3u);
365#endif
366    }
367    else
368    {
369        vec4 worldPos = calcWorldPosition(pos);
370        vec4 ndcPos   = calcNdcFromWorldPosition(worldPos);
371
372        gl_Position = ndcPos;
373        pos_varying = worldPos;
374
375        normal_varying = calcNormal(normal);
376
377        // Avoid calculating point size stuff
378        // if we are not rendering points.
379        if (point_rasterization)
380        {
381            gl_PointSize = calcPointSize(ndcPos);
382        }
383        else
384        {
385            gl_PointSize = pointsize;
386        }
387
388#if kTexUnits >= 1u
389        texcoord0_varying = (texture_matrix[0] * texcoord0).xyz;
390#endif
391#if kTexUnits >= 2u
392        texcoord1_varying = (texture_matrix[1] * texcoord1).xyz;
393#endif
394#if kTexUnits >= 3u
395        texcoord2_varying = (texture_matrix[2] * texcoord2).xyz;
396#endif
397#if kTexUnits >= 4u
398        texcoord3_varying = (texture_matrix[3] * texcoord3).xyz;
399#endif
400    }
401
402    mediump vec4 vertex_color = color;
403
404    if (enable_lighting)
405    {
406        vertex_color = doLighting(color);
407    }
408
409    vertex_color = clamp(vertex_color, vec4(0), vec4(1));
410
411    color_varying      = vertex_color;
412    color_varying_flat = vertex_color;
413}
414)";
415
416constexpr char kGLES1DrawFShaderVersion[] = R"(#version 300 es
417)";
418
419constexpr char kGLES1DrawFShaderHeader[] = R"(precision highp float;
420
421// Defines for GL constants
422#define kMaxTexUnits                         4u
423#define kMaxClipPlanes                       6u
424
425#define kModulate                       0x2100u
426#define kDecal                          0x2101u
427#define kCombine                        0x8570u
428#define kReplace                        0x1E01u
429#define kBlend                          0x0BE2u
430#define kAdd                            0x0104u
431
432#define kAddSigned                      0x8574u
433#define kInterpolate                    0x8575u
434#define kSubtract                       0x84E7u
435#define kDot3Rgb                        0x86AEu
436#define kDot3Rgba                       0x86AFu
437
438#define kAlpha                          0x1906u
439#define kRGB                            0x1907u
440#define kRGBA                           0x1908u
441#define kLuminance                      0x1909u
442#define kLuminanceAlpha                 0x190Au
443
444#define kTexture                        0x1702u
445#define kConstant                       0x8576u
446#define kPrimaryColor                   0x8577u
447#define kPrevious                       0x8578u
448
449#define kSrcColor                       0x0300u
450#define kOneMinusSrcColor               0x0301u
451#define kSrcAlpha                       0x0302u
452#define kOneMinusSrcAlpha               0x0303u
453
454#define kLinear                         0x2601u
455#define kExp                            0x0800u
456#define kExp2                           0x0801u
457
458#define kNever                          0x0200u
459#define kLess                           0x0201u
460#define kEqual                          0x0202u
461#define kLequal                         0x0203u
462#define kGreater                        0x0204u
463#define kNotequal                       0x0205u
464#define kGequal                         0x0206u
465#define kAlways                         0x0207u
466#define kZero                              0x0u
467#define kOne                               0x1u
468
469#define kAnd                            0u
470#define kAndInverted                    1u
471#define kAndReverse                     2u
472#define kClear                          3u
473#define kCopy                           4u
474#define kCopyInverted                   5u
475#define kEquiv                          6u
476#define kInvert                         7u
477#define kNand                           8u
478#define kNoop                           9u
479#define kNor                            10u
480#define kOr                             11u
481#define kOrInverted                     12u
482#define kOrReverse                      13u
483#define kSet                            14u
484#define kXor                            15u
485)";
486
487constexpr char kGLES1DrawFShaderUniformDefs[] = R"(
488
489// Texture units ///////////////////////////////////////////////////////////////
490
491// These are not arrays because hw support for arrays
492// of samplers is rather lacking.
493
494uniform mediump sampler2D tex_sampler0;
495uniform mediump samplerCube tex_cube_sampler0;
496
497uniform mediump sampler2D tex_sampler1;
498uniform mediump samplerCube tex_cube_sampler1;
499
500uniform mediump sampler2D tex_sampler2;
501uniform mediump samplerCube tex_cube_sampler2;
502
503uniform mediump sampler2D tex_sampler3;
504uniform mediump samplerCube tex_cube_sampler3;
505
506uniform mediump vec4 texture_env_color[kMaxTexUnits];
507uniform mediump float texture_env_rgb_scale[kMaxTexUnits];
508uniform mediump float texture_env_alpha_scale[kMaxTexUnits];
509
510// Vertex attributes////////////////////////////////////////////////////////////
511
512in vec4 pos_varying;
513in vec3 normal_varying;
514in mediump vec4 color_varying;
515flat in mediump vec4 color_varying_flat;
516#if kTexUnits >= 1u
517in mediump vec3 texcoord0_varying;
518#endif
519#if kTexUnits >= 2u
520in mediump vec3 texcoord1_varying;
521#endif
522#if kTexUnits >= 3u
523in mediump vec3 texcoord2_varying;
524#endif
525#if kTexUnits >= 4u
526in mediump vec3 texcoord3_varying;
527#endif
528
529// Alpha test///////////////////////////////////////////////////////////////////
530
531uniform mediump float alpha_test_ref;
532
533// Fog /////////////////////////////////////////////////////////////////////////
534
535uniform float fog_density;
536uniform float fog_start;
537uniform float fog_end;
538uniform mediump vec4 fog_color;
539
540// User clip plane /////////////////////////////////////////////////////////////
541
542uniform vec4 clip_planes[kMaxClipPlanes];
543
544// Logic Op ////////////////////////////////////////////////////////////////////
545
546// Format is:
547// - 4x4 bits depicting the bit width of each channel of color output
548// - 4 bits for the op based on LogicalOperation's packing
549uniform highp uint logic_op;
550
551// Point rasterization//////////////////////////////////////////////////////////
552
553// GL_OES_draw_texture//////////////////////////////////////////////////////////
554)";
555
556constexpr char kGLES1DrawFShaderOutputDef[] = R"(
557out mediump vec4 frag_color;
558)";
559
560constexpr char kGLES1DrawFShaderFramebufferFetchOutputDef[] = R"(
561inout mediump vec4 frag_color;
562)";
563
564constexpr char kGLES1DrawFShaderFramebufferFetchNonCoherentOutputDef[] = R"(
565layout(noncoherent) inout mediump vec4 frag_color;
566)";
567
568constexpr char kGLES1DrawFShaderFunctions[] = R"(
569
570bool doAlphaTest(mediump vec4 currentFragment)
571{
572    bool shouldPassAlpha   = false;
573    mediump float incAlpha = currentFragment.a;
574
575    switch (alpha_func)
576    {
577        case kNever:
578            shouldPassAlpha = false;
579            break;
580        case kLess:
581            shouldPassAlpha = incAlpha < alpha_test_ref;
582            break;
583        case kLequal:
584            shouldPassAlpha = incAlpha <= alpha_test_ref;
585            break;
586        case kEqual:
587            shouldPassAlpha = incAlpha == alpha_test_ref;
588            break;
589        case kGequal:
590            shouldPassAlpha = incAlpha >= alpha_test_ref;
591            break;
592        case kGreater:
593            shouldPassAlpha = incAlpha > alpha_test_ref;
594            break;
595        case kNotequal:
596            shouldPassAlpha = incAlpha != alpha_test_ref;
597            break;
598        case kAlways:
599        default:
600            shouldPassAlpha = true;
601            break;
602    }
603
604    return shouldPassAlpha;
605}
606
607bool doClipPlaneTest()
608{
609    bool res = true;
610
611    for (uint i = 0u; i < kMaxClipPlanes; i++)
612    {
613        if (clip_plane_enables[i])
614        {
615            float dist = dot(clip_planes[i].xyz, pos_varying.xyz) + clip_planes[i].w * pos_varying.w;
616            res        = res && (dist >= 0.0);
617        }
618    }
619
620    return res;
621}
622
623mediump vec4 doFog(mediump vec4 currentFragment)
624{
625
626    float eyeDist = abs(pos_varying.z / pos_varying.w);
627    float f       = 1.0;
628    switch (fog_mode)
629    {
630        case kExp:
631            f = exp(-fog_density * eyeDist);
632            break;
633        case kExp2:
634            f = exp(-(pow(fog_density * eyeDist, 2.0)));
635            break;
636        case kLinear:
637            f = (fog_end - eyeDist) / (fog_end - fog_start);
638            break;
639        default:
640            break;
641    }
642
643    f = clamp(f, 0.0, 1.0);
644    mediump vec4 result = vec4(f * currentFragment.rgb + (1.0 - f) * fog_color.rgb, currentFragment.a);
645    return result;
646}
647)";
648
649constexpr char kGLES1DrawFShaderLogicOpFramebufferFetchDisabled[] = R"(
650mediump vec4 applyLogicOp(mediump vec4 currentFragment)
651{
652    return currentFragment;
653}
654)";
655
656// applyLogicOp takes logic-op information from a packed uniform and applies it to the color
657// attachment using framebuffer fetch.  See the description of logic_op above for the format of the
658// uniform.
659//
660// In particular, 4 bits in logic_op (at offset 16) contain the packed logical operation (of
661// LogicalOperation type).  Based on the selected operation, the formula specified in the spec is
662// applied (applied as bitwise operations on unorm values).
663constexpr char kGLES1DrawFShaderLogicOpFramebufferFetchEnabled[] = R"(
664mediump vec4 applyLogicOp(mediump vec4 currentFragment)
665{
666    mediump vec4 previousFragment = frag_color;
667
668    mediump uvec4 channelWidths = uvec4(logic_op & 0xFu,
669                                        logic_op >> 4u & 0xFu,
670                                        logic_op >> 8u & 0xFu,
671                                        logic_op >> 12u & 0xFu);
672
673    mediump uvec4 channelMasks = (uvec4(1) << channelWidths) - 1u;
674
675    mediump uvec4 src = uvec4(round(currentFragment * vec4(channelMasks)));
676    mediump uvec4 dst = uvec4(round(previousFragment * vec4(channelMasks)));
677    mediump uvec4 result;
678
679    switch (logic_op >> 16u & 0xFu)
680    {
681        case kAnd:
682            result = src & dst;
683            break;
684        case kAndInverted:
685            result = ~src & dst;
686            break;
687        case kAndReverse:
688            result = src & ~dst;
689            break;
690        case kClear:
691            result = uvec4(0);
692            break;
693        case kCopy:
694            result = src;
695            break;
696        case kCopyInverted:
697            result = ~src;
698            break;
699        case kEquiv:
700            result = ~(src ^ dst);
701            break;
702        case kInvert:
703            result = ~dst;
704            break;
705        case kNand:
706            result = ~(src & dst);
707            break;
708        case kNoop:
709            result = dst;
710            break;
711        case kNor:
712            result = ~(src | dst);
713            break;
714        case kOr:
715            result = src | dst;
716            break;
717        case kOrInverted:
718            result = ~src | dst;
719            break;
720        case kOrReverse:
721            result = src | ~dst;
722            break;
723        case kSet:
724            result = channelMasks;
725            break;
726        case kXor:
727            result = src ^ dst;
728            break;
729    }
730
731    result &= channelMasks;
732
733    // Avoid division by zero for formats without alpha
734    channelMasks.a = max(channelMasks.a, 1u);
735
736    return vec4(result) / vec4(channelMasks);
737}
738)";
739
740constexpr char kGLES1DrawFShaderMultitexturing[] = R"(
741
742bool isTextureUnitEnabled(uint unit)
743{
744    return enable_texture_2d[unit] || enable_texture_cube_map[unit];
745}
746
747mediump vec4 getTextureColor(uint unit)
748{
749    mediump vec4 res;
750
751    switch (unit)
752    {
753#if kTexUnits >= 1u
754        case 0u:
755            if (enable_texture_2d[0])
756            {
757                res = texture(tex_sampler0, texcoord0_varying.xy);
758            }
759            else if (enable_texture_cube_map[0])
760            {
761                res = texture(tex_cube_sampler0, texcoord0_varying);
762            }
763            break;
764#endif
765#if kTexUnits >= 2u
766        case 1u:
767            if (enable_texture_2d[1])
768            {
769                res = texture(tex_sampler1, texcoord1_varying.xy);
770            }
771            else if (enable_texture_cube_map[1])
772            {
773                res = texture(tex_cube_sampler1, texcoord1_varying);
774            }
775            break;
776#endif
777#if kTexUnits >= 3u
778        case 2u:
779            if (enable_texture_2d[2])
780            {
781                res = texture(tex_sampler2, texcoord2_varying.xy);
782            }
783            else if (enable_texture_cube_map[2])
784            {
785                res = texture(tex_cube_sampler2, texcoord2_varying);
786            }
787            break;
788#endif
789#if kTexUnits >= 4u
790        case 3u:
791            if (enable_texture_2d[3])
792            {
793                res = texture(tex_sampler3, texcoord3_varying.xy);
794            }
795            else if (enable_texture_cube_map[3])
796            {
797                // TODO: Weird stuff happens
798                // res = texture(tex_cube_sampler3, texcoord3_varying);
799            }
800            break;
801#endif
802        default:
803            break;
804    }
805
806    return res;
807}
808
809mediump vec4 getPointSpriteTextureColor(uint unit)
810{
811    mediump vec4 res;
812
813    switch (unit)
814    {
815        case 0u:
816            if (enable_texture_2d[0])
817            {
818                res = texture(tex_sampler0, gl_PointCoord.xy);
819            }
820            break;
821        case 1u:
822            if (enable_texture_2d[1])
823            {
824                res = texture(tex_sampler1, gl_PointCoord.xy);
825            }
826            break;
827        case 2u:
828            if (enable_texture_2d[2])
829            {
830                res = texture(tex_sampler2, gl_PointCoord.xy);
831            }
832            break;
833        case 3u:
834            if (enable_texture_2d[3])
835            {
836                res = texture(tex_sampler3, gl_PointCoord.xy);
837            }
838            break;
839        default:
840            break;
841    }
842
843    return res;
844}
845
846mediump vec3 textureCombineSrcnOpnRgb(uint srcnRgb,
847                                      uint opnRgb,
848                                      mediump vec4 textureEnvColor,
849                                      mediump vec4 vertexColor,
850                                      mediump vec4 texturePrevColor,
851                                      mediump vec4 textureColor)
852{
853    mediump vec3 res;
854    mediump vec4 op;
855
856    switch (srcnRgb)
857    {
858        case kTexture:
859            op = textureColor;
860            break;
861        case kConstant:
862            op = textureEnvColor;
863            break;
864        case kPrimaryColor:
865            op = vertexColor;
866            break;
867        case kPrevious:
868            op = texturePrevColor;
869            break;
870        default:
871            op = texturePrevColor;
872            break;
873    }
874
875    switch (opnRgb)
876    {
877        case kSrcColor:
878            res = op.rgb;
879            break;
880        case kOneMinusSrcColor:
881            res = 1.0 - op.rgb;
882            break;
883        case kSrcAlpha:
884            res = vec3(op.a, op.a, op.a);
885            break;
886        case kOneMinusSrcAlpha:
887            res = vec3(1.0 - op.a, 1.0 - op.a, 1.0 - op.a);
888            break;
889        default:
890            break;
891    }
892
893    return res;
894}
895
896mediump float textureCombineSrcnOpnAlpha(uint srcn,
897                                         uint opn,
898                                         mediump vec4 textureEnvColor,
899                                         mediump vec4 vertexColor,
900                                         mediump vec4 texturePrevColor,
901                                         mediump vec4 textureColor)
902{
903    mediump float res;
904    mediump vec4 op;
905
906    switch (srcn)
907    {
908        case kTexture:
909            op = textureColor;
910            break;
911        case kConstant:
912            op = textureEnvColor;
913            break;
914        case kPrimaryColor:
915            op = vertexColor;
916            break;
917        case kPrevious:
918            op = texturePrevColor;
919            break;
920        default:
921            op = texturePrevColor;
922            break;
923    }
924
925    switch (opn)
926    {
927        case kSrcAlpha:
928            res = op.a;
929            break;
930        case kOneMinusSrcAlpha:
931            res = 1.0 - op.a;
932            break;
933        default:
934            break;
935    }
936
937    return res;
938}
939
940mediump vec4 textureCombine(uint combineRgb,
941                            uint combineAlpha,
942                            uint src0Rgb,
943                            uint src0Alpha,
944                            uint src1Rgb,
945                            uint src1Alpha,
946                            uint src2Rgb,
947                            uint src2Alpha,
948                            uint op0Rgb,
949                            uint op0Alpha,
950                            uint op1Rgb,
951                            uint op1Alpha,
952                            uint op2Rgb,
953                            uint op2Alpha,
954                            mediump vec4 textureEnvColor,
955                            mediump float rgbScale,
956                            mediump float alphaScale,
957                            mediump vec4 vertexColor,
958                            mediump vec4 texturePrevColor,
959                            mediump vec4 textureColor)
960{
961
962    mediump vec3 resRgb;
963    mediump float resAlpha;
964
965    mediump vec3 arg0Rgb;
966    mediump float arg0Alpha;
967    mediump vec3 arg1Rgb;
968    mediump float arg1Alpha;
969    mediump vec3 arg2Rgb;
970    mediump float arg2Alpha;
971    mediump float dotVal;
972
973    arg0Rgb   = textureCombineSrcnOpnRgb(src0Rgb, op0Rgb, textureEnvColor, vertexColor,
974                                       texturePrevColor, textureColor);
975    arg0Alpha = textureCombineSrcnOpnAlpha(src0Alpha, op0Alpha, textureEnvColor, vertexColor,
976                                           texturePrevColor, textureColor);
977
978    if (combineRgb != kReplace)
979    {
980        arg1Rgb = textureCombineSrcnOpnRgb(src1Rgb, op1Rgb, textureEnvColor, vertexColor,
981                                           texturePrevColor, textureColor);
982    }
983
984    if (combineAlpha != kReplace)
985    {
986        arg1Alpha = textureCombineSrcnOpnAlpha(src1Alpha, op1Alpha, textureEnvColor, vertexColor,
987                                               texturePrevColor, textureColor);
988    }
989
990    if (combineRgb == kInterpolate)
991    {
992        arg2Rgb = textureCombineSrcnOpnRgb(src2Rgb, op2Rgb, textureEnvColor, vertexColor,
993                                           texturePrevColor, textureColor);
994    }
995
996    if (combineAlpha == kInterpolate)
997    {
998        arg2Alpha = textureCombineSrcnOpnAlpha(src2Alpha, op2Alpha, textureEnvColor, vertexColor,
999                                               texturePrevColor, textureColor);
1000    }
1001
1002    switch (combineRgb)
1003    {
1004        case kReplace:
1005            resRgb = arg0Rgb;
1006            break;
1007        case kModulate:
1008            resRgb = arg0Rgb * arg1Rgb;
1009            break;
1010        case kAdd:
1011            resRgb = arg0Rgb + arg1Rgb;
1012            break;
1013        case kAddSigned:
1014            resRgb = arg0Rgb + arg1Rgb - 0.5;
1015            break;
1016        case kInterpolate:
1017            resRgb = arg0Rgb * arg2Rgb + arg1Rgb * (1.0 - arg2Rgb);
1018            break;
1019        case kSubtract:
1020            resRgb = arg0Rgb - arg1Rgb;
1021            break;
1022        default:
1023            break;
1024    }
1025
1026    switch (combineAlpha)
1027    {
1028        case kReplace:
1029            resAlpha = arg0Alpha;
1030            break;
1031        case kModulate:
1032            resAlpha = arg0Alpha * arg1Alpha;
1033            break;
1034        case kAdd:
1035            resAlpha = arg0Alpha + arg1Alpha;
1036            break;
1037        case kAddSigned:
1038            resAlpha = arg0Alpha + arg1Alpha - 0.5;
1039            break;
1040        case kInterpolate:
1041            resAlpha = arg0Alpha * arg2Alpha + arg1Alpha * (1.0 - arg2Alpha);
1042            break;
1043        case kSubtract:
1044            resAlpha = arg0Alpha - arg1Alpha;
1045            break;
1046        default:
1047            break;
1048    }
1049
1050    if (combineRgb == kDot3Rgb || combineRgb == kDot3Rgba)
1051    {
1052        dotVal = 4.0 * dot(arg0Rgb - 0.5, arg1Rgb - 0.5);
1053
1054        if (combineRgb == kDot3Rgb)
1055        {
1056            return vec4(dotVal, dotVal, dotVal, resAlpha);
1057        }
1058        else
1059        {
1060            return vec4(dotVal, dotVal, dotVal, dotVal);
1061        }
1062    }
1063    else
1064    {
1065        return vec4(resRgb, resAlpha);
1066    }
1067}
1068
1069mediump vec4 textureFunction(uint unit,
1070                             uint texFormat,
1071                             uint envMode,
1072                             uint combineRgb,
1073                             uint combineAlpha,
1074                             uint src0Rgb,
1075                             uint src0Alpha,
1076                             uint src1Rgb,
1077                             uint src1Alpha,
1078                             uint src2Rgb,
1079                             uint src2Alpha,
1080                             uint op0Rgb,
1081                             uint op0Alpha,
1082                             uint op1Rgb,
1083                             uint op1Alpha,
1084                             uint op2Rgb,
1085                             uint op2Alpha,
1086                             mediump vec4 textureEnvColor,
1087                             mediump float rgbScale,
1088                             mediump float alphaScale,
1089                             mediump vec4 vertexColor,
1090                             mediump vec4 texturePrevColor,
1091                             mediump vec4 textureColor)
1092{
1093
1094    if (!isTextureUnitEnabled(unit))
1095    {
1096        return texturePrevColor;
1097    }
1098
1099    mediump vec4 res;
1100
1101    switch (envMode)
1102    {
1103        case kReplace:
1104            switch (texFormat)
1105            {
1106                case kAlpha:
1107                    res.rgb = texturePrevColor.rgb;
1108                    res.a   = textureColor.a;
1109                    break;
1110                case kRGBA:
1111                case kLuminanceAlpha:
1112                    res.rgba = textureColor.rgba;
1113                    break;
1114                case kRGB:
1115                case kLuminance:
1116                default:
1117                    res.rgb = textureColor.rgb;
1118                    res.a   = texturePrevColor.a;
1119                    break;
1120            }
1121            break;
1122        case kModulate:
1123            switch (texFormat)
1124            {
1125                case kAlpha:
1126                    res.rgb = texturePrevColor.rgb;
1127                    res.a   = texturePrevColor.a * textureColor.a;
1128                    break;
1129                case kRGBA:
1130                case kLuminanceAlpha:
1131                    res.rgba = texturePrevColor.rgba * textureColor.rgba;
1132                    break;
1133                case kRGB:
1134                case kLuminance:
1135                default:
1136                    res.rgb = texturePrevColor.rgb * textureColor.rgb;
1137                    res.a   = texturePrevColor.a;
1138                    break;
1139            }
1140            break;
1141        case kDecal:
1142            switch (texFormat)
1143            {
1144                case kRGB:
1145                    res.rgb = textureColor.rgb;
1146                    res.a   = texturePrevColor.a;
1147                    break;
1148                case kRGBA:
1149                    res.rgb = texturePrevColor.rgb * (1.0 - textureColor.a) +
1150                              textureColor.rgb * textureColor.a;
1151                    res.a = texturePrevColor.a;
1152                    break;
1153                case kAlpha:
1154                case kLuminance:
1155                case kLuminanceAlpha:
1156                default:
1157                    res.rgb = texturePrevColor.rgb * textureColor.rgb;
1158                    res.a   = texturePrevColor.a;
1159                    break;
1160            }
1161            break;
1162        case kBlend:
1163            switch (texFormat)
1164            {
1165                case kAlpha:
1166                    res.rgb = texturePrevColor.rgb;
1167                    res.a   = textureColor.a * texturePrevColor.a;
1168                    break;
1169                case kLuminance:
1170                case kRGB:
1171                    res.rgb = texturePrevColor.rgb * (1.0 - textureColor.rgb) +
1172                              textureEnvColor.rgb * textureColor.rgb;
1173                    res.a = texturePrevColor.a;
1174                    break;
1175                case kLuminanceAlpha:
1176                case kRGBA:
1177                default:
1178                    res.rgb = texturePrevColor.rgb * (1.0 - textureColor.rgb) +
1179                              textureEnvColor.rgb * textureColor.rgb;
1180                    res.a = textureColor.a * texturePrevColor.a;
1181                    break;
1182            }
1183            break;
1184        case kAdd:
1185            switch (texFormat)
1186            {
1187                case kAlpha:
1188                    res.rgb = texturePrevColor.rgb;
1189                    res.a   = textureColor.a * texturePrevColor.a;
1190                    break;
1191                case kLuminance:
1192                case kRGB:
1193                    res.rgb = texturePrevColor.rgb + textureColor.rgb;
1194                    res.a   = texturePrevColor.a;
1195                    break;
1196                case kLuminanceAlpha:
1197                case kRGBA:
1198                default:
1199                    res.rgb = texturePrevColor.rgb + textureColor.rgb;
1200                    res.a   = textureColor.a * texturePrevColor.a;
1201                    break;
1202            }
1203            break;
1204        case kCombine:
1205            res = textureCombine(combineRgb, combineAlpha, src0Rgb, src0Alpha, src1Rgb, src1Alpha,
1206                                 src2Rgb, src2Alpha, op0Rgb, op0Alpha, op1Rgb, op1Alpha, op2Rgb,
1207                                 op2Alpha, textureEnvColor, rgbScale, alphaScale, vertexColor,
1208                                 texturePrevColor, textureColor);
1209            res.rgb *= rgbScale;
1210            res.a *= alphaScale;
1211            break;
1212        default:
1213            break;
1214    }
1215
1216    return clamp(res, 0.0, 1.0);
1217}
1218)";
1219
1220constexpr char kGLES1DrawFShaderMain[] = R"(
1221void main()
1222{
1223    if (enable_clip_planes && !enable_draw_texture)
1224    {
1225        if (!doClipPlaneTest())
1226        {
1227            discard;
1228        }
1229    }
1230
1231    mediump vec4 vertex_color;
1232
1233    if (shade_model_flat)
1234    {
1235        vertex_color = color_varying_flat;
1236    }
1237    else
1238    {
1239        vertex_color = color_varying;
1240    }
1241
1242    mediump vec4 currentFragment = vertex_color;
1243
1244    mediump vec4 texturePrevColor = currentFragment;
1245
1246    for (uint i = 0u; i < kTexUnits; i++)
1247    {
1248        mediump vec4 textureColor;
1249
1250        if (point_rasterization && point_sprite_enabled &&
1251            point_sprite_coord_replace[i]) {
1252            textureColor = getPointSpriteTextureColor(i);
1253        } else {
1254            textureColor = getTextureColor(i);
1255        }
1256
1257        currentFragment = textureFunction(
1258            i, texture_format[i], texture_env_mode[i], combine_rgb[i], combine_alpha[i],
1259            src0_rgb[i], src0_alpha[i], src1_rgb[i], src1_alpha[i], src2_rgb[i], src2_alpha[i],
1260            op0_rgb[i], op0_alpha[i], op1_rgb[i], op1_alpha[i], op2_rgb[i], op2_alpha[i],
1261            texture_env_color[i], texture_env_rgb_scale[i], texture_env_alpha_scale[i],
1262            vertex_color, texturePrevColor, textureColor);
1263
1264        texturePrevColor = currentFragment;
1265    }
1266
1267    if (enable_fog)
1268    {
1269        currentFragment = doFog(currentFragment);
1270    }
1271
1272    if (enable_alpha_test && !doAlphaTest(currentFragment))
1273    {
1274        discard;
1275    }
1276
1277    frag_color = applyLogicOp(currentFragment);
1278}
1279)";
1280