[colobot] 37/100: Optimizations and changes in OpenGL 2.1 device.

Didier Raboud odyx at moszumanska.debian.org
Thu Jun 1 18:10:16 UTC 2017


This is an automated email from the git hooks/post-receive script.

odyx pushed a commit to branch debian/master
in repository colobot.

commit 9bdd83771e0e081ecf3be1384c7b1bb197ad4165
Author: Tomasz Kapuściński <tomaszkax86 at gmail.com>
Date:   Mon Jan 2 16:35:40 2017 +0100

    Optimizations and changes in OpenGL 2.1 device.
    
    * Limited number of lights to 4
    * Only directional lights
    * Per-pixel lighting
    * Improved dynamic shadows a bit
---
 src/graphics/opengl/gl21device.cpp              | 149 +++++++++++++-----------
 src/graphics/opengl/gl21device.h                |  10 +-
 src/graphics/opengl/glutil.h                    |   2 -
 src/graphics/opengl/shaders/gl21/fs_normal.glsl |  81 +++++++++++--
 src/graphics/opengl/shaders/gl21/vs_normal.glsl |  95 +--------------
 5 files changed, 164 insertions(+), 173 deletions(-)

diff --git a/src/graphics/opengl/gl21device.cpp b/src/graphics/opengl/gl21device.cpp
index b38f638..4846766 100644
--- a/src/graphics/opengl/gl21device.cpp
+++ b/src/graphics/opengl/gl21device.cpp
@@ -242,7 +242,7 @@ bool CGL21Device::Create()
     glViewport(0, 0, m_config.size.x, m_config.size.y);
 
     // this is set in shader
-    int numLights = 8;
+    int numLights = 4;
 
     m_lights        = std::vector<Light>(numLights, Light());
     m_lightsEnabled = std::vector<bool> (numLights, false);
@@ -408,7 +408,7 @@ bool CGL21Device::Create()
         uni.fogColor = glGetUniformLocation(m_normalProgram, "uni_FogColor");
 
         uni.shadowColor = glGetUniformLocation(m_normalProgram, "uni_ShadowColor");
-        uni.lightingEnabled = glGetUniformLocation(m_normalProgram, "uni_LightingEnabled");
+        uni.lightCount = glGetUniformLocation(m_normalProgram, "uni_LightCount");
 
         uni.ambientColor = glGetUniformLocation(m_normalProgram, "uni_Material.ambient");
         uni.diffuseColor = glGetUniformLocation(m_normalProgram, "uni_Material.diffuse");
@@ -417,12 +417,6 @@ bool CGL21Device::Create()
         GLchar name[64];
         for (int i = 0; i < 8; i++)
         {
-            sprintf(name, "uni_Light[%d].Enabled", i);
-            uni.lights[i].enabled = glGetUniformLocation(m_normalProgram, name);
-
-            sprintf(name, "uni_Light[%d].Type", i);
-            uni.lights[i].type = glGetUniformLocation(m_normalProgram, name);
-
             sprintf(name, "uni_Light[%d].Position", i);
             uni.lights[i].position = glGetUniformLocation(m_normalProgram, name);
 
@@ -434,18 +428,6 @@ bool CGL21Device::Create()
 
             sprintf(name, "uni_Light[%d].Specular", i);
             uni.lights[i].specular = glGetUniformLocation(m_normalProgram, name);
-
-            sprintf(name, "uni_Light[%d].Attenuation", i);
-            uni.lights[i].attenuation = glGetUniformLocation(m_normalProgram, name);
-
-            sprintf(name, "uni_Light[%d].SpotDirection", i);
-            uni.lights[i].spotDirection = glGetUniformLocation(m_normalProgram, name);
-
-            sprintf(name, "uni_Light[%d].Exponent", i);
-            uni.lights[i].spotExponent = glGetUniformLocation(m_normalProgram, name);
-
-            sprintf(name, "uni_Light[%d].SpotCutoff", i);
-            uni.lights[i].spotCutoff = glGetUniformLocation(m_normalProgram, name);
         }
 
         // Set default uniform values
@@ -476,10 +458,7 @@ bool CGL21Device::Create()
 
         glUniform1f(uni.shadowColor, 0.5f);
 
-        glUniform1i(uni.lightingEnabled, 0);
-
-        for (int i = 0; i < 8; i++)
-            glUniform1i(uni.lights[i].enabled, 0);
+        glUniform1i(uni.lightCount, 0);
     }
 
     // Obtain uniform locations from interface rendering program and initialize them
@@ -594,6 +573,7 @@ void CGL21Device::ConfigChanged(const DeviceConfig& newConfig)
 
     // Reset state
     m_lighting = false;
+    m_updateLights = true;
 
     glViewport(0, 0, m_config.size.x, m_config.size.y);
 
@@ -721,36 +701,7 @@ void CGL21Device::SetLight(int index, const Light &light)
 
     m_lights[index] = light;
 
-    LightLocations &loc = m_uniforms[m_mode].lights[index];
-
-    glUniform4fv(loc.ambient, 1, light.ambient.Array());
-    glUniform4fv(loc.diffuse, 1, light.diffuse.Array());
-    glUniform4fv(loc.specular, 1, light.specular.Array());
-    glUniform3f(loc.attenuation, light.attenuation0, light.attenuation1, light.attenuation2);
-
-    if (light.type == LIGHT_DIRECTIONAL)
-    {
-        glUniform1i(loc.type, 1);
-        glUniform4f(loc.position, -light.direction.x, -light.direction.y, -light.direction.z, 0.0f);
-    }
-    else if (light.type == LIGHT_POINT)
-    {
-        glUniform1i(loc.type, 2);
-        glUniform4f(loc.position, light.position.x, light.position.y, light.position.z, 1.0f);
-
-        glUniform3f(loc.spotDirection, 0.0f, 1.0f, 0.0f);
-        glUniform1f(loc.spotCutoff, -1.0f);
-        glUniform1f(loc.spotExponent, 1.0f);
-    }
-    else if (light.type == LIGHT_SPOT)
-    {
-        glUniform1i(loc.type, 3);
-        glUniform4f(loc.position, light.position.x, light.position.y, light.position.z, 1.0f);
-
-        glUniform3f(loc.spotDirection, -light.direction.x, -light.direction.y, -light.direction.z);
-        glUniform1f(loc.spotCutoff, std::cos(light.spotAngle));
-        glUniform1f(loc.spotExponent, light.spotIntensity);
-    }
+    m_updateLights = true;
 }
 
 void CGL21Device::SetLightEnabled(int index, bool enabled)
@@ -760,7 +711,7 @@ void CGL21Device::SetLightEnabled(int index, bool enabled)
 
     m_lightsEnabled[index] = enabled;
 
-    glUniform1i(m_uniforms[m_mode].lights[index].enabled, enabled ? 1 : 0);
+    m_updateLights = true;
 }
 
 /** If image is invalid, returns invalid texture.
@@ -798,12 +749,13 @@ Texture CGL21Device::CreateTexture(ImageData *data, const TextureCreateParams &p
 
     result.originalSize = result.size;
 
-    glActiveTexture(GL_TEXTURE0);
-    glEnable(GL_TEXTURE_2D);
-
     glGenTextures(1, &result.id);
+
+    glActiveTexture(GL_TEXTURE0);
     glBindTexture(GL_TEXTURE_2D, result.id);
 
+    glEnable(GL_TEXTURE_2D);
+
     // Set texture parameters
     GLint minF = GL_NEAREST, magF = GL_NEAREST;
     int mipmapLevel = 1;
@@ -991,7 +943,7 @@ void CGL21Device::SetTexture(int index, const Texture &texture)
     glBindTexture(GL_TEXTURE_2D, texture.id);
 
     // Params need to be updated for the new bound texture
-    UpdateTextureStatus();
+    UpdateTextureState(index);
     UpdateTextureParams(index);
 }
 
@@ -1009,7 +961,7 @@ void CGL21Device::SetTexture(int index, unsigned int textureId)
     glBindTexture(GL_TEXTURE_2D, textureId);
 
     // Params need to be updated for the new bound texture
-    UpdateTextureStatus();
+    UpdateTextureState(index);
     UpdateTextureParams(index);
 }
 
@@ -1024,15 +976,54 @@ void CGL21Device::SetTextureEnabled(int index, bool enabled)
     if (same)
         return; // nothing to do
 
-    UpdateTextureStatus();
+    UpdateTextureState(index);
 }
 
-void CGL21Device::UpdateTextureStatus()
+void CGL21Device::UpdateTextureState(int index)
 {
-    for (int i = 0; i < 3; i++)
+    bool enabled = m_texturesEnabled[index] && (m_currentTextures[index].id != 0);
+    glUniform1i(m_uniforms[m_mode].textureEnabled[index], enabled ? 1 : 0);
+}
+
+void CGL21Device::UpdateLights()
+{
+    m_updateLights = false;
+
+    // If not in normal rendering mode, return immediately
+    if (m_mode != 0) return;
+
+    // Lighting enabled
+    if (m_lighting)
+    {
+        int index = 0;
+
+        // Iterate all lights
+        for (unsigned int i = 0; i < m_lights.size(); i++)
+        {
+            // If disabled, ignore and continue
+            if (!m_lightsEnabled[i]) continue;
+
+            // If not directional, ignore and continue
+            if (m_lights[i].type != LIGHT_DIRECTIONAL) continue;
+
+            Light &light = m_lights[i];
+            LightLocations &uni = m_uniforms[m_mode].lights[index];
+
+            glUniform4fv(uni.ambient, 1, light.ambient.Array());
+            glUniform4fv(uni.diffuse, 1, light.diffuse.Array());
+            glUniform4fv(uni.specular, 1, light.specular.Array());
+
+            glUniform4f(uni.position, -light.direction.x, -light.direction.y, -light.direction.z, 0.0f);
+
+            index++;
+        }
+
+        glUniform1i(m_uniforms[m_mode].lightCount, index);
+    }
+    // Lighting disabled
+    else
     {
-        bool enabled = m_texturesEnabled[i] && (m_currentTextures[i].id != 0);
-        glUniform1i(m_uniforms[m_mode].textureEnabled[i], enabled ? 1 : 0);
+        glUniform1i(m_uniforms[m_mode].lightCount, 0);
     }
 }
 
@@ -1044,6 +1035,12 @@ inline void CGL21Device::BindVBO(GLuint vbo)
     m_currentVBO = vbo;
 }
 
+inline void CGL21Device::BindTexture(int index, GLuint texture)
+{
+    glActiveTexture(GL_TEXTURE0 + index);
+    glBindTexture(GL_TEXTURE_2D, texture);
+}
+
 /**
   Sets the texture parameters for the given texture stage.
   If the given texture was not set (bound) yet, nothing happens.
@@ -1121,6 +1118,8 @@ void CGL21Device::SetTextureStageWrap(int index, TexWrapMode wrapS, TexWrapMode
 void CGL21Device::DrawPrimitive(PrimitiveType type, const Vertex *vertices, int vertexCount,
                               Color color)
 {
+    if (m_updateLights) UpdateLights();
+
     BindVBO(0);
 
     Vertex* vs = const_cast<Vertex*>(vertices);
@@ -1148,6 +1147,8 @@ void CGL21Device::DrawPrimitive(PrimitiveType type, const Vertex *vertices, int
 void CGL21Device::DrawPrimitive(PrimitiveType type, const VertexTex2 *vertices, int vertexCount,
                               Color color)
 {
+    if (m_updateLights) UpdateLights();
+
     BindVBO(0);
 
     VertexTex2* vs = const_cast<VertexTex2*>(vertices);
@@ -1180,6 +1181,8 @@ void CGL21Device::DrawPrimitive(PrimitiveType type, const VertexTex2 *vertices,
 
 void CGL21Device::DrawPrimitive(PrimitiveType type, const VertexCol *vertices, int vertexCount)
 {
+    if (m_updateLights) UpdateLights();
+
     BindVBO(0);
 
     VertexCol* vs = const_cast<VertexCol*>(vertices);
@@ -1199,6 +1202,8 @@ void CGL21Device::DrawPrimitive(PrimitiveType type, const VertexCol *vertices, i
 void CGL21Device::DrawPrimitive(PrimitiveType type, const void *vertices,
     int size, const VertexFormat &format, int vertexCount)
 {
+    if (m_updateLights) UpdateLights();
+
     BindVBO(0);
 
     const char *ptr = reinterpret_cast<const char*>(vertices);
@@ -1277,6 +1282,8 @@ void CGL21Device::DrawPrimitive(PrimitiveType type, const void *vertices,
 void CGL21Device::DrawPrimitives(PrimitiveType type, const void *vertices,
     int size, const VertexFormat &format, int first[], int count[], int drawCount)
 {
+    if (m_updateLights) UpdateLights();
+
     BindVBO(0);
 
     const char *ptr = reinterpret_cast<const char*>(vertices);
@@ -1355,6 +1362,8 @@ void CGL21Device::DrawPrimitives(PrimitiveType type, const void *vertices,
 void CGL21Device::DrawPrimitives(PrimitiveType type, const Vertex *vertices,
     int first[], int count[], int drawCount, Color color)
 {
+    if (m_updateLights) UpdateLights();
+
     BindVBO(0);
 
     Vertex* vs = const_cast<Vertex*>(vertices);
@@ -1381,6 +1390,8 @@ void CGL21Device::DrawPrimitives(PrimitiveType type, const Vertex *vertices,
 void CGL21Device::DrawPrimitives(PrimitiveType type, const VertexTex2 *vertices,
     int first[], int count[], int drawCount, Color color)
 {
+    if (m_updateLights) UpdateLights();
+
     BindVBO(0);
 
     VertexTex2* vs = const_cast<VertexTex2*>(vertices);
@@ -1414,6 +1425,8 @@ void CGL21Device::DrawPrimitives(PrimitiveType type, const VertexTex2 *vertices,
 void CGL21Device::DrawPrimitives(PrimitiveType type, const VertexCol *vertices,
     int first[], int count[], int drawCount)
 {
+    if (m_updateLights) UpdateLights();
+
     BindVBO(0);
 
     VertexCol* vs = const_cast<VertexCol*>(vertices);
@@ -1574,6 +1587,8 @@ void CGL21Device::DrawStaticBuffer(unsigned int bufferId)
     if (it == m_vboObjects.end())
         return;
 
+    if (m_updateLights) UpdateLights();
+
     BindVBO((*it).second.bufferId);
 
     if ((*it).second.vertexType == VERTEX_TYPE_NORMAL)
@@ -1741,9 +1756,11 @@ void CGL21Device::SetRenderState(RenderState state, bool enabled)
     }
     else if (state == RENDER_STATE_LIGHTING)
     {
+        if (m_lighting == enabled) return;
+
         m_lighting = enabled;
 
-        glUniform1i(m_uniforms[m_mode].lightingEnabled, enabled ? 1 : 0);
+        m_updateLights = true;
 
         return;
     }
diff --git a/src/graphics/opengl/gl21device.h b/src/graphics/opengl/gl21device.h
index e70d66c..9a2bea7 100644
--- a/src/graphics/opengl/gl21device.h
+++ b/src/graphics/opengl/gl21device.h
@@ -183,10 +183,14 @@ public:
 private:
     //! Updates the texture params for given texture stage
     void UpdateTextureParams(int index);
-    //! Updates texture status
-    void UpdateTextureStatus();
+    //! Updates texture state
+    void UpdateTextureState(int index);
+    //! Update light parameters
+    void UpdateLights();
     //! Binds VBO
     inline void BindVBO(GLuint vbo);
+    //! Binds texture
+    inline void BindTexture(int index, GLuint texture);
 
 private:
     //! Current config
@@ -208,6 +212,8 @@ private:
 
     //! Whether lighting is enabled
     bool m_lighting = false;
+    //! true means that lights need to be updated
+    bool m_updateLights = false;
     //! Current lights
     std::vector<Light> m_lights;
     //! Current lights enable status
diff --git a/src/graphics/opengl/glutil.h b/src/graphics/opengl/glutil.h
index 4b66d50..f6b0f16 100644
--- a/src/graphics/opengl/glutil.h
+++ b/src/graphics/opengl/glutil.h
@@ -194,8 +194,6 @@ struct UniformLocations
     //! Shadow color
     GLint shadowColor = -1;
 
-    //! true enables lighting
-    GLint lightingEnabled = -1;
     // Number of enabled lights
     GLint lightCount = -1;
     //! Ambient color
diff --git a/src/graphics/opengl/shaders/gl21/fs_normal.glsl b/src/graphics/opengl/shaders/gl21/fs_normal.glsl
index fdf59ac..d21bc9c 100644
--- a/src/graphics/opengl/shaders/gl21/fs_normal.glsl
+++ b/src/graphics/opengl/shaders/gl21/fs_normal.glsl
@@ -19,6 +19,8 @@
 // FRAGMENT SHADER - NORMAL MODE
 #version 120
 
+#define CONFIG_QUALITY_SHADOWS 1
+
 uniform sampler2D uni_PrimaryTexture;
 uniform sampler2D uni_SecondaryTexture;
 uniform sampler2DShadow uni_ShadowTexture;
@@ -34,6 +36,26 @@ uniform vec4 uni_FogColor;
 
 uniform float uni_ShadowColor;
 
+struct LightParams
+{
+    vec4 Position;
+    vec4 Ambient;
+    vec4 Diffuse;
+    vec4 Specular;
+};
+
+struct Material
+{
+    vec4 ambient;
+    vec4 diffuse;
+    vec4 specular;
+};
+
+uniform Material uni_Material;
+
+uniform int uni_LightCount;
+uniform LightParams uni_Light[4];
+
 varying float pass_Distance;
 varying vec4 pass_Color;
 varying vec3 pass_Normal;
@@ -47,6 +69,55 @@ void main()
 {
     vec4 color = pass_Color;
 
+    if (uni_LightCount > 0)
+    {
+        vec4 ambient = vec4(0.0f);
+        vec4 diffuse = vec4(0.0f);
+        vec4 specular = vec4(0.0f);
+
+        vec3 normal = normalize(pass_Normal);
+
+        for (int i = 0; i < uni_LightCount; i++)
+        {
+            LightParams light = uni_Light[i];
+
+            vec3 lightDirection = light.Position.xyz;
+            vec3 reflectDirection = -reflect(lightDirection, normal);
+
+            float diffuseComponent = clamp(dot(normal, lightDirection), 0.0f, 1.0f);
+            float specularComponent = clamp(pow(dot(normal, lightDirection + reflectDirection), 10.0f), 0.0f, 1.0f);
+
+            ambient += light.Ambient;
+            diffuse += diffuseComponent * light.Diffuse;
+            specular += specularComponent * light.Specular;
+        }
+
+        float shadow = 1.0f;
+
+        if (uni_TextureEnabled[2])
+        {
+#ifdef CONFIG_QUALITY_SHADOWS
+            float offset = 0.00025f;
+
+            float value = (1.0f / 5.0f) * (shadow2D(uni_ShadowTexture, pass_TexCoord2).x
+                    + shadow2D(uni_ShadowTexture, pass_TexCoord2 + vec3( offset,    0.0f, 0.0f)).x
+                    + shadow2D(uni_ShadowTexture, pass_TexCoord2 + vec3(-offset,    0.0f, 0.0f)).x
+                    + shadow2D(uni_ShadowTexture, pass_TexCoord2 + vec3(   0.0f,  offset, 0.0f)).x
+                    + shadow2D(uni_ShadowTexture, pass_TexCoord2 + vec3(   0.0f, -offset, 0.0f)).x);
+
+            shadow = mix(uni_ShadowColor, 1.0f, value);
+#else
+            shadow = mix(uni_ShadowColor, 1.0f, shadow2D(uni_ShadowTexture, pass_TexCoord2).x);
+#endif
+        }
+
+        vec4 result = ambient * uni_Material.ambient
+                + diffuse * uni_Material.diffuse * shadow
+                + specular * uni_Material.specular * shadow;
+
+        color = clamp(vec4(result.rgb, 1.0f), 0.0f, 1.0f);
+    }
+
     if (uni_TextureEnabled[0])
     {
         color = color * texture2D(uni_PrimaryTexture, pass_TexCoord0);
@@ -57,16 +128,6 @@ void main()
         color = color * texture2D(uni_SecondaryTexture, pass_TexCoord1);
     }
 
-    if (uni_TextureEnabled[2])
-    {
-        vec3 normal = pass_Normal * (2.0f * gl_Color.x - 1.0f);
-
-        if (dot(normal, const_LightDirection) < 0.0f)
-            color.rgb *= uni_ShadowColor;
-        else
-            color.rgb *= mix(uni_ShadowColor, 1.0f, shadow2D(uni_ShadowTexture, pass_TexCoord2).x);
-    }
-
     if (uni_FogEnabled)
     {
         float interpolate = (pass_Distance - uni_FogRange.x) / (uni_FogRange.y - uni_FogRange.x);
diff --git a/src/graphics/opengl/shaders/gl21/vs_normal.glsl b/src/graphics/opengl/shaders/gl21/vs_normal.glsl
index 117f09b..9195cd2 100644
--- a/src/graphics/opengl/shaders/gl21/vs_normal.glsl
+++ b/src/graphics/opengl/shaders/gl21/vs_normal.glsl
@@ -25,33 +25,6 @@ uniform mat4 uni_ModelMatrix;
 uniform mat4 uni_ShadowMatrix;
 uniform mat4 uni_NormalMatrix;
 
-struct LightParams
-{
-    bool Enabled;
-    int Type;
-    vec4 Position;
-    vec4 Ambient;
-    vec4 Diffuse;
-    vec4 Specular;
-    float Shininess;
-    vec3 Attenuation;
-    vec3 SpotDirection;
-    float SpotCutoff;
-    float SpotExponent;
-};
-
-struct Material
-{
-    vec4 ambient;
-    vec4 diffuse;
-    vec4 specular;
-};
-
-uniform Material uni_Material;
-
-uniform bool uni_LightingEnabled;
-uniform LightParams uni_Light[8];
-
 varying float pass_Distance;
 varying vec4 pass_Color;
 varying vec3 pass_Normal;
@@ -65,75 +38,11 @@ void main()
     vec4 eyeSpace = uni_ViewMatrix * position;
     vec4 shadowCoord = uni_ShadowMatrix * position;
 
-    vec4 color = gl_Color;
-
-    vec3 normal = normalize((uni_NormalMatrix * vec4(gl_Normal, 0.0f)).xyz);
-
-    if (uni_LightingEnabled)
-    {
-        vec4 ambient = vec4(0.0f);
-        vec4 diffuse = vec4(0.0f);
-        vec4 specular = vec4(0.0f);
-
-        for (int i = 0; i < 8; i++)
-        {
-            if (uni_Light[i].Enabled)
-            {
-                LightParams light = uni_Light[i];
-
-                vec3 lightDirection = light.Position.xyz;
-                float atten = 1.0f;
-
-                if (light.Position.w > 0.5f)
-                {
-                    float dist = distance(light.Position.xyz, position.xyz);
-
-                    float atten = 1.0f / dot(light.Attenuation,
-                            vec3(1.0f, dist, dist * dist));
-
-                    lightDirection = normalize(light.Position.xyz - position.xyz);
-                }
-
-                float spot = 1.0f;
-
-                if (light.SpotCutoff > 0.0f)
-                {
-                    float cone = dot(light.SpotDirection, lightDirection);
-
-                    if (cone > light.SpotCutoff)
-                    {
-                        spot = pow(cone, light.SpotExponent);
-                    }
-                    else
-                    {
-                        continue;
-                    }
-                }
-
-                vec3 reflectDirection = -reflect(lightDirection, normal);
-
-                float component = atten * spot;
-                float diffuseComponent = clamp(dot(normal, lightDirection), 0.0f, 1.0f);
-                float specularComponent = clamp(pow(dot(normal, lightDirection + reflectDirection), light.Shininess), 0.0f, 1.0f);
-
-                ambient += component * light.Ambient * uni_Material.ambient;
-                diffuse += component * diffuseComponent * light.Diffuse * uni_Material.diffuse;
-                specular += component * specularComponent * light.Specular * uni_Material.specular;
-            }
-        }
-
-        vec4 result = ambient + diffuse + specular;
-
-        color = clamp(vec4(result.rgb, uni_Material.diffuse), 0.0f, 1.0f);
-    }
-
     gl_Position = uni_ProjectionMatrix * eyeSpace;
-    gl_FrontColor = vec4(1.0f);
-    gl_BackColor = vec4(0.0f);
 
+    pass_Color = gl_Color;
+    pass_Normal = normalize((uni_NormalMatrix * vec4(gl_Normal, 0.0f)).xyz);
     pass_Distance = abs(eyeSpace.z / eyeSpace.w);
-    pass_Color = color;
-    pass_Normal = normal;
     pass_TexCoord0 = gl_MultiTexCoord0.st;
     pass_TexCoord1 = gl_MultiTexCoord1.st;
     pass_TexCoord2 = shadowCoord.xyz / shadowCoord.w;

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-games/colobot.git



More information about the Pkg-games-commits mailing list