Ver Fonte

On Windows, save DDS versions of textures in cache on import and look for those when loading a texture.

Matt Benic há 9 anos atrás
pai
commit
81e01532a1

+ 91 - 1
Source/Atomic/Resource/Image.cpp

@@ -33,6 +33,7 @@
 #include <SDL/include/SDL_surface.h>
 #include <STB/stb_image.h>
 #include <STB/stb_image_write.h>
+#include <crunch/inc/crnlib.h>
 
 #include "../DebugNew.h"
 
@@ -246,7 +247,9 @@ Image::Image(Context* context) :
     components_(0),
     cubemap_(false),
     array_(false),
-    sRGB_(false)
+    sRGB_(false),
+    pot_(false),
+    hasAlphaChannel_(false)
 {
 }
 
@@ -800,6 +803,8 @@ bool Image::SetSize(int width, int height, int depth, unsigned components)
     components_ = components;
     compressedFormat_ = CF_NONE;
     numCompressedLevels_ = 0;
+    pot_ = IsPowerOfTwo(width_) && IsPowerOfTwo(height_);
+    hasAlphaChannel_ = components > 3;
     nextLevel_.Reset();
 
     SetMemoryUse(width * height * depth * components);
@@ -1211,6 +1216,91 @@ bool Image::SaveJPG(const String& fileName, int quality) const
         return false;
 }
 
+bool Image::SaveDDS(const String& fileName) const
+{
+    PROFILE(SaveImageDDS);
+
+    FileSystem* fileSystem = GetSubsystem<FileSystem>();
+    if (fileSystem && !fileSystem->CheckAccess(GetPath(fileName)))
+    {
+        LOGERROR("Access denied to " + fileName);
+        return false;
+    }
+
+    if (IsCompressed())
+    {
+        LOGERROR("Can not save compressed image to DDS");
+        return false;
+    }
+
+    if (data_)
+    {
+        // #623 BEGIN TODO: Should have an abstract ImageReader and ImageWriter classes
+        // with subclasses for particular image output types. Also should have image settings in the image meta.
+        // ImageReader/Writers should also support a progress callback so UI can be updated.
+
+        // Compression setup
+        crn_comp_params compParams;
+        compParams.m_width = width_;
+        compParams.m_height = height_;
+        compParams.set_flag(cCRNCompFlagPerceptual, true); // IsSRGB() incorrectly returning false
+        compParams.set_flag(cCRNCompFlagDXT1AForTransparency, false);
+        compParams.set_flag(cCRNCompFlagHierarchical, true);
+        compParams.m_file_type = cCRNFileTypeDDS;
+        compParams.m_format = (hasAlphaChannel_ ? cCRNFmtDXT5 : cCRNFmtDXT1);
+
+        compParams.m_pImages[0][0] = (uint32_t*)data_.Get();
+
+        compParams.m_target_bitrate = 0;
+        compParams.m_quality_level = 255;
+        compParams.m_num_helper_threads = 1;
+        compParams.m_pProgress_func = nullptr;
+
+        // Mipmap setup
+        crn_mipmap_params mipParams;
+        mipParams.m_gamma_filtering = true; // IsSRGB() incorrectly returns false
+        mipParams.m_mode = cCRNMipModeNoMips; // or cCRNMipModeGenerateMips
+
+        // Output params
+        crn_uint32 actualQualityLevel;
+        float actualBitrate;
+        crn_uint32 outputFileSize;
+
+        void* compressedData = crn_compress(
+            compParams, 
+            mipParams, 
+            outputFileSize, 
+            &actualQualityLevel, 
+            &actualBitrate);
+
+        if (nullptr == compressedData)
+        {
+            LOGERROR("Failed to compress image to DXT");
+            return false;
+        }
+
+        FileSystem* fileSystem = GetSubsystem<FileSystem>();
+        SharedPtr<File> dest(new File(context_, fileName, FILE_WRITE));
+
+        if (dest.Null())
+        {
+            // Open error already logged
+            crn_free_block(compressedData);
+            return false;
+        }
+        else
+        {
+            bool success = dest->Write(compressedData, outputFileSize) == outputFileSize;
+            crn_free_block(compressedData);
+            return success;
+        }
+        
+        // #623 END TODO
+    }
+
+    return false;
+}
+
 Color Image::GetPixel(int x, int y) const
 {
     return GetPixel(x, y, 0);

+ 10 - 0
Source/Atomic/Resource/Image.h

@@ -138,12 +138,18 @@ public:
     bool SaveTGA(const String& fileName) const;
     /// Save in JPG format with compression quality. Return true if successful.
     bool SaveJPG(const String& fileName, int quality) const;
+    /// Save in DDS format. Return true if successful.
+    bool SaveDDS(const String& fileName) const;
     /// Whether this texture is detected as a cubemap, only relevant for DDS.
     bool IsCubemap() const { return cubemap_; }
     /// Whether this texture has been detected as a volume, only relevant for DDS.
     bool IsArray() const { return array_; }
     /// Whether this texture is in sRGB, only relevant for DDS.
     bool IsSRGB() const { return sRGB_; }
+    /// Whether this texture has power of two dimensions
+    bool IsPOT() const { return pot_; }
+    /// Whether this texture has an alpha channel
+    bool HasAlphaChannel() const { return hasAlphaChannel_; }
 
     /// Return a 2D pixel color.
     Color GetPixel(int x, int y) const;
@@ -219,6 +225,10 @@ private:
     bool array_;
     /// Data is sRGB.
     bool sRGB_;
+    /// Dimensions are power of two
+    bool pot_;
+    /// Image has alpha channel
+    bool hasAlphaChannel_;
     /// Compressed format.
     CompressedFormat compressedFormat_;
     /// Pixel data.

+ 20 - 1
Source/Atomic/Resource/ResourceCache.cpp

@@ -595,7 +595,26 @@ Resource* ResourceCache::GetResource(StringHash type, const String& nameIn, bool
     }
 
     // Attempt to load the resource
-    SharedPtr<File> file = GetFile(name, sendEventOnFailure);
+    SharedPtr<File> file;
+
+    // #623 BEGIN TODO: For now try to get DDS version of textures from /DDS cache sub directory,
+    // ultimately should have per platform compressed versions saved in cache
+#if ATOMIC_PLATFORM_WINDOWS
+    String ext = Atomic::GetExtension(name);
+    if (ext == ".jpg" || ext == ".png" || ext == ".tga")
+    {
+        String ddsName = "DDS/" + name + ".dds";
+        file = GetFile(ddsName, false);
+        if (file)
+            LOGDEBUG("Loaded cached DDS " + name + ".dds");
+    }
+    if (!file)
+        file = GetFile(name, sendEventOnFailure);
+#else
+    // #623 END TODO
+    file = GetFile(name, sendEventOnFailure);
+#endif
+
     if (!file)
         return 0;   // Error is already logged
 

+ 22 - 3
Source/ToolCore/Assets/TextureImporter.cpp

@@ -9,6 +9,7 @@
 #include <Atomic/Resource/Image.h>
 #include <Atomic/Atomic2D/Sprite2D.h>
 #include <Atomic/Atomic2D/StaticSprite2D.h>
+#include <Atomic/IO/FileSystem.h>
 
 #include "Asset.h"
 #include "AssetDatabase.h"
@@ -35,18 +36,36 @@ void TextureImporter::SetDefaults()
 bool TextureImporter::Import()
 {
     AssetDatabase* db = GetSubsystem<AssetDatabase>();
-
     ResourceCache* cache = GetSubsystem<ResourceCache>();
+    String cachePath = db->GetCachePath();
+
+    // #623 BEGIN TODO: Delete previously saved per-platform compressed version so
+    // it won't get re-loaded here
+#if ATOMIC_PLATFORM_WINDOWS
+    FileSystem* fileSystem = GetSubsystem<FileSystem>();
+    String compressedPath = cachePath + "DDS/" + asset_->GetRelativePath() + ".dds";
+    fileSystem->Delete(compressedPath);
+#endif
+    // #623 END TODO
+
     SharedPtr<Image> image = cache->GetTempResource<Image>(asset_->GetPath());
 
     if (image.Null())
         return false;
 
+    // #623 BEGIN TODO: Save per-platform compressed version to cache
+#if ATOMIC_PLATFORM_WINDOWS
+    if (!image->IsCompressed())
+    {
+        fileSystem->CreateDirs(cachePath, "DDS/" + Atomic::GetPath(asset_->GetRelativePath()));
+        image->SaveDDS(compressedPath);
+    }
+#endif
+    // #623 END TODO
+
     // todo, proper proportions
     image->Resize(64, 64);
 
-    String cachePath = db->GetCachePath();
-
     // not sure entirely what we want to do here, though if the cache file doesn't exist
     // will reimport
     image->SavePNG(cachePath + asset_->GetGUID());