Browse Source

Fix GetData() from rendertarget textures on D3D9. Thanks for JSandusky for bringing into attention. Added GetComponents() to Texture to easily determine which kind of Image needs to be created to receive the texture data.

Lasse Öörni 10 years ago
parent
commit
46ebfb4b22

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

@@ -248,6 +248,14 @@ unsigned Texture::GetRowDataSize(int width) const
     }
 }
 
+unsigned Texture::GetComponents() const
+{
+    if (!width_ || IsCompressed())
+        return 0;
+    else
+        return GetRowDataSize(width_) / width_;
+}
+
 void Texture::SetParameters(XMLFile* file)
 {
     if (!file)

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

@@ -102,6 +102,8 @@ public:
     unsigned GetDataSize(int width, int height, int depth) const;
     /// Return data size in bytes for a pixel or block row.
     unsigned GetRowDataSize(int width) const;
+    /// Return number of image components required to receive pixel data from GetData(), or 0 for compressed images.
+    unsigned GetComponents() const;
     /// Return whether the parameters are dirty.
     bool GetParametersDirty() const { return parametersDirty_ || !sampler_; }
 

+ 8 - 0
Source/Urho3D/Graphics/Direct3D9/D3D9Texture.cpp

@@ -233,6 +233,14 @@ unsigned Texture::GetRowDataSize(int width) const
     }
 }
 
+unsigned Texture::GetComponents() const
+{
+    if (!width_ || IsCompressed())
+        return 0;
+    else
+        return GetRowDataSize(width_) / width_;
+}
+
 void Texture::SetParameters(XMLFile* file)
 {
     if (!file)

+ 2 - 0
Source/Urho3D/Graphics/Direct3D9/D3D9Texture.h

@@ -101,6 +101,8 @@ public:
     unsigned GetDataSize(int width, int height, int depth) const;
     /// Return data size in bytes for a pixel or block row.
     unsigned GetRowDataSize(int width) const;
+    /// Return number of image components required to receive pixel data from GetData(), or 0 for compressed images.
+    unsigned GetComponents() const;
 
     /// Set additional parameters from an XML file.
     void SetParameters(XMLFile* xml);

+ 40 - 5
Source/Urho3D/Graphics/Direct3D9/D3D9Texture2D.cpp

@@ -463,12 +463,40 @@ bool Texture2D::GetData(unsigned level, void* dest) const
     d3dRect.right = levelWidth;
     d3dRect.bottom = levelHeight;
     
-    if (FAILED(((IDirect3DTexture9*)object_)->LockRect(level, &d3dLockedRect, &d3dRect, D3DLOCK_READONLY)))
+    IDirect3DSurface9* offscreenSurface = 0;
+    // Need to use a offscreen surface & GetRenderTargetData() for rendertargets
+    if (renderSurface_)
     {
-        LOGERROR("Could not lock texture");
-        return false;
+        if (level != 0)
+        {
+            LOGERROR("Can only get mip level 0 data from a rendertarget");
+            return false;
+        }
+
+        IDirect3DDevice9* device = graphics_->GetImpl()->GetDevice();
+        device->CreateOffscreenPlainSurface(width_, height_, (D3DFORMAT)format_, D3DPOOL_SYSTEMMEM, &offscreenSurface, 0);
+        if (!offscreenSurface)
+        {
+            LOGERROR("Could not create surface for getting rendertarget data");
+            return false;
+        }
+        device->GetRenderTargetData((IDirect3DSurface9*)renderSurface_->GetSurface(), offscreenSurface);
+        if (FAILED(offscreenSurface->LockRect(&d3dLockedRect, &d3dRect, D3DLOCK_READONLY)))
+        {
+            LOGERROR("Could not lock surface for getting rendertarget data");
+            offscreenSurface->Release();
+            return false;
+        }
     }
-    
+    else
+    {
+        if (FAILED(((IDirect3DTexture9*)object_)->LockRect(level, &d3dLockedRect, &d3dRect, D3DLOCK_READONLY)))
+        {
+            LOGERROR("Could not lock texture");
+            return false;
+        }
+    }
+
     int height = levelHeight;
     if (IsCompressed())
         height = (height + 3) >> 2;
@@ -516,7 +544,14 @@ bool Texture2D::GetData(unsigned level, void* dest) const
         break;
     }
     
-    ((IDirect3DTexture9*)object_)->UnlockRect(level);
+    if (offscreenSurface)
+    {
+        offscreenSurface->UnlockRect();
+        offscreenSurface->Release();
+    }
+    else
+        ((IDirect3DTexture9*)object_)->UnlockRect(level);
+
     return true;
 }
 

+ 39 - 4
Source/Urho3D/Graphics/Direct3D9/D3D9TextureCube.cpp

@@ -668,10 +668,38 @@ bool TextureCube::GetData(CubeMapFace face, unsigned level, void* dest) const
     d3dRect.right = levelWidth;
     d3dRect.bottom = levelHeight;
     
-    if (FAILED(((IDirect3DCubeTexture9*)object_)->LockRect((D3DCUBEMAP_FACES)face, level, &d3dLockedRect, &d3dRect, D3DLOCK_READONLY)))
+    IDirect3DSurface9* offscreenSurface = 0;
+    // Need to use a offscreen surface & GetRenderTargetData() for rendertargets
+    if (renderSurfaces_[face])
     {
-        LOGERROR("Could not lock texture");
-        return false;
+        if (level != 0)
+        {
+            LOGERROR("Can only get mip level 0 data from a rendertarget");
+            return false;
+        }
+
+        IDirect3DDevice9* device = graphics_->GetImpl()->GetDevice();
+        device->CreateOffscreenPlainSurface(width_, height_, (D3DFORMAT)format_, D3DPOOL_SYSTEMMEM, &offscreenSurface, 0);
+        if (!offscreenSurface)
+        {
+            LOGERROR("Could not create surface for getting rendertarget data");
+            return false;
+        }
+        device->GetRenderTargetData((IDirect3DSurface9*)renderSurfaces_[face]->GetSurface(), offscreenSurface);
+        if (FAILED(offscreenSurface->LockRect(&d3dLockedRect, &d3dRect, D3DLOCK_READONLY)))
+        {
+            LOGERROR("Could not lock surface for getting rendertarget data");
+            offscreenSurface->Release();
+            return false;
+        }
+    }
+    else
+    {
+        if (FAILED(((IDirect3DCubeTexture9*)object_)->LockRect((D3DCUBEMAP_FACES)face, level, &d3dLockedRect, &d3dRect, D3DLOCK_READONLY)))
+        {
+            LOGERROR("Could not lock texture");
+            return false;
+        }
     }
     
     int height = levelHeight;
@@ -721,7 +749,14 @@ bool TextureCube::GetData(CubeMapFace face, unsigned level, void* dest) const
         break;
     }
     
-    ((IDirect3DCubeTexture9*)object_)->UnlockRect((D3DCUBEMAP_FACES)face, level);
+    if (offscreenSurface)
+    {
+        offscreenSurface->UnlockRect();
+        offscreenSurface->Release();
+    }
+    else
+        ((IDirect3DCubeTexture9*)object_)->UnlockRect((D3DCUBEMAP_FACES)face, level);
+    
     return true;
 }
 

+ 8 - 0
Source/Urho3D/Graphics/OpenGL/OGLTexture.cpp

@@ -366,6 +366,14 @@ unsigned Texture::GetRowDataSize(int width) const
     }
 }
 
+unsigned Texture::GetComponents() const
+{
+    if (!width_ || IsCompressed())
+        return 0;
+    else
+        return GetRowDataSize(width_) / width_;
+}
+
 unsigned Texture::GetExternalFormat(unsigned format)
 {
     #ifndef GL_ES_VERSION_2_0

+ 2 - 0
Source/Urho3D/Graphics/OpenGL/OGLTexture.h

@@ -109,6 +109,8 @@ public:
     unsigned GetDataSize(int width, int height, int depth) const;
     /// Return data size in bytes for a pixel or block row.
     unsigned GetRowDataSize(int width) const;
+    /// Return number of image components required to receive pixel data from GetData(), or 0 for compressed images.
+    unsigned GetComponents() const;
     /// Return the non-internal texture format corresponding to an OpenGL internal format.
     static unsigned GetExternalFormat(unsigned format);
     /// Return the data type corresponding to an OpenGL internal format.

+ 3 - 1
Source/Urho3D/LuaScript/pkgs/Graphics/Texture.pkg

@@ -26,12 +26,14 @@ class Texture : public Resource
     TextureUsage GetUsage() const;
     unsigned GetDataSize(int width, int height) const;
     unsigned GetRowDataSize(int width) const;
-    
+    unsigned GetComponents() const;
+
     tolua_readonly tolua_property__get_set unsigned format;
     tolua_readonly tolua_property__is_set bool compressed;
     tolua_readonly tolua_property__get_set unsigned levels;
     tolua_readonly tolua_property__get_set int width;
     tolua_readonly tolua_property__get_set int height;
+    tolua_readonly tolua_property__get_set unsigned components;
     tolua_property__get_set TextureFilterMode filterMode;
     tolua_property__get_set Color& borderColor;
     tolua_property__get_set bool sRGB;

+ 1 - 0
Source/Urho3D/Script/APITemplates.h

@@ -849,6 +849,7 @@ template <class T> void RegisterTexture(asIScriptEngine* engine, const char* cla
     engine->RegisterObjectMethod(className, "void set_mipsToSkip(int, int)", asMETHOD(T, SetMipsToSkip), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "int get_mipsToSkip(int) const", asMETHOD(T, GetMipsToSkip), asCALL_THISCALL);
     engine->RegisterObjectMethod(className, "bool get_dataLost() const", asMETHODPR(T, IsDataLost, () const, bool), asCALL_THISCALL);
+    engine->RegisterObjectMethod(className, "uint get_components() const", asMETHOD(T, GetComponents), asCALL_THISCALL);
 }
 
 /// Template function for registering a class derived from StaticModel.