Browse Source

Support textures filtering

raysan5 8 years ago
parent
commit
988d39029f
4 changed files with 178 additions and 48 deletions
  1. 12 3
      src/raylib.h
  2. 53 35
      src/rlgl.c
  3. 31 4
      src/rlgl.h
  4. 82 6
      src/textures.c

+ 12 - 3
src/raylib.h

@@ -550,7 +550,16 @@ typedef enum {
 } TextureFormat;
 
 // Texture parameters: filter mode
-typedef enum { FILTER_POINT = 0, FILTER_BILINEAR, FILTER_TRILINEAR } TextureFilterMode;
+// NOTE 1: Filtering considers mipmaps if available in the texture
+// NOTE 2: Filter is accordingly set for minification and magnification
+typedef enum { 
+    FILTER_POINT = 0,               // No filter, just pixel aproximation
+    FILTER_BILINEAR,                // Linear filtering
+    FILTER_TRILINEAR,               // Trilinear filtering (linear with mipmaps)
+    FILTER_ANISOTROPIC_4X,          // Anisotropic filtering 4x
+    FILTER_ANISOTROPIC_8X,          // Anisotropic filtering 8x
+    FILTER_ANISOTROPIC_16X,         // Anisotropic filtering 16x
+} TextureFilterMode;
 
 // Texture parameters: wrap mode
 typedef enum { WRAP_REPEAT = 0, WRAP_CLAMP, WRAP_MIRROR } TextureWrapMode;
@@ -797,8 +806,8 @@ RLAPI void ImageColorGrayscale(Image *image);
 RLAPI void ImageColorContrast(Image *image, float contrast);                                             // Modify image color: contrast (-100 to 100)
 RLAPI void ImageColorBrightness(Image *image, int brightness);                                           // Modify image color: brightness (-255 to 255)
 RLAPI void GenTextureMipmaps(Texture2D texture);                                                         // Generate GPU mipmaps for a texture
-RLAPI void SetTextureFilter(Texture2D texture, int filterMode);
-RLAPI void SetTextureWrap(Texture2D texture, int wrapMode);
+RLAPI void SetTextureFilter(Texture2D texture, int filterMode);                                          // Set texture scaling filter mode
+RLAPI void SetTextureWrap(Texture2D texture, int wrapMode);                                              // Set texture wrapping mode
 
 RLAPI void DrawTexture(Texture2D texture, int posX, int posY, Color tint);                               // Draw a Texture2D
 RLAPI void DrawTextureV(Texture2D texture, Vector2 position, Color tint);                                // Draw a Texture2D with position defined as Vector2

+ 53 - 35
src/rlgl.c

@@ -140,6 +140,14 @@
     #define GL_COMPRESSED_RGBA_ASTC_8x8_KHR     0x93b7
 #endif
 
+#ifndef GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT
+    #define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT   0x84FF
+#endif
+
+#ifndef GL_TEXTURE_MAX_ANISOTROPY_EXT
+    #define GL_TEXTURE_MAX_ANISOTROPY_EXT       0x84FE
+#endif
+
 #if defined(GRAPHICS_API_OPENGL_11)
     #define GL_UNSIGNED_SHORT_5_6_5     0x8363
     #define GL_UNSIGNED_SHORT_5_5_5_1   0x8034
@@ -283,14 +291,21 @@ static Shader standardShader;               // Shader with support for lighting
 static Shader currentShader;                // Shader to be used on rendering (by default, defaultShader)
 static bool standardShaderLoaded = false;   // Flag to track if standard shader has been loaded
 
-// Flags for supported extensions
+// Extension supported flag: VAO
 static bool vaoSupported = false;           // VAO support (OpenGL ES2 could not support VAO extension)
 
-// Compressed textures support flags
+// Extension supported flag: Compressed textures
 static bool texCompETC1Supported = false;   // ETC1 texture compression support
 static bool texCompETC2Supported = false;   // ETC2/EAC texture compression support
 static bool texCompPVRTSupported = false;   // PVR texture compression support
 static bool texCompASTCSupported = false;   // ASTC texture compression support
+
+// Extension supported flag: Anisotropic filtering
+static bool texAnisotropicFilterSupported = false;  // Anisotropic texture filtering support
+static float maxAnisotropicLevel = 0.0f;        // Maximum anisotropy level supported (minimum is 2.0f)
+
+// Extension supported flag: Clamp mirror wrap mode
+static bool texClampMirrorSupported = false;    // Clamp mirror wrap mode supported
 #endif
 
 #if defined(RLGL_OCULUS_SUPPORT)
@@ -871,45 +886,34 @@ void rlDisableTexture(void)
 #endif
 }
 
-// Set texture parameters
-// TODO: Review this function to choose right filter/wrap value
+// Set texture parameters (wrap mode/filter mode)
 void rlTextureParameters(unsigned int id, int param, int value)
 {
-/*
-// TextureWrapMode
-#define GL_REPEAT                         0x2901
-#define GL_CLAMP_TO_EDGE                  0x812F
-
-// TextureMagFilter
-#define GL_NEAREST                        0x2600
-#define GL_LINEAR                         0x2601
-
-// TextureMinFilter 
-#define GL_NEAREST                        0x2600
-#define GL_LINEAR                         0x2601
-#define GL_NEAREST_MIPMAP_NEAREST         0x2700
-#define GL_LINEAR_MIPMAP_NEAREST          0x2701
-#define GL_NEAREST_MIPMAP_LINEAR          0x2702
-#define GL_LINEAR_MIPMAP_LINEAR           0x2703
-*/    
-    
-    int glValue = 0;
-    
     glBindTexture(GL_TEXTURE_2D, id);
-    
-    switch (value)
+
+    switch (param)
     {
-        case FILTER_POINT: glValue = GL_NEAREST; break;
-        case FILTER_BILINEAR: glValue = GL_LINEAR; break;
-        case FILTER_TRILINEAR: glValue = GL_LINEAR; break;
-        //case WRAP_REPEAT: glValue = GL_REPEAT; break;
-        //case WRAP_CLAMP: glValue = GL_CLAMP_TO_EDGE; break;
-        //case WRAP_MIRROR: glValue = GL_NEAREST; break;
+        case RL_TEXTURE_WRAP_S:
+        case RL_TEXTURE_WRAP_T:
+        {
+            if ((value == RL_WRAP_CLAMP_MIRROR) && !texClampMirrorSupported) TraceLog(WARNING, "Clamp mirror wrap mode not supported");
+            else glTexParameteri(GL_TEXTURE_2D, param, value);
+        } break;
+        case RL_TEXTURE_MAG_FILTER:
+        case RL_TEXTURE_MIN_FILTER: glTexParameteri(GL_TEXTURE_2D, param, value); break;
+        case RL_TEXTURE_ANISOTROPIC_FILTER:
+        {
+            if (value <= maxAnisotropicLevel) glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, value);
+            else if (maxAnisotropicLevel > 0.0f)
+            {
+                TraceLog(WARNING, "[TEX ID %i] Maximum anisotropic filter level supported is %iX", id, maxAnisotropicLevel);
+                glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, value);
+            }
+            else TraceLog(WARNING, "Anisotropic filtering not supported");
+        } break;
         default: break;
     }
 
-    glTexParameteri(GL_TEXTURE_2D, param, glValue);
-
     glBindTexture(GL_TEXTURE_2D, 0);
 }
 
@@ -1166,7 +1170,7 @@ void rlglInit(int width, int height)
         // Check NPOT textures support
         // NOTE: Only check on OpenGL ES, OpenGL 3.3 has NPOT textures full support as core feature
         if (strcmp(extList[i], (const char *)"GL_OES_texture_npot") == 0) npotSupported = true;
-#endif   
+#endif
         
         // DDS texture compression support
         if ((strcmp(extList[i], (const char *)"GL_EXT_texture_compression_s3tc") == 0) ||
@@ -1185,6 +1189,16 @@ void rlglInit(int width, int height)
 
         // ASTC texture compression support
         if (strcmp(extList[i], (const char *)"GL_KHR_texture_compression_astc_hdr") == 0) texCompASTCSupported = true;
+        
+        // Anisotropic texture filter support
+        if (strcmp(extList[i], (const char *)"GL_EXT_texture_filter_anisotropic") == 0)
+        {
+            texAnisotropicFilterSupported = true;
+            glGetFloatv(0x84FF, &maxAnisotropicLevel);   // GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT      
+        }
+        
+        // Clamp mirror wrap mode supported
+        if (strcmp(extList[i], (const char *)"GL_EXT_texture_mirror_clamp") == 0) texClampMirrorSupported = true;
     }
     
 #ifdef _MSC_VER
@@ -1204,6 +1218,9 @@ void rlglInit(int width, int height)
     if (texCompETC2Supported) TraceLog(INFO, "[EXTENSION] ETC2/EAC compressed textures supported");
     if (texCompPVRTSupported) TraceLog(INFO, "[EXTENSION] PVRT compressed textures supported");
     if (texCompASTCSupported) TraceLog(INFO, "[EXTENSION] ASTC compressed textures supported");
+    
+    if (texAnisotropicFilterSupported) TraceLog(INFO, "[EXTENSION] Anisotropic textures filtering supported (max: %.0fX)", maxAnisotropicLevel);
+    if (texClampMirrorSupported) TraceLog(INFO, "[EXTENSION] Clamp mirror wrap texture mode supported");
 
     // Initialize buffers, default shaders and default textures
     //----------------------------------------------------------
@@ -1729,6 +1746,7 @@ void rlglGenerateMipmaps(Texture2D texture)
 #endif
 
 #if defined(GRAPHICS_API_OPENGL_33) || defined(GRAPHICS_API_OPENGL_ES2)
+        //glHint(GL_GENERATE_MIPMAP_HINT, GL_DONT_CARE);   // Hint for mipmaps generation algorythm: GL_FASTEST, GL_NICEST, GL_DONT_CARE
         glGenerateMipmap(GL_TEXTURE_2D);    // Generate mipmaps automatically
         TraceLog(INFO, "[TEX ID %i] Mipmaps generated automatically", texture.id);
 

+ 31 - 4
src/rlgl.h

@@ -91,10 +91,22 @@
 #endif
 
 // Texture parameters (equivalent to OpenGL defines)
-#define RL_TEXTURE_MAG_FILTER     0x2800
-#define RL_TEXTURE_MIN_FILTER     0x2801
-#define RL_TEXTURE_WRAP_S         0x2802
-#define RL_TEXTURE_WRAP_T         0x2803
+#define RL_TEXTURE_WRAP_S               0x2802      // GL_TEXTURE_WRAP_S
+#define RL_TEXTURE_WRAP_T               0x2803      // GL_TEXTURE_WRAP_T
+#define RL_TEXTURE_MAG_FILTER           0x2800      // GL_TEXTURE_MAG_FILTER
+#define RL_TEXTURE_MIN_FILTER           0x2801      // GL_TEXTURE_MIN_FILTER
+#define RL_TEXTURE_ANISOTROPIC_FILTER   0x3000      // Anisotropic filter (custom identifier)
+
+#define RL_FILTER_NEAREST               0x2600      // GL_NEAREST
+#define RL_FILTER_LINEAR                0x2601      // GL_LINEAR
+#define RL_FILTER_MIP_NEAREST           0x2700      // GL_NEAREST_MIPMAP_NEAREST
+#define RL_FILTER_NEAREST_MIP_LINEAR    0x2702      // GL_NEAREST_MIPMAP_LINEAR
+#define RL_FILTER_LINEAR_MIP_NEAREST    0x2701      // GL_LINEAR_MIPMAP_NEAREST
+#define RL_FILTER_MIP_LINEAR            0x2703      // GL_LINEAR_MIPMAP_LINEAR
+
+#define RL_WRAP_REPEAT                  0x2901      // GL_REPEAT
+#define RL_WRAP_CLAMP                   0x812F      // GL_CLAMP_TO_EDGE
+#define RL_WRAP_CLAMP_MIRROR            0x8742      // GL_MIRROR_CLAMP_EXT
 
 //----------------------------------------------------------------------------------
 // Types and Structures Definition
@@ -242,6 +254,21 @@ typedef enum { RL_LINES, RL_TRIANGLES, RL_QUADS } DrawMode;
 
     // Light types
     typedef enum { LIGHT_POINT, LIGHT_DIRECTIONAL, LIGHT_SPOT } LightType;
+    
+    // Texture parameters: filter mode
+    // NOTE 1: Filtering considers mipmaps if available in the texture
+    // NOTE 2: Filter is accordingly set for minification and magnification
+    typedef enum { 
+        FILTER_POINT = 0,               // No filter, just pixel aproximation
+        FILTER_BILINEAR,                // Linear filtering
+        FILTER_TRILINEAR,               // Trilinear filtering (linear with mipmaps)
+        FILTER_ANISOTROPIC_4X,          // Anisotropic filtering 4x
+        FILTER_ANISOTROPIC_8X,          // Anisotropic filtering 8x
+        FILTER_ANISOTROPIC_16X,         // Anisotropic filtering 16x
+    } TextureFilterMode;
+    
+    // Texture parameters: wrap mode
+    typedef enum { WRAP_REPEAT = 0, WRAP_CLAMP, WRAP_MIRROR } TextureWrapMode;
 
     // Color blending modes (pre-defined)
     typedef enum { BLEND_ALPHA = 0, BLEND_ADDITIVE, BLEND_MULTIPLIED } BlendMode;

+ 82 - 6
src/textures.c

@@ -442,18 +442,94 @@ void UnloadRenderTexture(RenderTexture2D target)
     if (target.id != 0) rlDeleteRenderTextures(target);
 }
 
-// Set texture scale filter
+// Set texture scaling filter mode
 void SetTextureFilter(Texture2D texture, int filterMode)
 {
-    rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, filterMode);
-    rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, filterMode);
+    switch (filterMode)
+    {
+        case FILTER_POINT:
+        {
+            if (texture.mipmaps > 1)
+            {
+                // RL_FILTER_MIP_NEAREST - tex filter: POINT, mipmaps filter: POINT (sharp switching between mipmaps)
+                rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_FILTER_MIP_NEAREST);
+                
+                // RL_FILTER_NEAREST - tex filter: POINT (no filter), no mipmaps
+                rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_FILTER_NEAREST);
+            }
+            else
+            {
+                // RL_FILTER_NEAREST - tex filter: POINT (no filter), no mipmaps
+                rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_FILTER_NEAREST);
+                rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_FILTER_NEAREST);
+            }
+        } break;
+        case FILTER_BILINEAR:
+        {
+            if (texture.mipmaps > 1)
+            {
+                // RL_FILTER_LINEAR_MIP_NEAREST - tex filter: BILINEAR, mipmaps filter: POINT (sharp switching between mipmaps)
+                // Alternative: RL_FILTER_NEAREST_MIP_LINEAR - tex filter: POINT, mipmaps filter: BILINEAR (smooth transition between mipmaps)
+                rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_FILTER_LINEAR_MIP_NEAREST);
+                
+                // RL_FILTER_LINEAR - tex filter: BILINEAR, no mipmaps
+                rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_FILTER_LINEAR);
+            }
+            else
+            {
+                // RL_FILTER_LINEAR - tex filter: BILINEAR, no mipmaps
+                rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_FILTER_LINEAR);
+                rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_FILTER_LINEAR);
+            }
+        } break;
+        case FILTER_TRILINEAR:
+        {
+            if (texture.mipmaps > 1)
+            {
+                // RL_FILTER_MIP_LINEAR - tex filter: BILINEAR, mipmaps filter: BILINEAR (smooth transition between mipmaps)
+                rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_FILTER_MIP_LINEAR);
+                
+                // RL_FILTER_LINEAR - tex filter: BILINEAR, no mipmaps
+                rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_FILTER_LINEAR);
+            }
+            else
+            {
+                TraceLog(WARNING, "[TEX ID %i] No mipmaps available for TRILINEAR texture filtering", texture.id);
+                
+                // RL_FILTER_LINEAR - tex filter: BILINEAR, no mipmaps
+                rlTextureParameters(texture.id, RL_TEXTURE_MIN_FILTER, RL_FILTER_LINEAR);
+                rlTextureParameters(texture.id, RL_TEXTURE_MAG_FILTER, RL_FILTER_LINEAR);
+            }
+        } break;
+        case FILTER_ANISOTROPIC_4X: rlTextureParameters(texture.id, RL_TEXTURE_ANISOTROPIC_FILTER, 4); break;
+        case FILTER_ANISOTROPIC_8X: rlTextureParameters(texture.id, RL_TEXTURE_ANISOTROPIC_FILTER, 8); break;
+        case FILTER_ANISOTROPIC_16X: rlTextureParameters(texture.id, RL_TEXTURE_ANISOTROPIC_FILTER, 16); break;
+        default: break;
+    }
 }
 
-// Set texture wrap mode
+// Set texture wrapping mode
 void SetTextureWrap(Texture2D texture, int wrapMode)
 {
-    rlTextureParameters(texture.id, RL_TEXTURE_WRAP_S, wrapMode);
-    rlTextureParameters(texture.id, RL_TEXTURE_WRAP_T, wrapMode);
+    switch (wrapMode)
+    {
+        case WRAP_REPEAT:
+        {
+            rlTextureParameters(texture.id, RL_TEXTURE_WRAP_S, RL_WRAP_REPEAT);
+            rlTextureParameters(texture.id, RL_TEXTURE_WRAP_T, RL_WRAP_REPEAT);
+        } break;
+        case WRAP_CLAMP:
+        {
+            rlTextureParameters(texture.id, RL_TEXTURE_WRAP_S, RL_WRAP_CLAMP);
+            rlTextureParameters(texture.id, RL_TEXTURE_WRAP_T, RL_WRAP_CLAMP);
+        } break;
+        case WRAP_MIRROR:
+        {
+            rlTextureParameters(texture.id, RL_TEXTURE_WRAP_S, RL_WRAP_CLAMP_MIRROR);
+            rlTextureParameters(texture.id, RL_TEXTURE_WRAP_T, RL_WRAP_CLAMP_MIRROR);
+        } break;
+        default: break;
+    }
 }
 
 // Get pixel data from image in the form of Color struct array