Browse Source

On D3D11 & OpenGL3, convert luminance & luminance-alpha textures to RGBA on upload. Revert RampGenerator & Spot/SpotWide texture changes to use RGB format. Closes #718.

Lasse Öörni 10 years ago
parent
commit
f4b5ead164

+ 7 - 18
Source/Tools/RampGenerator/RampGenerator.cpp

@@ -93,13 +93,13 @@ void Run(const Vector<String>& arguments)
     
     
     if (dimensions == 2)
     if (dimensions == 2)
     {
     {
-        SharedArrayPtr<unsigned char> data(new unsigned char[width * width * 3]);
+        SharedArrayPtr<unsigned char> data(new unsigned char[width * width]);
         
         
         for (int y = 0; y < width; ++y)
         for (int y = 0; y < width; ++y)
         {
         {
             for (int x = 0; x < width; ++x)
             for (int x = 0; x < width; ++x)
             {
             {
-                unsigned i = (y * width + x) * 3;
+                unsigned i = y * width + x;
                 
                 
                 float halfWidth = width * 0.5f;
                 float halfWidth = width * 0.5f;
                 float xf = (x - halfWidth + 0.5f) / (halfWidth - 0.5f);
                 float xf = (x - halfWidth + 0.5f) / (halfWidth - 0.5f);
@@ -109,29 +109,18 @@ void Run(const Vector<String>& arguments)
                     dist = 1.0f;
                     dist = 1.0f;
                 
                 
                 data[i] = (unsigned char)((1.0f - pow(dist, power)) * 255.0f);
                 data[i] = (unsigned char)((1.0f - pow(dist, power)) * 255.0f);
-                data[i + 1] = data[i];
-                data[i + 2] = data[i];
             }
             }
         }
         }
         
         
         // Ensure the border is completely black
         // Ensure the border is completely black
         for (int x = 0; x < width; ++x)
         for (int x = 0; x < width; ++x)
         {
         {
-            data[x * 3] = 0;
-            data[x * 3 + 1] = 0;
-            data[x * 3 + 2] = 0;
-            data[((width - 1) * width + x) * 3] = 0;
-            data[((width - 1) * width + x) * 3 + 1] = 0;
-            data[((width - 1) * width + x) * 3 + 2] = 0;
-            data[x * width * 3] = 0;
-            data[x * width * 3 + 1] = 0;
-            data[x * width * 3 + 2] = 0;
-            data[(x * width + (width - 1)) * 3] = 0;
-            data[(x * width + (width - 1)) * 3 + 1] = 0;
-            data[(x * width + (width - 1)) * 3 + 2] = 0;
+            data[x] = 0;
+            data[(width - 1) * width + x] = 0;
+            data[x * width] = 0;
+            data[x * width + (width - 1)] = 0;
         }
         }
         
         
-        // Save as RGB to allow Direct3D11 shaders to sample monochrome and color spot textures similarly
-        stbi_write_png(arguments[0].CString(), width, width, 3, data.Get(), 0);
+        stbi_write_png(arguments[0].CString(), width, width, 1, data.Get(), 0);
     }
     }
 }
 }

+ 0 - 42
Source/Urho3D/Graphics/Direct3D11/D3D11Texture.cpp

@@ -346,48 +346,6 @@ void Texture::UpdateParameters()
     parametersDirty_ = false;
     parametersDirty_ = false;
 }
 }
 
 
-SharedArrayPtr<unsigned char> Texture::ConvertRGBToRGBA(int width, int height, const unsigned char* data)
-{
-    if (!width || !height)
-        return SharedArrayPtr<unsigned char>();
-
-    SharedArrayPtr<unsigned char> ret(new unsigned char[width * height * 4]);
-    unsigned char* dest = ret.Get();
-
-    for (int i = 0; i < width * height; ++i)
-    {
-        dest[0] = data[0];
-        dest[1] = data[1];
-        dest[2] = data[2];
-        dest[3] = 255;
-        dest += 4;
-        data += 3;
-    }
-
-    return ret;
-}
-
-SharedArrayPtr<unsigned char> Texture::ConvertRGBToRGBA(int width, int height, int depth, const unsigned char* data)
-{
-    if (!width || !height || !depth)
-        return SharedArrayPtr<unsigned char>();
-
-    SharedArrayPtr<unsigned char> ret(new unsigned char[width * height * depth * 4]);
-    unsigned char* dest = ret.Get();
-
-    for (int i = 0; i < width * height * depth; ++i)
-    {
-        dest[0] = data[0];
-        dest[1] = data[1];
-        dest[2] = data[2];
-        dest[3] = 255;
-        dest += 4;
-        data += 3;
-    }
-
-    return ret;
-}
-
 unsigned Texture::CheckMaxLevels(int width, int height, unsigned requestedLevels)
 unsigned Texture::CheckMaxLevels(int width, int height, unsigned requestedLevels)
 {
 {
     unsigned maxLevels = 1;
     unsigned maxLevels = 1;

+ 0 - 4
Source/Urho3D/Graphics/Direct3D11/D3D11Texture.h

@@ -118,10 +118,6 @@ public:
     /// Return sampler state object.
     /// Return sampler state object.
     void* GetSampler() const { return sampler_; }
     void* GetSampler() const { return sampler_; }
     
     
-    /// Convert RGB data to RGBA for loading into a texture.
-    static SharedArrayPtr<unsigned char> ConvertRGBToRGBA(int width, int height, const unsigned char* data);
-    /// Convert RGB data to RGBA for loading into a 3D texture.
-    static SharedArrayPtr<unsigned char> ConvertRGBToRGBA(int width, int height, int depth, const unsigned char* data);
     /// Check maximum allowed mip levels for a specific texture size.
     /// Check maximum allowed mip levels for a specific texture size.
     static unsigned CheckMaxLevels(int width, int height, unsigned requestedLevels);
     static unsigned CheckMaxLevels(int width, int height, unsigned requestedLevels);
     /// Check maximum allowed mip levels for a specific 3D texture size.
     /// Check maximum allowed mip levels for a specific 3D texture size.

+ 11 - 18
Source/Urho3D/Graphics/Direct3D11/D3D11Texture2D.cpp

@@ -267,10 +267,19 @@ bool Texture2D::SetData(SharedPtr<Image> image, bool useAlpha)
     
     
     if (!image->IsCompressed())
     if (!image->IsCompressed())
     {
     {
+        // Convert unsuitable formats to RGBA
+        unsigned components = image->GetComponents();
+        if ((components == 1 && !useAlpha) || components == 2 || components == 3)
+        {
+            image = image->ConvertToRGBA();
+            if (!image)
+                return false;
+            components = image->GetComponents();
+        }
+
         unsigned char* levelData = image->GetData();
         unsigned char* levelData = image->GetData();
         int levelWidth = image->GetWidth();
         int levelWidth = image->GetWidth();
         int levelHeight = image->GetHeight();
         int levelHeight = image->GetHeight();
-        unsigned components = image->GetComponents();
         unsigned format = 0;
         unsigned format = 0;
         
         
         // Discard unnecessary mip levels
         // Discard unnecessary mip levels
@@ -285,15 +294,7 @@ bool Texture2D::SetData(SharedPtr<Image> image, bool useAlpha)
         switch (components)
         switch (components)
         {
         {
         case 1:
         case 1:
-            format = useAlpha ? Graphics::GetAlphaFormat() : Graphics::GetLuminanceFormat();
-            break;
-            
-        case 2:
-            format = Graphics::GetLuminanceAlphaFormat();
-            break;
-            
-        case 3:
-            format = Graphics::GetRGBFormat();
+            format = Graphics::GetAlphaFormat();
             break;
             break;
             
             
         case 4:
         case 4:
@@ -308,14 +309,6 @@ bool Texture2D::SetData(SharedPtr<Image> image, bool useAlpha)
         
         
         for (unsigned i = 0; i < levels_; ++i)
         for (unsigned i = 0; i < levels_; ++i)
         {
         {
-            // D3D11 needs RGB data as 4-component
-            SharedArrayPtr<unsigned char> convertedData;
-            if (components == 3)
-            {
-                convertedData = ConvertRGBToRGBA(levelWidth, levelHeight, levelData);
-                levelData = convertedData;
-            }
-
             SetData(i, 0, 0, levelWidth, levelHeight, levelData);
             SetData(i, 0, 0, levelWidth, levelHeight, levelData);
             memoryUse += levelWidth * levelHeight * components;
             memoryUse += levelWidth * levelHeight * components;
             
             

+ 12 - 19
Source/Urho3D/Graphics/Direct3D11/D3D11Texture3D.cpp

@@ -324,11 +324,20 @@ bool Texture3D::SetData(SharedPtr<Image> image, bool useAlpha)
     
     
     if (!image->IsCompressed())
     if (!image->IsCompressed())
     {
     {
+        // Convert unsuitable formats to RGBA
+        unsigned components = image->GetComponents();
+        if ((components == 1 && !useAlpha) || components == 2 || components == 3)
+        {
+            image = image->ConvertToRGBA();
+            if (!image)
+                return false;
+            components = image->GetComponents();
+        }
+
         unsigned char* levelData = image->GetData();
         unsigned char* levelData = image->GetData();
         int levelWidth = image->GetWidth();
         int levelWidth = image->GetWidth();
         int levelHeight = image->GetHeight();
         int levelHeight = image->GetHeight();
         int levelDepth = image->GetDepth();
         int levelDepth = image->GetDepth();
-        unsigned components = image->GetComponents();
         unsigned format = 0;
         unsigned format = 0;
         
         
         // Discard unnecessary mip levels
         // Discard unnecessary mip levels
@@ -344,17 +353,9 @@ bool Texture3D::SetData(SharedPtr<Image> image, bool useAlpha)
         switch (components)
         switch (components)
         {
         {
         case 1:
         case 1:
-            format = useAlpha ? Graphics::GetAlphaFormat() : Graphics::GetLuminanceFormat();
-            break;
-            
-        case 2:
-            format = Graphics::GetLuminanceAlphaFormat();
+            format = Graphics::GetAlphaFormat();
             break;
             break;
-            
-        case 3:
-            format = Graphics::GetRGBFormat();
-            break;
-            
+
         case 4:
         case 4:
             format = Graphics::GetRGBAFormat();
             format = Graphics::GetRGBAFormat();
             break;
             break;
@@ -367,14 +368,6 @@ bool Texture3D::SetData(SharedPtr<Image> image, bool useAlpha)
         
         
         for (unsigned i = 0; i < levels_; ++i)
         for (unsigned i = 0; i < levels_; ++i)
         {
         {
-            // D3D11 needs RGB data as 4-component
-            SharedArrayPtr<unsigned char> convertedData;
-            if (components == 3)
-            {
-                convertedData = ConvertRGBToRGBA(levelWidth, levelHeight, levelDepth, levelData);
-                levelData = convertedData;
-            }
-
             SetData(i, 0, 0, 0, levelWidth, levelHeight, levelDepth, levelData);
             SetData(i, 0, 0, 0, levelWidth, levelHeight, levelDepth, levelData);
             memoryUse += levelWidth * levelHeight * levelDepth * components;
             memoryUse += levelWidth * levelHeight * levelDepth * components;
             
             

+ 13 - 20
Source/Urho3D/Graphics/Direct3D11/D3D11TextureCube.cpp

@@ -422,10 +422,19 @@ bool TextureCube::SetData(CubeMapFace face, SharedPtr<Image> image, bool useAlph
     
     
     if (!image->IsCompressed())
     if (!image->IsCompressed())
     {
     {
+        // Convert unsuitable formats to RGBA
+        unsigned components = image->GetComponents();
+        if ((components == 1 && !useAlpha) || components == 2 || components == 3)
+        {
+            image = image->ConvertToRGBA();
+            if (!image)
+                return false;
+            components = image->GetComponents();
+        }
+
         unsigned char* levelData = image->GetData();
         unsigned char* levelData = image->GetData();
         int levelWidth = image->GetWidth();
         int levelWidth = image->GetWidth();
         int levelHeight = image->GetHeight();
         int levelHeight = image->GetHeight();
-        unsigned components = image->GetComponents();
         unsigned format = 0;
         unsigned format = 0;
         
         
         if (levelWidth != levelHeight)
         if (levelWidth != levelHeight)
@@ -433,7 +442,7 @@ bool TextureCube::SetData(CubeMapFace face, SharedPtr<Image> image, bool useAlph
             LOGERROR("Cube texture width not equal to height");
             LOGERROR("Cube texture width not equal to height");
             return false;
             return false;
         }
         }
-        
+
         // Discard unnecessary mip levels
         // Discard unnecessary mip levels
         for (unsigned i = 0; i < mipsToSkip_[quality]; ++i)
         for (unsigned i = 0; i < mipsToSkip_[quality]; ++i)
         {
         {
@@ -446,17 +455,9 @@ bool TextureCube::SetData(CubeMapFace face, SharedPtr<Image> image, bool useAlph
         switch (components)
         switch (components)
         {
         {
         case 1:
         case 1:
-            format = useAlpha ? Graphics::GetAlphaFormat() : Graphics::GetLuminanceFormat();
+            format = Graphics::GetAlphaFormat();
             break;
             break;
-            
-        case 2:
-            format = Graphics::GetLuminanceAlphaFormat();
-            break;
-            
-        case 3:
-            format = Graphics::GetRGBFormat();
-            break;
-            
+
         case 4:
         case 4:
             format = Graphics::GetRGBAFormat();
             format = Graphics::GetRGBAFormat();
             break;
             break;
@@ -486,14 +487,6 @@ bool TextureCube::SetData(CubeMapFace face, SharedPtr<Image> image, bool useAlph
         
         
         for (unsigned i = 0; i < levels_; ++i)
         for (unsigned i = 0; i < levels_; ++i)
         {
         {
-            // D3D11 needs RGB data as 4-component
-            SharedArrayPtr<unsigned char> convertedData;
-            if (components == 3)
-            {
-                convertedData = ConvertRGBToRGBA(levelWidth, levelHeight, levelData);
-                levelData = convertedData;
-            }
-
             SetData(face, i, 0, 0, levelWidth, levelHeight, levelData);
             SetData(face, i, 0, 0, levelWidth, levelHeight, levelData);
             memoryUse += levelWidth * levelHeight * components;
             memoryUse += levelWidth * levelHeight * components;
             
             

+ 10 - 1
Source/Urho3D/Graphics/OpenGL/OGLTexture2D.cpp

@@ -277,10 +277,19 @@ bool Texture2D::SetData(SharedPtr<Image> image, bool useAlpha)
     
     
     if (!image->IsCompressed())
     if (!image->IsCompressed())
     {
     {
+        // Convert unsuitable formats to RGBA
+        unsigned components = image->GetComponents();
+        if (Graphics::GetGL3Support() && ((components == 1 && !useAlpha) || components == 2))
+        {
+            image = image->ConvertToRGBA();
+            if (!image)
+                return false;
+            components = image->GetComponents();
+        }
+
         unsigned char* levelData = image->GetData();
         unsigned char* levelData = image->GetData();
         int levelWidth = image->GetWidth();
         int levelWidth = image->GetWidth();
         int levelHeight = image->GetHeight();
         int levelHeight = image->GetHeight();
-        unsigned components = image->GetComponents();
         unsigned format = 0;
         unsigned format = 0;
         
         
         // Discard unnecessary mip levels
         // Discard unnecessary mip levels

+ 10 - 1
Source/Urho3D/Graphics/OpenGL/OGLTexture3D.cpp

@@ -325,11 +325,20 @@ bool Texture3D::SetData(SharedPtr<Image> image, bool useAlpha)
     
     
     if (!image->IsCompressed())
     if (!image->IsCompressed())
     {
     {
+        // Convert unsuitable formats to RGBA
+        unsigned components = image->GetComponents();
+        if (Graphics::GetGL3Support() && ((components == 1 && !useAlpha) || components == 2))
+        {
+            image = image->ConvertToRGBA();
+            if (!image)
+                return false;
+            components = image->GetComponents();
+        }
+
         unsigned char* levelData = image->GetData();
         unsigned char* levelData = image->GetData();
         int levelWidth = image->GetWidth();
         int levelWidth = image->GetWidth();
         int levelHeight = image->GetHeight();
         int levelHeight = image->GetHeight();
         int levelDepth = image->GetDepth();
         int levelDepth = image->GetDepth();
-        unsigned components = image->GetComponents();
         unsigned format = 0;
         unsigned format = 0;
         
         
         // Discard unnecessary mip levels
         // Discard unnecessary mip levels

+ 10 - 1
Source/Urho3D/Graphics/OpenGL/OGLTextureCube.cpp

@@ -440,10 +440,19 @@ bool TextureCube::SetData(CubeMapFace face, SharedPtr<Image> image, bool useAlph
     
     
     if (!image->IsCompressed())
     if (!image->IsCompressed())
     {
     {
+        // Convert unsuitable formats to RGBA
+        unsigned components = image->GetComponents();
+        if (Graphics::GetGL3Support() && ((components == 1 && !useAlpha) || components == 2))
+        {
+            image = image->ConvertToRGBA();
+            if (!image)
+                return false;
+            components = image->GetComponents();
+        }
+
         unsigned char* levelData = image->GetData();
         unsigned char* levelData = image->GetData();
         int levelWidth = image->GetWidth();
         int levelWidth = image->GetWidth();
         int levelHeight = image->GetHeight();
         int levelHeight = image->GetHeight();
-        unsigned components = image->GetComponents();
         unsigned format = 0;
         unsigned format = 0;
         
         
         if (levelWidth != levelHeight)
         if (levelWidth != levelHeight)

+ 66 - 0
Source/Urho3D/Resource/Image.cpp

@@ -1425,6 +1425,72 @@ SharedPtr<Image> Image::GetNextLevel() const
     return mipImage;
     return mipImage;
 }
 }
 
 
+SharedPtr<Image> Image::ConvertToRGBA() const
+{
+    if (IsCompressed())
+    {
+        LOGERROR("Can not convert compressed image to RGBA");
+        return SharedPtr<Image>();
+    }
+    if (components_ < 1 || components_ > 4)
+    {
+        LOGERROR("Illegal number of image components for conversion to RGBA");
+        return SharedPtr<Image>();
+    }
+    if (!data_)
+    {
+        LOGERROR("Can not convert image without data to RGBA");
+        return SharedPtr<Image>();
+    }
+
+    // Already RGBA?
+    if (components_ == 4)
+        return SharedPtr<Image>(const_cast<Image*>(this));
+
+    SharedPtr<Image> ret(new Image(context_));
+    ret->SetSize(width_, height_, depth_, 4);
+    
+    const unsigned char* src = data_;
+    unsigned char* dest = ret->GetData();
+
+    switch (components_)
+    {
+    case 1:
+        for (unsigned i = 0; i < width_ * height_ * depth_; ++i)
+        {
+            unsigned char pixel = *src++;
+            *dest++ = pixel;
+            *dest++ = pixel;
+            *dest++ = pixel;
+            *dest++ = 255;
+        }
+        break;
+
+    case 2:
+        for (unsigned i = 0; i < width_ * height_ * depth_; ++i)
+        {
+            unsigned char pixel = *src++;
+            *dest++ = pixel;
+            *dest++ = pixel;
+            *dest++ = pixel;
+            *dest++ = *src++;
+        }
+        break;
+
+    case 3:
+        for (unsigned i = 0; i < width_ * height_ * depth_; ++i)
+        {
+            *dest++ = *src++;
+            *dest++ = *src++;
+            *dest++ = *src++;
+            *dest++ = 255;
+        }
+        break;
+    }
+
+    return ret;
+}
+
 CompressedLevel Image::GetCompressedLevel(unsigned index) const
 CompressedLevel Image::GetCompressedLevel(unsigned index) const
 {
 {
     CompressedLevel level;
     CompressedLevel level;

+ 2 - 0
Source/Urho3D/Resource/Image.h

@@ -169,6 +169,8 @@ public:
     unsigned GetNumCompressedLevels() const { return numCompressedLevels_; }
     unsigned GetNumCompressedLevels() const { return numCompressedLevels_; }
     /// Return next mip level by bilinear filtering.
     /// Return next mip level by bilinear filtering.
     SharedPtr<Image> GetNextLevel() const;
     SharedPtr<Image> GetNextLevel() const;
+    /// Return image converted to 4-component (RGBA) to circumvent modern rendering API's not supporting e.g. the luminance-alpha format.
+    SharedPtr<Image> ConvertToRGBA() const;
     /// Return a compressed mip level.
     /// Return a compressed mip level.
     CompressedLevel GetCompressedLevel(unsigned index) const;
     CompressedLevel GetCompressedLevel(unsigned index) const;
     /// Return subimage from the image by the defined rect or null if failed. 3D images are not supported. You must free the subimage yourself.
     /// Return subimage from the image by the defined rect or null if failed. 3D images are not supported. You must free the subimage yourself.

BIN
bin/CoreData/Textures/Spot.png


BIN
bin/CoreData/Textures/SpotWide.png