gamnit: use premultiplied alpha
authorAlexis Laferrière <alexis.laf@xymus.net>
Mon, 26 Jun 2017 15:44:53 +0000 (11:44 -0400)
committerAlexis Laferrière <alexis.laf@xymus.net>
Wed, 28 Jun 2017 16:55:53 +0000 (12:55 -0400)
Signed-off-by: Alexis Laferrière <alexis.laf@xymus.net>

lib/gamnit/depth/particles.nit
lib/gamnit/display_android.nit
lib/gamnit/flat.nit
lib/gamnit/textures.nit

index 3c40ac1..bfe3392 100644 (file)
@@ -258,7 +258,6 @@ class ParticleProgram
                {
                        if (use_texture) {
                                gl_FragColor = texture2D(texture0, gl_PointCoord) * v_color;
-                               if (gl_FragColor.a <= 0.01) discard;
                        } else {
                                gl_FragColor = v_color;
                        }
@@ -301,7 +300,7 @@ class ExplosionProgram
                gl_Position = center * mvp;
                gl_PointSize = scale / gl_Position.z * pt;
 
-               if (pt > 0.8) v_color.a = (1.0-pt)/0.2;
+               if (pt > 0.8) v_color *= (1.0-pt)/0.2;
        """
 end
 
@@ -318,8 +317,8 @@ class SmokeProgram
                gl_PointSize = scale / gl_Position.z * (pt+0.1);
 
                if (pt < 0.1)
-                       v_color.a = pt / 0.1;
+                       v_color *= pt / 0.1;
                else
-                       v_color.a = 1.0 - pt*0.9;
+                       v_color *= 1.0 - pt*0.9;
        """
 end
index e9d1b4a..6d968f8 100644 (file)
@@ -62,7 +62,7 @@ redef class TextureAsset
                        return
                end
 
-               var buf = bmp.copy_pixels
+               var buf = bmp.copy_pixels(unmultiply=not premultiply_alpha)
                loaded = true
                width = bmp.width.to_f
                height = bmp.height.to_f
index 56fd402..f3043c3 100644 (file)
@@ -430,7 +430,7 @@ redef class App
 
                # Enable blending
                gl.capabilities.blend.enable
-               glBlendFunc(gl_SRC_ALPHA, gl_ONE_MINUS_SRC_ALPHA)
+               glBlendFunc(gl_ONE, gl_ONE_MINUS_SRC_ALPHA)
 
                # Enable depth test
                gl.capabilities.depth_test.enable
@@ -695,7 +695,7 @@ private class Simple2dProgram
                        }
 
                        gl_Position = (vec4(c * scale, 1.0) * rotation() + translation)* mvp;
-                       v_color = color;
+                       v_color = vec4(color.rgb*color.a, color.a);
                }
                """ @ glsl_vertex_shader
 
index 53e88a5..4fb98ac 100644 (file)
@@ -208,7 +208,7 @@ class CustomTexture
        end
 end
 
-# Texture with its own pixels
+# Texture with its own pixel data
 class RootTexture
        super Texture
 
@@ -221,6 +221,18 @@ class RootTexture
 
        init do all_root_textures.add self
 
+       # Should the pixels RGB values be premultiplied by their alpha value at loading?
+       #
+       # All gamnit textures must have premultiplied alpha, it provides a better
+       # alpha blending, avoids artifacts and allows for additive blending.
+       #
+       # When at `true`, the default, pixels RGB values are premultiplied
+       # at loading. Set to `false` if pixels RGB values are already
+       # premultiplied in the source data.
+       #
+       # This value must be set before calling `load`.
+       var premultiply_alpha = true is writable
+
        private fun load_from_pixels(pixels: Pointer, width, height: Int, format: GLPixelFormat)
        do
                var max_texture_size = glGetIntegerv(gl_MAX_TEXTURE_SIZE, 0)
@@ -229,6 +241,11 @@ class RootTexture
                        return
                end
 
+               # Premultiply alpha?
+               if premultiply_alpha and format == gl_RGBA then
+                       pixels.premultiply_alpha(width, height)
+               end
+
                glPixelStorei(gl_UNPACK_ALIGNEMENT, 1)
                var tex = glGenTextures(1)[0]
                gl_texture = tex
@@ -368,3 +385,20 @@ class TextureSet
        # Load all texture of this set
        fun load_all do for t in self do t.load
 end
+
+redef class Pointer
+       # Multiply RBG values by their alpha value
+       private fun premultiply_alpha(width, height: Int) `{
+               uint8_t *bytes = (uint8_t *)self;
+               int x, y, i = 0;
+               for(y = 0; y < height; y ++) {
+                       for(x = 0; x < width; x ++) {
+                               int a = bytes[i+3];
+                               bytes[i  ] = bytes[i  ] * a / 255;
+                               bytes[i+1] = bytes[i+1] * a / 255;
+                               bytes[i+2] = bytes[i+2] * a / 255;
+                               i += 4;
+                       }
+               }
+       `}
+end