GLES1: Lighting and materials (renderer)

- Update test expectations
- Add gles1 sample app that shows simple lighting.

BUG=angleproject:2306

Change-Id: I545dcf860374abd9d628b0d554153cb634098f6d
Reviewed-on: https://chromium-review.googlesource.com/1065501
Commit-Queue: Lingfeng Yang <lfy@google.com>
Reviewed-by: Corentin Wallez <cwallez@chromium.org>
diff --git a/samples/BUILD.gn b/samples/BUILD.gn
index 61692bf..80043bf 100644
--- a/samples/BUILD.gn
+++ b/samples/BUILD.gn
@@ -185,6 +185,12 @@
   ]
 }
 
+angle_sample("gles1_simple_lighting") {
+  sources = [
+    "gles1/SimpleLighting.cpp",
+  ]
+}
+
 group("all") {
   testonly = true
   deps = [
diff --git a/samples/gles1/SimpleLighting.cpp b/samples/gles1/SimpleLighting.cpp
new file mode 100644
index 0000000..a97e8ca
--- /dev/null
+++ b/samples/gles1/SimpleLighting.cpp
@@ -0,0 +1,124 @@
+//
+// Copyright 2018 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+
+//            Based on Hello_Triangle.c from
+// Book:      OpenGL(R) ES 2.0 Programming Guide
+// Authors:   Aaftab Munshi, Dan Ginsburg, Dave Shreiner
+// ISBN-10:   0321502795
+// ISBN-13:   9780321502797
+// Publisher: Addison-Wesley Professional
+// URLs:      http://safari.informit.com/9780321563835
+//            http://www.opengles-book.com
+
+#include "SampleApplication.h"
+
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+
+#include <algorithm>
+
+class SimpleLightingSample : public SampleApplication
+{
+  public:
+    SimpleLightingSample(EGLint displayType)
+        : SampleApplication("SimpleLightingSample", 1280, 720, 1, 0, displayType)
+    {
+    }
+
+    virtual bool initialize()
+    {
+        glClearColor(0.4f, 0.3f, 0.2f, 1.0f);
+        mRotDeg = 0.0f;
+
+        return true;
+    }
+
+    virtual void destroy() {}
+
+    virtual void draw()
+    {
+
+        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+        glColor4f(0.2f, 0.6f, 0.8f, 1.0f);
+
+        GLfloat mat_ambient[]  = {0.7f, 0.4f, 0.2f, 1.0f};
+        GLfloat mat_specular[] = {0.5f, 0.5f, 0.5f, 1.0f};
+        GLfloat mat_diffuse[]  = {0.3f, 0.4f, 0.6f, 1.0f};
+        GLfloat lightpos[]     = {0.0f, 1.0f, 0.0f, 0.0f};
+
+        GLfloat normals[] = {
+            -0.4f, 0.4f, -0.4f, -0.4f, -0.4f, -0.4f, 0.2f, 0.0f, -0.4f,
+
+            -0.4f, 0.4f, 0.4f,  -0.4f, -0.4f, 0.4f,  0.2f, 0.0f, 0.4f,
+        };
+
+        GLfloat vertices[] = {
+            -0.5f, 0.5f, 0.0f, -0.5f, -0.5f, 0.0f, 0.5f, 0.0f, 0.0f,
+
+            -0.5f, 0.5f, 0.3f, -0.5f, -0.5f, 0.3f, 0.5f, 0.0f, 0.3f,
+        };
+
+        GLuint indices[] = {
+            0, 1, 2, 3, 4, 5,
+
+            0, 4, 3, 4, 0, 1,
+
+            4, 1, 2, 2, 5, 4,
+
+            5, 2, 3, 3, 2, 0,
+        };
+
+        glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mat_ambient);
+        glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular);
+        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat_diffuse);
+
+        glEnable(GL_DEPTH_TEST);
+        glEnable(GL_LIGHTING);
+        glEnable(GL_LIGHT0);
+        glLightfv(GL_LIGHT0, GL_POSITION, lightpos);
+
+        glEnableClientState(GL_VERTEX_ARRAY);
+        glEnableClientState(GL_NORMAL_ARRAY);
+        glVertexPointer(3, GL_FLOAT, 0, vertices);
+        glNormalPointer(GL_FLOAT, 0, normals);
+
+        for (int i = 0; i < 3; i++)
+        {
+            for (int j = 0; j < 3; j++)
+            {
+                glPushMatrix();
+
+                glTranslatef(-0.6f + i * 0.6f, -0.6f + j * 0.6f, 0.0f);
+
+                glRotatef(mRotDeg + (10.0f * (3.0f * i + j)), 0.0f, 1.0f, 0.0f);
+                glRotatef(20.0f + (20.0f * (3.0f * i + j)), 1.0f, 0.0f, 0.0f);
+                GLfloat scale = 0.5;
+                glScalef(scale, scale, scale);
+                glDrawElements(GL_TRIANGLES, 3 * 8, GL_UNSIGNED_INT, indices);
+
+                glPopMatrix();
+            }
+        }
+
+        mRotDeg += 0.03f;
+    }
+
+  private:
+    float mRotDeg;
+};
+
+int main(int argc, char **argv)
+{
+    EGLint displayType = EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE;
+
+    if (argc > 1)
+    {
+        displayType = GetDisplayTypeFromArg(argv[1]);
+    }
+
+    SimpleLightingSample app(displayType);
+    return app.run();
+}
diff --git a/src/libANGLE/GLES1Renderer.cpp b/src/libANGLE/GLES1Renderer.cpp
index 6d3e901..d43291e 100644
--- a/src/libANGLE/GLES1Renderer.cpp
+++ b/src/libANGLE/GLES1Renderer.cpp
@@ -85,27 +85,18 @@
         }
     }
 
+    // Matrices
     {
         angle::Mat4 proj = gles1State.mProjectionMatrices.back();
-        if (mProgramState.projMatrixLoc != -1)
-        {
-            programObject->setUniformMatrix4fv(mProgramState.projMatrixLoc, 1, GL_FALSE,
-                                               proj.data());
-        }
+        setUniformMatrix4fv(programObject, mProgramState.projMatrixLoc, 1, GL_FALSE, proj.data());
 
         angle::Mat4 modelview = gles1State.mModelviewMatrices.back();
-        if (mProgramState.modelviewMatrixLoc != -1)
-        {
-            programObject->setUniformMatrix4fv(mProgramState.modelviewMatrixLoc, 1, GL_FALSE,
-                                               modelview.data());
-        }
+        setUniformMatrix4fv(programObject, mProgramState.modelviewMatrixLoc, 1, GL_FALSE,
+                            modelview.data());
 
         angle::Mat4 modelviewInvTr = modelview.transpose().inverse();
-        if (mProgramState.modelviewInvTrLoc != -1)
-        {
-            programObject->setUniformMatrix4fv(mProgramState.modelviewInvTrLoc, 1, GL_FALSE,
-                                               modelviewInvTr.data());
-        }
+        setUniformMatrix4fv(programObject, mProgramState.modelviewInvTrLoc, 1, GL_FALSE,
+                            modelviewInvTr.data());
 
         Mat4Uniform *textureMatrixBuffer = uniformBuffers.textureMatrices.data();
 
@@ -115,13 +106,11 @@
             memcpy(textureMatrixBuffer + i, textureMatrix.data(), sizeof(Mat4Uniform));
         }
 
-        if (mProgramState.textureMatrixLoc != -1)
-        {
-            programObject->setUniformMatrix4fv(mProgramState.textureMatrixLoc, 4, GL_FALSE,
-                                               (float *)uniformBuffers.textureMatrices.data());
-        }
+        setUniformMatrix4fv(programObject, mProgramState.textureMatrixLoc, kTexUnitCount, GL_FALSE,
+                            (float *)uniformBuffers.textureMatrices.data());
     }
 
+    // Texturing
     {
         std::array<GLint, kTexUnitCount> &tex2DEnables   = uniformBuffers.tex2DEnables;
         std::array<GLint, kTexUnitCount> &texCubeEnables = uniformBuffers.texCubeEnables;
@@ -151,23 +140,87 @@
                 !texCubeEnables[i] && (gles1State.isTextureTargetEnabled(i, TextureType::_2D));
         }
 
-        if (mProgramState.enableTexture2DLoc != -1)
+        setUniform1iv(programObject, mProgramState.enableTexture2DLoc, kTexUnitCount,
+                      tex2DEnables.data());
+        setUniform1iv(programObject, mProgramState.enableTextureCubeMapLoc, kTexUnitCount,
+                      texCubeEnables.data());
+    }
+
+    // Shading, materials, and lighting
+    {
+        setUniform1i(programObject, mProgramState.shadeModelFlatLoc,
+                     gles1State.mShadeModel == ShadingModel::Flat);
+        setUniform1i(programObject, mProgramState.enableLightingLoc,
+                     glState->getEnableFeature(GL_LIGHTING));
+        setUniform1i(programObject, mProgramState.enableRescaleNormalLoc,
+                     glState->getEnableFeature(GL_RESCALE_NORMAL));
+        setUniform1i(programObject, mProgramState.enableNormalizeLoc,
+                     glState->getEnableFeature(GL_NORMALIZE));
+        setUniform1i(programObject, mProgramState.enableColorMaterialLoc,
+                     glState->getEnableFeature(GL_COLOR_MATERIAL));
+
+        const auto &material = gles1State.mMaterial;
+
+        setUniform4fv(programObject, mProgramState.materialAmbientLoc, 1, material.ambient.data());
+        setUniform4fv(programObject, mProgramState.materialDiffuseLoc, 1, material.diffuse.data());
+        setUniform4fv(programObject, mProgramState.materialSpecularLoc, 1,
+                      material.specular.data());
+        setUniform4fv(programObject, mProgramState.materialEmissiveLoc, 1,
+                      material.emissive.data());
+        setUniform1f(programObject, mProgramState.materialSpecularExponentLoc,
+                     material.specularExponent);
+
+        const auto &lightModel = gles1State.mLightModel;
+
+        setUniform4fv(programObject, mProgramState.lightModelSceneAmbientLoc, 1,
+                      lightModel.color.data());
+
+        // TODO (lfy@google.com): Implement two-sided lighting model
+        // gl->uniform1i(mProgramState.lightModelTwoSidedLoc, lightModel.twoSided);
+
+        for (int i = 0; i < kLightCount; i++)
         {
-            programObject->setUniform1iv(mProgramState.enableTexture2DLoc, kTexUnitCount,
-                                         tex2DEnables.data());
-        }
-        if (mProgramState.enableTextureCubeMapLoc != -1)
-        {
-            programObject->setUniform1iv(mProgramState.enableTextureCubeMapLoc, kTexUnitCount,
-                                         texCubeEnables.data());
+            const auto &light              = gles1State.mLights[i];
+            uniformBuffers.lightEnables[i] = light.enabled;
+            memcpy(uniformBuffers.lightAmbients.data() + i, light.ambient.data(),
+                   sizeof(Vec4Uniform));
+            memcpy(uniformBuffers.lightDiffuses.data() + i, light.diffuse.data(),
+                   sizeof(Vec4Uniform));
+            memcpy(uniformBuffers.lightSpeculars.data() + i, light.specular.data(),
+                   sizeof(Vec4Uniform));
+            memcpy(uniformBuffers.lightPositions.data() + i, light.position.data(),
+                   sizeof(Vec4Uniform));
+            memcpy(uniformBuffers.lightDirections.data() + i, light.direction.data(),
+                   sizeof(Vec3Uniform));
+            uniformBuffers.spotlightExponents[i]    = light.spotlightExponent;
+            uniformBuffers.spotlightCutoffAngles[i] = light.spotlightCutoffAngle;
+            uniformBuffers.attenuationConsts[i]     = light.attenuationConst;
+            uniformBuffers.attenuationLinears[i]    = light.attenuationLinear;
+            uniformBuffers.attenuationQuadratics[i] = light.attenuationQuadratic;
         }
 
-        GLint flatShading = gles1State.mShadeModel == ShadingModel::Flat;
-
-        if (mProgramState.shadeModelFlatLoc != -1)
-        {
-            programObject->setUniform1iv(mProgramState.shadeModelFlatLoc, 1, &flatShading);
-        }
+        setUniform1iv(programObject, mProgramState.lightEnablesLoc, kLightCount,
+                      uniformBuffers.lightEnables.data());
+        setUniform4fv(programObject, mProgramState.lightAmbientsLoc, kLightCount,
+                      (GLfloat *)uniformBuffers.lightAmbients.data());
+        setUniform4fv(programObject, mProgramState.lightDiffusesLoc, kLightCount,
+                      (GLfloat *)uniformBuffers.lightDiffuses.data());
+        setUniform4fv(programObject, mProgramState.lightSpecularsLoc, kLightCount,
+                      (GLfloat *)uniformBuffers.lightSpeculars.data());
+        setUniform4fv(programObject, mProgramState.lightPositionsLoc, kLightCount,
+                      (GLfloat *)uniformBuffers.lightPositions.data());
+        setUniform3fv(programObject, mProgramState.lightDirectionsLoc, kLightCount,
+                      (GLfloat *)uniformBuffers.lightDirections.data());
+        setUniform1fv(programObject, mProgramState.lightSpotlightExponentsLoc, kLightCount,
+                      (GLfloat *)uniformBuffers.spotlightExponents.data());
+        setUniform1fv(programObject, mProgramState.lightSpotlightCutoffAnglesLoc, kLightCount,
+                      (GLfloat *)uniformBuffers.spotlightCutoffAngles.data());
+        setUniform1fv(programObject, mProgramState.lightAttenuationConstsLoc, kLightCount,
+                      (GLfloat *)uniformBuffers.attenuationConsts.data());
+        setUniform1fv(programObject, mProgramState.lightAttenuationLinearsLoc, kLightCount,
+                      (GLfloat *)uniformBuffers.attenuationLinears.data());
+        setUniform1fv(programObject, mProgramState.lightAttenuationQuadraticsLoc, kLightCount,
+                      (GLfloat *)uniformBuffers.attenuationQuadratics.data());
     }
 
     // None of those are changes in sampler, so there is no need to set the GL_PROGRAM dirty.
@@ -377,28 +430,53 @@
             programObject->getUniformLocation(sscube.str().c_str());
     }
 
-    mProgramState.shadeModelFlatLoc = programObject->getUniformLocation("shade_model_flat");
-
     mProgramState.enableTexture2DLoc = programObject->getUniformLocation("enable_texture_2d");
     mProgramState.enableTextureCubeMapLoc =
         programObject->getUniformLocation("enable_texture_cube_map");
 
+    mProgramState.shadeModelFlatLoc = programObject->getUniformLocation("shade_model_flat");
+    mProgramState.enableLightingLoc = programObject->getUniformLocation("enable_lighting");
+    mProgramState.enableRescaleNormalLoc =
+        programObject->getUniformLocation("enable_rescale_normal");
+    mProgramState.enableNormalizeLoc = programObject->getUniformLocation("enable_normalize");
+    mProgramState.enableColorMaterialLoc =
+        programObject->getUniformLocation("enable_color_material");
+
+    mProgramState.materialAmbientLoc  = programObject->getUniformLocation("material_ambient");
+    mProgramState.materialDiffuseLoc  = programObject->getUniformLocation("material_diffuse");
+    mProgramState.materialSpecularLoc = programObject->getUniformLocation("material_specular");
+    mProgramState.materialEmissiveLoc = programObject->getUniformLocation("material_emissive");
+    mProgramState.materialSpecularExponentLoc =
+        programObject->getUniformLocation("material_specular_exponent");
+
+    mProgramState.lightModelSceneAmbientLoc =
+        programObject->getUniformLocation("light_model_scene_ambient");
+    mProgramState.lightModelTwoSidedLoc =
+        programObject->getUniformLocation("light_model_two_sided");
+
+    mProgramState.lightEnablesLoc    = programObject->getUniformLocation("light_enables");
+    mProgramState.lightAmbientsLoc   = programObject->getUniformLocation("light_ambients");
+    mProgramState.lightDiffusesLoc   = programObject->getUniformLocation("light_diffuses");
+    mProgramState.lightSpecularsLoc  = programObject->getUniformLocation("light_speculars");
+    mProgramState.lightPositionsLoc  = programObject->getUniformLocation("light_positions");
+    mProgramState.lightDirectionsLoc = programObject->getUniformLocation("light_directions");
+    mProgramState.lightSpotlightExponentsLoc =
+        programObject->getUniformLocation("light_spotlight_exponents");
+    mProgramState.lightSpotlightCutoffAnglesLoc =
+        programObject->getUniformLocation("light_spotlight_cutoff_angles");
+    mProgramState.lightAttenuationConstsLoc =
+        programObject->getUniformLocation("light_attenuation_consts");
+    mProgramState.lightAttenuationLinearsLoc =
+        programObject->getUniformLocation("light_attenuation_linears");
+    mProgramState.lightAttenuationQuadraticsLoc =
+        programObject->getUniformLocation("light_attenuation_quadratics");
+
     glState->setProgram(context, programObject);
 
     for (int i = 0; i < kTexUnitCount; i++)
     {
-
-        if (mProgramState.tex2DSamplerLocs[i] != -1)
-        {
-            GLint val = i;
-            programObject->setUniform1iv(mProgramState.tex2DSamplerLocs[i], 1, &val);
-        }
-
-        if (mProgramState.texCubeSamplerLocs[i] != -1)
-        {
-            GLint val = i + kTexUnitCount;
-            programObject->setUniform1iv(mProgramState.texCubeSamplerLocs[i], 1, &val);
-        }
+        setUniform1i(programObject, mProgramState.tex2DSamplerLocs[i], i);
+        setUniform1i(programObject, mProgramState.texCubeSamplerLocs[i], i + kTexUnitCount);
     }
 
     glState->setObjectDirty(GL_PROGRAM);
@@ -407,4 +485,69 @@
     return NoError();
 }
 
+void GLES1Renderer::setUniform1i(Program *programObject, GLint loc, GLint value)
+{
+    if (loc == -1)
+        return;
+    programObject->setUniform1iv(loc, 1, &value);
+}
+
+void GLES1Renderer::setUniform1iv(Program *programObject,
+                                  GLint loc,
+                                  GLint count,
+                                  const GLint *value)
+{
+    if (loc == -1)
+        return;
+    programObject->setUniform1iv(loc, count, value);
+}
+
+void GLES1Renderer::setUniformMatrix4fv(Program *programObject,
+                                        GLint loc,
+                                        GLint count,
+                                        GLboolean transpose,
+                                        const GLfloat *value)
+{
+    if (loc == -1)
+        return;
+    programObject->setUniformMatrix4fv(loc, count, transpose, value);
+}
+
+void GLES1Renderer::setUniform4fv(Program *programObject,
+                                  GLint loc,
+                                  GLint count,
+                                  const GLfloat *value)
+{
+    if (loc == -1)
+        return;
+    programObject->setUniform4fv(loc, count, value);
+}
+
+void GLES1Renderer::setUniform3fv(Program *programObject,
+                                  GLint loc,
+                                  GLint count,
+                                  const GLfloat *value)
+{
+    if (loc == -1)
+        return;
+    programObject->setUniform3fv(loc, count, value);
+}
+
+void GLES1Renderer::setUniform1f(Program *programObject, GLint loc, GLfloat value)
+{
+    if (loc == -1)
+        return;
+    programObject->setUniform1fv(loc, 1, &value);
+}
+
+void GLES1Renderer::setUniform1fv(Program *programObject,
+                                  GLint loc,
+                                  GLint count,
+                                  const GLfloat *value)
+{
+    if (loc == -1)
+        return;
+    programObject->setUniform1fv(loc, count, value);
+}
+
 }  // namespace gl
diff --git a/src/libANGLE/GLES1Renderer.h b/src/libANGLE/GLES1Renderer.h
index b553ff3..4679a62 100644
--- a/src/libANGLE/GLES1Renderer.h
+++ b/src/libANGLE/GLES1Renderer.h
@@ -43,6 +43,8 @@
 
   private:
     using Mat4Uniform = float[16];
+    using Vec4Uniform = float[4];
+    using Vec3Uniform = float[3];
 
     Shader *getShader(GLuint handle) const;
     Program *getProgram(GLuint handle) const;
@@ -59,7 +61,20 @@
                       GLuint *programOut);
     Error initializeRendererProgram(Context *context, State *glState);
 
+    void setUniform1i(Program *programObject, GLint loc, GLint value);
+    void setUniform1iv(Program *programObject, GLint loc, GLint count, const GLint *value);
+    void setUniformMatrix4fv(Program *programObject,
+                             GLint loc,
+                             GLint count,
+                             GLboolean transpose,
+                             const GLfloat *value);
+    void setUniform4fv(Program *programObject, GLint loc, GLint count, const GLfloat *value);
+    void setUniform3fv(Program *programObject, GLint loc, GLint count, const GLfloat *value);
+    void setUniform1f(Program *programObject, GLint loc, GLfloat value);
+    void setUniform1fv(Program *programObject, GLint loc, GLint count, const GLfloat *value);
+
     static constexpr int kTexUnitCount = 4;
+    static constexpr int kLightCount   = 8;
 
     static constexpr int kVertexAttribIndex           = 0;
     static constexpr int kNormalAttribIndex           = 1;
@@ -79,13 +94,39 @@
         GLint textureMatrixLoc;
         GLint modelviewInvTrLoc;
 
-        std::array<GLint, kTexUnitCount> tex2DSamplerLocs;
-        std::array<GLint, kTexUnitCount> texCubeSamplerLocs;
-
+        // Shading, materials, and lighting
         GLint shadeModelFlatLoc;
+        GLint enableLightingLoc;
+        GLint enableRescaleNormalLoc;
+        GLint enableNormalizeLoc;
+        GLint enableColorMaterialLoc;
 
+        GLint materialAmbientLoc;
+        GLint materialDiffuseLoc;
+        GLint materialSpecularLoc;
+        GLint materialEmissiveLoc;
+        GLint materialSpecularExponentLoc;
+
+        GLint lightModelSceneAmbientLoc;
+        GLint lightModelTwoSidedLoc;
+
+        GLint lightEnablesLoc;
+        GLint lightAmbientsLoc;
+        GLint lightDiffusesLoc;
+        GLint lightSpecularsLoc;
+        GLint lightPositionsLoc;
+        GLint lightDirectionsLoc;
+        GLint lightSpotlightExponentsLoc;
+        GLint lightSpotlightCutoffAnglesLoc;
+        GLint lightAttenuationConstsLoc;
+        GLint lightAttenuationLinearsLoc;
+        GLint lightAttenuationQuadraticsLoc;
+
+        // Texturing
         GLint enableTexture2DLoc;
         GLint enableTextureCubeMapLoc;
+        std::array<GLint, kTexUnitCount> tex2DSamplerLocs;
+        std::array<GLint, kTexUnitCount> texCubeSamplerLocs;
     };
 
     struct GLES1UniformBuffers
@@ -93,6 +134,19 @@
         std::array<Mat4Uniform, kTexUnitCount> textureMatrices;
         std::array<GLint, kTexUnitCount> tex2DEnables;
         std::array<GLint, kTexUnitCount> texCubeEnables;
+
+        // Lighting
+        std::array<GLint, kLightCount> lightEnables;
+        std::array<Vec4Uniform, kLightCount> lightAmbients;
+        std::array<Vec4Uniform, kLightCount> lightDiffuses;
+        std::array<Vec4Uniform, kLightCount> lightSpeculars;
+        std::array<Vec4Uniform, kLightCount> lightPositions;
+        std::array<Vec3Uniform, kLightCount> lightDirections;
+        std::array<GLfloat, kLightCount> spotlightExponents;
+        std::array<GLfloat, kLightCount> spotlightCutoffAngles;
+        std::array<GLfloat, kLightCount> attenuationConsts;
+        std::array<GLfloat, kLightCount> attenuationLinears;
+        std::array<GLfloat, kLightCount> attenuationQuadratics;
     };
 
     GLES1UniformBuffers mUniformBuffers;
diff --git a/src/libANGLE/GLES1Shaders.inc b/src/libANGLE/GLES1Shaders.inc
index a468410..8f35cc8 100644
--- a/src/libANGLE/GLES1Shaders.inc
+++ b/src/libANGLE/GLES1Shaders.inc
@@ -25,6 +25,9 @@
 uniform mat4 modelview_invtr;
 uniform mat4 texture_matrix[4];
 
+uniform bool enable_rescale_normal;
+uniform bool enable_normalize;
+
 out vec4 pos_varying;
 out vec3 normal_varying;
 out vec4 color_varying;
@@ -41,6 +44,20 @@
     mat3 mvInvTr3 = mat3(modelview_invtr);
     normal_varying = mvInvTr3 * normal;
 
+    if (enable_rescale_normal) {
+        float rescale = 1.0;
+        vec3 rescaleVec = vec3(mvInvTr3[2]);
+        float len = length(rescaleVec);
+        if (len > 0.0) {
+            rescale = 1.0 / len;
+        }
+        normal_varying *= rescale;
+    }
+
+    if (enable_normalize) {
+        normal_varying = normalize(normal_varying);
+    }
+
     color_varying = color;
     color_varying_flat = color;
     pointsize_varying = pointsize;
@@ -145,10 +162,6 @@
 uniform sampler2D tex_sampler3;
 uniform samplerCube tex_cube_sampler3;
 
-// Global enables, alpha func, logic op ////////////////////////////////////////
-
-uniform bool shade_model_flat;
-
 // Vertex attributes////////////////////////////////////////////////////////////
 
 in vec4 pos_varying;
@@ -161,6 +174,33 @@
 in vec4 texcoord2_varying;
 in vec4 texcoord3_varying;
 
+// Shading: flat shading, lighting, and materials///////////////////////////////
+
+uniform bool shade_model_flat;
+uniform bool enable_lighting;
+uniform bool enable_color_material;
+
+uniform vec4 material_ambient;
+uniform vec4 material_diffuse;
+uniform vec4 material_specular;
+uniform vec4 material_emissive;
+uniform float material_specular_exponent;
+
+uniform vec4 light_model_scene_ambient;
+uniform bool light_model_two_sided;
+
+uniform bool light_enables[kMaxLights];
+uniform vec4 light_ambients[kMaxLights];
+uniform vec4 light_diffuses[kMaxLights];
+uniform vec4 light_speculars[kMaxLights];
+uniform vec4 light_positions[kMaxLights];
+uniform vec3 light_directions[kMaxLights];
+uniform float light_spotlight_exponents[kMaxLights];
+uniform float light_spotlight_cutoff_angles[kMaxLights];
+uniform float light_attenuation_consts[kMaxLights];
+uniform float light_attenuation_linears[kMaxLights];
+uniform float light_attenuation_quadratics[kMaxLights];
+
 // Outgoing fragment////////////////////////////////////////////////////////////
 
 out vec4 frag_color;
@@ -237,6 +277,100 @@
     return getTextureColor(unit);
 }
 
+float posDot(vec3 a, vec3 b) {
+    return max(dot(a, b), 0.0);
+}
+
+vec4 doLighting(vec4 currentFragment) {
+    vec4 materialAmbientActual = material_ambient;
+    vec4 materialDiffuseActual = material_diffuse;
+
+    if (enable_color_material || enable_texture_2d[0] || enable_texture_cube_map[0]) {
+        materialAmbientActual = currentFragment;
+        materialDiffuseActual = currentFragment;
+    }
+
+    vec4 lightingResult = material_emissive +
+               materialAmbientActual * light_model_scene_ambient;
+
+    for (int i = 0; i < kMaxLights; i++) {
+
+        if (!light_enables[i]) continue;
+
+        vec4 lightAmbient = light_ambients[i];
+        vec4 lightDiffuse = light_diffuses[i];
+        vec4 lightSpecular = light_speculars[i];
+        vec4 lightPos = light_positions[i];
+        vec3 lightDir = light_directions[i];
+        float attConst = light_attenuation_consts[i];
+        float attLinear = light_attenuation_linears[i];
+        float attQuadratic = light_attenuation_quadratics[i];
+        float spotAngle = light_spotlight_cutoff_angles[i];
+        float spotExponent = light_spotlight_exponents[i];
+
+        vec3 toLight;
+        if (lightPos.w == 0.0) {
+            toLight = lightPos.xyz;
+        } else {
+            toLight = (lightPos.xyz / lightPos.w - pos_varying.xyz);
+        }
+
+        float lightDist = length(toLight);
+        vec3 h = normalize(toLight) + vec3(0.0, 0.0, 1.0);
+        float ndotL = posDot(normal_varying, normalize(toLight));
+        float ndoth = posDot(normal_varying, normalize(h));
+
+        float specAtt;
+
+        if (ndotL != 0.0) {
+            specAtt = 1.0;
+        } else {
+            specAtt = 0.0;
+        }
+
+        float att;
+
+        if (lightPos.w != 0.0) {
+            float attDenom = (attConst + attLinear * lightDist +
+                              attQuadratic * lightDist * lightDist);
+            att = 1.0 / attDenom;
+        } else {
+            att = 1.0;
+        }
+
+        float spot;
+
+        float spotAngleCos = cos(radians(spotAngle));
+        vec3 toSurfaceDir = -normalize(toLight);
+        float spotDot = posDot(toSurfaceDir, normalize(lightDir));
+
+        if (spotAngle == 180.0 || lightPos.w == 0.0) {
+            spot = 1.0;
+        } else {
+            if (spotDot < spotAngleCos) {
+                spot = 0.0;
+            } else {
+                spot = pow(spotDot, spotExponent);
+            }
+        }
+
+        vec4 contrib = materialAmbientActual * lightAmbient;
+        contrib += ndotL * materialDiffuseActual * lightDiffuse;
+        if (ndoth > 0.0 && material_specular_exponent > 0.0) {
+            contrib += specAtt * pow(ndoth, material_specular_exponent) *
+                                 material_specular * lightSpecular;
+        } else {
+            if (ndoth > 0.0) {
+                contrib += specAtt * material_specular * lightSpecular;
+            }
+        }
+        contrib *= att * spot;
+        lightingResult += contrib;
+    }
+
+    return lightingResult;
+}
+
 )";
 
 constexpr char kGLES1DrawFShaderMain[] = R"(
@@ -257,6 +391,10 @@
     // Unit 0 only for now
     currentFragment = getColor(0, vertex_color);
 
+    if (enable_lighting) {
+        currentFragment = doLighting(currentFragment);
+    }
+
     frag_color = currentFragment;
 }
 )";
diff --git a/src/tests/gles1_conformance_tests/ConformanceTests.cpp b/src/tests/gles1_conformance_tests/ConformanceTests.cpp
index 895d3d9..930f3e8 100644
--- a/src/tests/gles1_conformance_tests/ConformanceTests.cpp
+++ b/src/tests/gles1_conformance_tests/ConformanceTests.cpp
@@ -137,19 +137,16 @@
 
 TEST_P(GLES1ConformanceTest, AmbLight)
 {
-    ANGLE_SKIP_TEST_IF(true);
     ASSERT_NE(CONFORMANCE_TEST_ERROR, AmbLightExec());
 }
 
 TEST_P(GLES1ConformanceTest, AmbMat)
 {
-    ANGLE_SKIP_TEST_IF(true);
     ASSERT_NE(CONFORMANCE_TEST_ERROR, AmbMatExec());
 }
 
 TEST_P(GLES1ConformanceTest, AmbScene)
 {
-    ANGLE_SKIP_TEST_IF(true);
     ASSERT_NE(CONFORMANCE_TEST_ERROR, AmbSceneExec());
 }
 
@@ -161,13 +158,11 @@
 
 TEST_P(GLES1ConformanceTest, AtnConst)
 {
-    ANGLE_SKIP_TEST_IF(true);
     ASSERT_NE(CONFORMANCE_TEST_ERROR, AtnConstExec());
 }
 
 TEST_P(GLES1ConformanceTest, AtnPos)
 {
-    ANGLE_SKIP_TEST_IF(true);
     ASSERT_NE(CONFORMANCE_TEST_ERROR, AtnPosExec());
 }
 
@@ -193,7 +188,6 @@
 
 TEST_P(GLES1ConformanceTest, Clip)
 {
-    ANGLE_SKIP_TEST_IF(true);
     ASSERT_NE(CONFORMANCE_TEST_ERROR, ClipExec());
 }
 
@@ -210,25 +204,21 @@
 
 TEST_P(GLES1ConformanceTest, DifLight)
 {
-    ANGLE_SKIP_TEST_IF(true);
     ASSERT_NE(CONFORMANCE_TEST_ERROR, DifLightExec());
 }
 
 TEST_P(GLES1ConformanceTest, DifMat)
 {
-    ANGLE_SKIP_TEST_IF(true);
     ASSERT_NE(CONFORMANCE_TEST_ERROR, DifMatExec());
 }
 
 TEST_P(GLES1ConformanceTest, DifMatNorm)
 {
-    ANGLE_SKIP_TEST_IF(true);
     ASSERT_NE(CONFORMANCE_TEST_ERROR, DifMatNormExec());
 }
 
 TEST_P(GLES1ConformanceTest, DifMatPos)
 {
-    ANGLE_SKIP_TEST_IF(true);
     ASSERT_NE(CONFORMANCE_TEST_ERROR, DifMatPosExec());
 }
 
@@ -245,7 +235,6 @@
 
 TEST_P(GLES1ConformanceTest, EmitMat)
 {
-    ANGLE_SKIP_TEST_IF(true);
     ASSERT_NE(CONFORMANCE_TEST_ERROR, EmitMatExec());
 }
 
@@ -380,31 +369,26 @@
 
 TEST_P(GLES1ConformanceTest, SpecExp)
 {
-    ANGLE_SKIP_TEST_IF(true);
     ASSERT_NE(CONFORMANCE_TEST_ERROR, SpecExpExec());
 }
 
 TEST_P(GLES1ConformanceTest, SpecExpNorm)
 {
-    ANGLE_SKIP_TEST_IF(true);
     ASSERT_NE(CONFORMANCE_TEST_ERROR, SpecExpNormExec());
 }
 
 TEST_P(GLES1ConformanceTest, SpecLight)
 {
-    ANGLE_SKIP_TEST_IF(true);
     ASSERT_NE(CONFORMANCE_TEST_ERROR, SpecLightExec());
 }
 
 TEST_P(GLES1ConformanceTest, SpecMat)
 {
-    ANGLE_SKIP_TEST_IF(true);
     ASSERT_NE(CONFORMANCE_TEST_ERROR, SpecMatExec());
 }
 
 TEST_P(GLES1ConformanceTest, SpecNorm)
 {
-    ANGLE_SKIP_TEST_IF(true);
     ASSERT_NE(CONFORMANCE_TEST_ERROR, SpecNormExec());
 }
 
@@ -420,19 +404,16 @@
 
 TEST_P(GLES1ConformanceTest, SpotPos)
 {
-    ANGLE_SKIP_TEST_IF(true);
     ASSERT_NE(CONFORMANCE_TEST_ERROR, SpotPosExec());
 }
 
 TEST_P(GLES1ConformanceTest, SpotExpPos)
 {
-    ANGLE_SKIP_TEST_IF(true);
     ASSERT_NE(CONFORMANCE_TEST_ERROR, SpotExpPosExec());
 }
 
 TEST_P(GLES1ConformanceTest, SpotExpDir)
 {
-    ANGLE_SKIP_TEST_IF(true);
     ASSERT_NE(CONFORMANCE_TEST_ERROR, SpotExpDirExec());
 }
 
@@ -487,7 +468,6 @@
 
 TEST_P(GLES1ConformanceTest, XFormNormal)
 {
-    ANGLE_SKIP_TEST_IF(true);
     ASSERT_NE(CONFORMANCE_TEST_ERROR, XFormNormalExec());
 }