Browse Source

Added Image::GetSDLSurface() to avoid code duplication. Fixed crash from null image pointer in Graphics::CreateWindowIcon().

Lasse Öörni 12 years ago
parent
commit
d1df925013

+ 3 - 15
Source/Engine/Graphics/Direct3D9/D3D9Graphics.cpp

@@ -272,9 +272,7 @@ void Graphics::SetWindowIcon(Image* windowIcon)
 {
     windowIcon_ = windowIcon;
     if (impl_->window_)
-    {
         CreateWindowIcon();
-    }
 }
 
 void Graphics::SetWindowPosition(const IntVector2& position)
@@ -2221,22 +2219,12 @@ void Graphics::CreateWindowIcon()
 {
     if (windowIcon_)
     {
-        SDL_Surface*  surface = SDL_CreateRGBSurface(0, windowIcon_->GetWidth(), windowIcon_->GetHeight(), windowIcon_->GetComponents() * BITS_PER_COMPONENT, 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000);
-
-        if (windowIcon_->GetMemoryUse() > 0)
+        SDL_Surface* surface = windowIcon_->GetSDLSurface();
+        if (surface)
         {
-            SDL_LockSurface(surface);
-            memcpy(surface->pixels, windowIcon_->GetData(), windowIcon_->GetMemoryUse());
-            SDL_UnlockSurface(surface);
-
             SDL_SetWindowIcon(impl_->window_, surface);
+            SDL_FreeSurface(surface);
         }
-
-        SDL_FreeSurface(surface);
-    }
-    else
-    {
-        LOGERROR("Unable to load icon windowIcon_ " + windowIcon_->GetName());
     }
 }
 

+ 3 - 15
Source/Engine/Graphics/OpenGL/OGLGraphics.cpp

@@ -217,9 +217,7 @@ void Graphics::SetWindowIcon(Image* windowIcon)
 {
     windowIcon_ = windowIcon;
     if (impl_->window_)
-    {
         CreateWindowIcon();
-    }
 }
 
 void Graphics::SetWindowPosition(const IntVector2& position)
@@ -2402,22 +2400,12 @@ void Graphics::CreateWindowIcon()
 {
     if (windowIcon_)
     {
-        SDL_Surface*  surface = SDL_CreateRGBSurface(0, windowIcon_->GetWidth(), windowIcon_->GetHeight(), windowIcon_->GetComponents() * BITS_PER_COMPONENT, 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000);
-
-        if (windowIcon_->GetMemoryUse() > 0)
+        SDL_Surface* surface = windowIcon_->GetSDLSurface();
+        if (surface)
         {
-            SDL_LockSurface(surface);
-            memcpy(surface->pixels, windowIcon_->GetData(), windowIcon_->GetMemoryUse());
-            SDL_UnlockSurface(surface);
-
             SDL_SetWindowIcon(impl_->window_, surface);
+            SDL_FreeSurface(surface);
         }
-
-        SDL_FreeSurface(surface);
-    }
-    else
-    {
-        LOGERROR("Unable to load icon windowIcon_ " + windowIcon_->GetName());
     }
 }
 

+ 61 - 0
Source/Engine/Resource/Image.cpp

@@ -31,6 +31,7 @@
 #include <stb_image.h>
 #include <stb_image_write.h>
 #include <jo_jpeg.h>
+#include <SDL_surface.h>
 
 #include "DebugNew.h"
 
@@ -854,4 +855,64 @@ CompressedLevel Image::GetCompressedLevel(unsigned index) const
     }
 }
 
+SDL_Surface* Image::GetSDLSurface(const IntRect& rect) const
+{
+    if (!data_)
+        return 0;
+    
+    if (IsCompressed())
+    {
+        LOGERROR("Can not get SDL surface from compressed image " + GetName());
+        return 0;
+    }
+    
+    if (components_ < 3)
+    {
+        LOGERROR("Can not get SDL surface from image " + GetName() + " with less than 3 components");
+        return 0;
+    }
+    
+    IntRect imageRect = rect;
+    // Use full image if illegal rect
+    if (imageRect.left_ < 0 || imageRect.top_ < 0 || imageRect.right_ > width_ || imageRect.bottom_ > height_ || 
+        imageRect.left_ >= imageRect.right_ || imageRect.top_ >= imageRect.bottom_)
+    {
+        imageRect.left_ = 0;
+        imageRect.top_ = 0;
+        imageRect.right_ = width_;
+        imageRect.bottom_ = height_;
+    }
+    
+    int imageWidth = width_;
+    int width = imageRect.Width();
+    int height = imageRect.Height();
+
+    // Assume little-endian for all the supported platforms
+    unsigned rMask = 0x000000ff;
+    unsigned gMask = 0x0000ff00;
+    unsigned bMask = 0x00ff0000;
+    unsigned aMask = 0xff000000;
+
+    SDL_Surface* surface = SDL_CreateRGBSurface(0, width, height, components_ * 8, rMask, gMask, bMask, aMask);
+    if (surface)
+    {
+        SDL_LockSurface(surface);
+        
+        unsigned char* destination = reinterpret_cast<unsigned char*>(surface->pixels);
+        unsigned char* source = data_ + components_ * (imageWidth * imageRect.top_ + imageRect.left_);
+        for (int i = 0; i < height; ++i)
+        {
+            memcpy(destination, source, components_ * width);
+            destination += surface->pitch;
+            source += components_ * imageWidth;
+        }
+        
+        SDL_UnlockSurface(surface);
+    }
+    else
+        LOGERROR("Failed to create SDL surface from image " + GetName());
+    
+    return surface;
+}
+
 }

+ 4 - 0
Source/Engine/Resource/Image.h

@@ -25,6 +25,8 @@
 #include "ArrayPtr.h"
 #include "Resource.h"
 
+struct SDL_Surface;
+
 namespace Urho3D
 {
 
@@ -108,6 +110,8 @@ public:
     bool SaveTGA(const String& fileName);
     /// Save in JPG format with compression quality. Return true if successful.
     bool SaveJPG(const String& fileName, int quality);
+    /// Create SDL surface from the image, or null if failed. Specify rect to only return partial image. Only RGB images are supported. You must free the surface yourself.
+    SDL_Surface* GetSDLSurface(const IntRect& rect = IntRect::ZERO) const;
     
     /// Return width.
     int GetWidth() const { return width_; }

+ 2 - 20
Source/Engine/UI/Cursor.cpp

@@ -251,28 +251,10 @@ void Cursor::ApplyShape()
             // Create from image
             else if (info.image_)
             {
-                unsigned comp = info.image_->GetComponents();
-                int imageWidth = info.image_->GetWidth();
-                int width = imageRect_.Width();
-                int height = imageRect_.Height();
-
-                // Assume little-endian for all the supported platforms
-                unsigned rMask = 0x000000ff;
-                unsigned gMask = 0x0000ff00;
-                unsigned bMask = 0x00ff0000;
-                unsigned aMask = 0xff000000;
-
-                SDL_Surface* surface = (comp >= 3 ? SDL_CreateRGBSurface(0, width, height, comp * 8, rMask, gMask, bMask, aMask) : 0);
+                SDL_Surface* surface = info.image_->GetSDLSurface(info.imageRect_);
+                
                 if (surface)
                 {
-                    unsigned char* destination = reinterpret_cast<unsigned char*>(surface->pixels);
-                    unsigned char* source = info.image_->GetData() + comp * (imageWidth * imageRect_.top_ + imageRect_.left_);
-                    for (int i = 0; i < height; ++i)
-                    {
-                        memcpy(destination, source, comp * width);
-                        destination += comp * width;
-                        source += comp * imageWidth;
-                    }
                     info.osCursor_ = SDL_CreateColorCursor(surface, info.hotSpot_.x_, info.hotSpot_.y_);
                     info.systemDefined_ = false;
                     if (!info.osCursor_)