Commit 76c4b0f8 authored by hybrid's avatar hybrid

Add access to miplevels in addTexture, texture->lock, and texture->regenerateMipMapLevels.

This allows to create custom mipmap textures manually, or provide them from certain image formats that come with precalculated mipmaps.

git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@2912 dfc29bdd-3216-0410-991c-e03cc46cb475
parent 978c768a
......@@ -101,7 +101,7 @@ public:
\return Returns a pointer to the pixel data. The format of the pixel can
be determined by using getColorFormat(). 0 is returned, if
the texture cannot be locked. */
virtual void* lock(bool readOnly = false) = 0;
virtual void* lock(bool readOnly = false, u32 mipmapLevel=0) = 0;
//! Unlock function. Must be called after a lock() to the texture.
/** One should avoid to call unlock more than once before another lock. */
......@@ -149,7 +149,7 @@ public:
//! Regenerates the mip map levels of the texture.
/** Required after modifying the texture, usually after calling unlock(). */
virtual void regenerateMipMapLevels() = 0;
virtual void regenerateMipMapLevels(void* mipmapData=0) = 0;
//! Check whether the texture is a render target
/** \return True if this is a render target, otherwise false. */
......
......@@ -380,10 +380,13 @@ namespace video
/** \param name A name for the texture. Later calls of
getTexture() with this name will return this texture
\param image Image the texture is created from.
\mipmapData Optional pointer to a set of images which build up the
whole mipmap set. Must be images of the same color type as image. If
this parameter is not given, the mipmaps are derived from image.
\return Pointer to the newly created texture. This pointer
should not be dropped. See IReferenceCounted::drop() for more
information. */
virtual ITexture* addTexture(const io::path& name, IImage* image) = 0;
virtual ITexture* addTexture(const io::path& name, IImage* image, void* mipmapData=0) = 0;
//! Adds a new render target texture to the texture cache.
/** \param size Size of the texture, in pixels. Width and
......
......@@ -674,9 +674,9 @@ void CD3D8Driver::setMaterial(const SMaterial& material)
//! returns a device dependent texture from a software surface (IImage)
video::ITexture* CD3D8Driver::createDeviceDependentTexture(IImage* surface,const io::path& name)
video::ITexture* CD3D8Driver::createDeviceDependentTexture(IImage* surface,const io::path& name, void* mipmapData)
{
return new CD3D8Texture(surface, this, TextureCreationFlags, name);
return new CD3D8Texture(surface, this, TextureCreationFlags, name, mipmapData);
}
......
......@@ -257,7 +257,7 @@ namespace video
//! returns a device dependent texture from a software surface (IImage)
//! THIS METHOD HAS TO BE OVERRIDDEN BY DERIVED DRIVERS WITH OWN TEXTURES
virtual video::ITexture* createDeviceDependentTexture(IImage* surface, const io::path& name);
virtual video::ITexture* createDeviceDependentTexture(IImage* surface, const io::path& name, void* mipmapData=0);
// returns the current size of the screen or rendertarget
virtual const core::dimension2d<u32>& getCurrentRenderTargetSize() const;
......
......@@ -50,7 +50,7 @@ CD3D8Texture::CD3D8Texture(CD3D8Driver* driver, const core::dimension2d<u32>& si
//! constructor
CD3D8Texture::CD3D8Texture(IImage* image, CD3D8Driver* driver,
u32 flags, const io::path& name)
u32 flags, const io::path& name, void* mipmapData)
: ITexture(name), Texture(0), RTTSurface(0), Driver(driver),
TextureSize(0,0), ImageSize(0,0), Pitch(0),
HasMipMaps(false), IsRenderTarget(false)
......@@ -59,7 +59,7 @@ HasMipMaps(false), IsRenderTarget(false)
setDebugName("CD3D8Texture");
#endif
const bool generateMipLevels = Driver->getTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS);
HasMipMaps = Driver->getTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS);
Device=driver->getExposedVideoData().D3D8.D3DDev8;
if (Device)
......@@ -67,26 +67,11 @@ HasMipMaps(false), IsRenderTarget(false)
if (image)
{
if (createTexture(image, flags))
if (createTexture(flags, image))
{
if (copyTexture(image) && generateMipLevels)
if (copyTexture(image))
{
// create mip maps.
#ifndef _IRR_USE_D3DXFilterTexture_
// The D3DXFilterTexture function seems to get linked wrong when
// compiling with both D3D8 and 9, causing it not to work in the D3D9 device.
// So mipmapgeneration is replaced with my own bad generation in d3d 8 when
// compiling with both D3D 8 and 9.
HRESULT hr = D3DXFilterTexture(Texture, NULL, D3DX_DEFAULT , D3DX_DEFAULT );
if (FAILED(hr))
os::Printer::log("Could not create direct3d mip map levels.", ELL_WARNING);
else
HasMipMaps = true;
#else
createMipMaps();
HasMipMaps = true;
#endif
regenerateMipMapLevels(mipmapData);
}
}
else
......@@ -110,7 +95,7 @@ CD3D8Texture::~CD3D8Texture()
//! creates the hardware texture
bool CD3D8Texture::createTexture(video::IImage* image, u32 flags)
bool CD3D8Texture::createTexture(u32 flags, video::IImage* image)
{
ImageSize = image->getDimension();
......@@ -220,23 +205,30 @@ bool CD3D8Texture::copyTexture(video::IImage* image)
//! lock function
void* CD3D8Texture::lock(bool readOnly)
void* CD3D8Texture::lock(bool readOnly, u32 mipmapLevel)
{
if (!Texture)
return 0;
MipLevelLocked=mipmapLevel;
HRESULT hr;
D3DLOCKED_RECT rect;
if(!IsRenderTarget)
{
hr = Texture->LockRect(0, &rect, 0, readOnly?D3DLOCK_READONLY:0);
hr = Texture->LockRect(mipmapLevel, &rect, 0, readOnly?D3DLOCK_READONLY:0);
if (FAILED(hr))
{
os::Printer::log("Could not lock DIRECT3D9 Texture.", ELL_ERROR);
return 0;
}
}
else
{
D3DSURFACE_DESC desc;
Texture->GetLevelDesc(0, &desc);
if (!RTTSurface)
{
// Make RTT surface large enough for all miplevels (including 0)
D3DSURFACE_DESC desc;
Texture->GetLevelDesc(0, &desc);
hr = Device->CreateImageSurface(desc.Width, desc.Height, desc.Format, &RTTSurface);
if (FAILED(hr))
{
......@@ -246,33 +238,26 @@ void* CD3D8Texture::lock(bool readOnly)
}
IDirect3DSurface8 *surface = 0;
hr = Texture->GetSurfaceLevel(0, &surface);
hr = Texture->GetSurfaceLevel(mipmapLevel, &surface);
if (FAILED(hr))
{
os::Printer::log("Could not lock DIRECT3D8 Texture.", ELL_ERROR);
os::Printer::log("Could not lock DIRECT3D8 Texture.", "Could not get surface.", ELL_ERROR);
return 0;
}
hr = Device->CopyRects(surface, 0, 0, RTTSurface, 0);
surface->Release();
if(FAILED(hr))
{
os::Printer::log("Could not lock DIRECT3D8 Texture.", ELL_ERROR);
os::Printer::log("Could not lock DIRECT3D8 Texture.", "Data copy failed.", ELL_ERROR);
return 0;
}
hr = RTTSurface->LockRect(&rect, 0, readOnly?D3DLOCK_READONLY:0);
if(FAILED(hr))
{
os::Printer::log("Could not lock DIRECT3D8 Texture.", ELL_ERROR);
os::Printer::log("Could not lock DIRECT3D8 Texture.", "LockRect failed.", ELL_ERROR);
return 0;
}
return rect.pBits;
}
if (FAILED(hr))
{
os::Printer::log("Could not lock DIRECT3D8 Texture.", ELL_ERROR);
return 0;
}
return rect.pBits;
}
......@@ -284,7 +269,7 @@ void CD3D8Texture::unlock()
return;
if (!IsRenderTarget)
Texture->UnlockRect(0);
Texture->UnlockRect(MipLevelLocked);
else if (RTTSurface)
RTTSurface->UnlockRect();
}
......@@ -587,10 +572,59 @@ void CD3D8Texture::createRenderTarget()
//! Regenerates the mip map levels of the texture. Useful after locking and
//! modifying the texture
void CD3D8Texture::regenerateMipMapLevels()
void CD3D8Texture::regenerateMipMapLevels(void* mipmapData)
{
if (HasMipMaps)
if (mipmapData)
{
core::dimension2du size = TextureSize;
u32 level=0;
do
{
if (size.Width>1)
size.Width /=2;
if (size.Height>1)
size.Height /=2;
++level;
IDirect3DSurface8* mipSurface = 0;
HRESULT hr = Texture->GetSurfaceLevel(level, &mipSurface);
if (FAILED(hr) || !mipSurface)
{
os::Printer::log("Could not get mipmap level", ELL_WARNING);
return;
}
D3DSURFACE_DESC mipDesc;
mipSurface->GetDesc(&mipDesc);
D3DLOCKED_RECT miplr;
// lock mipmap surface
if (FAILED(mipSurface->LockRect(&miplr, NULL, 0)))
{
mipSurface->Release();
os::Printer::log("Could not lock texture", ELL_WARNING);
return;
}
memcpy(miplr.pBits, mipmapData, size.getArea()*getPitch()/TextureSize.Width);
mipmapData = (u8*)mipmapData+size.getArea()*getPitch()/TextureSize.Width;
// unlock
mipSurface->UnlockRect();
// release
mipSurface->Release();
} while (size.Width != 1 || size.Height != 1);
}
else if (HasMipMaps)
{
// create mip maps.
#ifndef _IRR_USE_D3DXFilterTexture_
// The D3DXFilterTexture function seems to get linked wrong when
// compiling with both D3D8 and 9, causing it not to work in the D3D9 device.
// So mipmapgeneration is replaced with my own bad generation in d3d 8 when
// compiling with both D3D 8 and 9.
HRESULT hr = D3DXFilterTexture(Texture, NULL, D3DX_DEFAULT , D3DX_DEFAULT );
if (FAILED(hr))
#endif
createMipMaps();
}
}
......
......@@ -29,7 +29,7 @@ public:
//! constructor
CD3D8Texture(IImage* image, CD3D8Driver* driver,
u32 flags, const io::path& name);
u32 flags, const io::path& name, void* mipmapData=0);
//! rendertarget constructor
CD3D8Texture(CD3D8Driver* driver, const core::dimension2d<u32>& size, const io::path& name);
......@@ -38,7 +38,7 @@ public:
virtual ~CD3D8Texture();
//! lock function
virtual void* lock(bool readOnly = false);
virtual void* lock(bool readOnly = false, u32 mipmapLevel=0);
//! unlock function
virtual void unlock();
......@@ -66,7 +66,7 @@ public:
//! Regenerates the mip map levels of the texture. Useful after locking and
//! modifying the texture
virtual void regenerateMipMapLevels();
virtual void regenerateMipMapLevels(void* mipmapData=0);
//! returns if it is a render target
virtual bool isRenderTarget() const;
......@@ -80,7 +80,7 @@ private:
void createRenderTarget();
//! creates the hardware texture
bool createTexture(IImage* Image, u32 flags);
bool createTexture(u32 flags, IImage* Image);
//! copies the image to the texture
bool copyTexture(IImage* Image);
......@@ -103,7 +103,9 @@ private:
core::dimension2d<u32> TextureSize;
core::dimension2d<u32> ImageSize;
s32 Pitch;
u32 MipLevelLocked;
ECOLOR_FORMAT ColorFormat;
bool HasMipMaps;
bool IsRenderTarget;
};
......
......@@ -720,9 +720,9 @@ void CD3D9Driver::setMaterial(const SMaterial& material)
//! returns a device dependent texture from a software surface (IImage)
video::ITexture* CD3D9Driver::createDeviceDependentTexture(IImage* surface,const io::path& name)
video::ITexture* CD3D9Driver::createDeviceDependentTexture(IImage* surface,const io::path& name, void* mipmapData)
{
return new CD3D9Texture(surface, this, TextureCreationFlags, name);
return new CD3D9Texture(surface, this, TextureCreationFlags, name, mipmapData);
}
......
......@@ -326,7 +326,7 @@ namespace video
//! returns a device dependent texture from a software surface (IImage)
//! THIS METHOD HAS TO BE OVERRIDDEN BY DERIVED DRIVERS WITH OWN TEXTURES
virtual video::ITexture* createDeviceDependentTexture(IImage* surface, const io::path& name);
virtual video::ITexture* createDeviceDependentTexture(IImage* surface, const io::path& name, void* mipmapData=0);
//! returns the current size of the screen or rendertarget
virtual const core::dimension2d<u32>& getCurrentRenderTargetSize() const;
......
......@@ -50,7 +50,7 @@ CD3D9Texture::CD3D9Texture(CD3D9Driver* driver, const core::dimension2d<u32>& si
//! constructor
CD3D9Texture::CD3D9Texture(IImage* image, CD3D9Driver* driver,
u32 flags, const io::path& name)
u32 flags, const io::path& name, void* mipmapData)
: ITexture(name), Texture(0), RTTSurface(0), Driver(driver), DepthSurface(0),
TextureSize(0,0), ImageSize(0,0), Pitch(0), ColorFormat(ECF_UNKNOWN),
HasMipMaps(false), HardwareMipMaps(false), IsRenderTarget(false)
......@@ -59,7 +59,7 @@ CD3D9Texture::CD3D9Texture(IImage* image, CD3D9Driver* driver,
setDebugName("CD3D9Texture");
#endif
const bool generateMipLevels = Driver->getTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS);
HasMipMaps = Driver->getTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS);
Device=driver->getExposedVideoData().D3D9.D3DDev9;
if (Device)
......@@ -69,22 +69,9 @@ CD3D9Texture::CD3D9Texture(IImage* image, CD3D9Driver* driver,
{
if (createTexture(flags, image))
{
if (copyTexture(image) && generateMipLevels)
if (copyTexture(image))
{
// create mip maps.
#ifdef _IRR_USE_D3DXFilterTexture_
// The D3DXFilterTexture function seems to get linked wrong when
// compiling with both D3D8 and 9, causing it not to work in the D3D9 device.
// So mipmapgeneration is replaced with my own bad generation
HRESULT hr = D3DXFilterTexture(Texture, NULL, D3DX_DEFAULT, D3DX_DEFAULT);
if (FAILED(hr))
os::Printer::log("Could not create direct3d mip map levels.", ELL_WARNING);
else
HasMipMaps = true;
#else
createMipMaps();
HasMipMaps = true;
#endif
regenerateMipMapLevels(mipmapData);
}
}
else
......@@ -188,8 +175,8 @@ bool CD3D9Texture::createMipMaps(u32 level)
Texture->GenerateMipSubLevels();
return true;
}
// os::Printer::log("manual mipmap");
// manual mipmap generation
IDirect3DSurface9* upperSurface = 0;
IDirect3DSurface9* lowerSurface = 0;
......@@ -396,30 +383,30 @@ bool CD3D9Texture::copyTexture(IImage * image)
//! lock function
void* CD3D9Texture::lock(bool readOnly)
void* CD3D9Texture::lock(bool readOnly, u32 mipmapLevel)
{
if (!Texture)
return 0;
MipLevelLocked=mipmapLevel;
HRESULT hr;
D3DLOCKED_RECT rect;
if(!IsRenderTarget)
{
hr = Texture->LockRect(0, &rect, 0, readOnly?D3DLOCK_READONLY:0);
hr = Texture->LockRect(mipmapLevel, &rect, 0, readOnly?D3DLOCK_READONLY:0);
if (FAILED(hr))
{
os::Printer::log("Could not lock DIRECT3D9 Texture.", ELL_ERROR);
return 0;
}
return rect.pBits;
}
else
{
D3DSURFACE_DESC desc;
Texture->GetLevelDesc(0, &desc);
if (!RTTSurface)
{
// Make RTT surface large enough for all miplevels (including 0)
D3DSURFACE_DESC desc;
Texture->GetLevelDesc(0, &desc);
hr = Device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &RTTSurface, 0);
if (FAILED(hr))
{
......@@ -429,7 +416,7 @@ void* CD3D9Texture::lock(bool readOnly)
}
IDirect3DSurface9 *surface = 0;
hr = Texture->GetSurfaceLevel(0, &surface);
hr = Texture->GetSurfaceLevel(mipmapLevel, &surface);
if (FAILED(hr))
{
os::Printer::log("Could not lock DIRECT3D9 Texture", "Could not get surface.", ELL_ERROR);
......@@ -448,8 +435,8 @@ void* CD3D9Texture::lock(bool readOnly)
os::Printer::log("Could not lock DIRECT3D9 Texture", "LockRect failed.", ELL_ERROR);
return 0;
}
return rect.pBits;
}
return rect.pBits;
}
......@@ -460,7 +447,7 @@ void CD3D9Texture::unlock()
return;
if (!IsRenderTarget)
Texture->UnlockRect(0);
Texture->UnlockRect(MipLevelLocked);
else if (RTTSurface)
RTTSurface->UnlockRect();
}
......@@ -602,10 +589,58 @@ void CD3D9Texture::copy32BitMipMap(char* src, char* tgt,
//! Regenerates the mip map levels of the texture. Useful after locking and
//! modifying the texture
void CD3D9Texture::regenerateMipMapLevels()
void CD3D9Texture::regenerateMipMapLevels(void* mipmapData)
{
if (HasMipMaps)
if (mipmapData)
{
core::dimension2du size = TextureSize;
u32 level=0;
do
{
if (size.Width>1)
size.Width /=2;
if (size.Height>1)
size.Height /=2;
++level;
IDirect3DSurface9* mipSurface = 0;
HRESULT hr = Texture->GetSurfaceLevel(level, &mipSurface);
if (FAILED(hr) || !mipSurface)
{
os::Printer::log("Could not get mipmap level", ELL_WARNING);
return;
}
D3DSURFACE_DESC mipDesc;
mipSurface->GetDesc(&mipDesc);
D3DLOCKED_RECT miplr;
// lock mipmap surface
if (FAILED(mipSurface->LockRect(&miplr, NULL, 0)))
{
mipSurface->Release();
os::Printer::log("Could not lock texture", ELL_WARNING);
return;
}
memcpy(miplr.pBits, mipmapData, size.getArea()*getPitch()/TextureSize.Width);
mipmapData = (u8*)mipmapData+size.getArea()*getPitch()/TextureSize.Width;
// unlock
mipSurface->UnlockRect();
// release
mipSurface->Release();
} while (size.Width != 1 || size.Height != 1);
}
else if (HasMipMaps)
{
// create mip maps.
#ifdef _IRR_USE_D3DXFilterTexture_
// The D3DXFilterTexture function seems to get linked wrong when
// compiling with both D3D8 and 9, causing it not to work in the D3D9 device.
// So mipmapgeneration is replaced with my own bad generation
HRESULT hr = D3DXFilterTexture(Texture, NULL, D3DX_DEFAULT, D3DX_DEFAULT);
if (FAILED(hr))
#endif
createMipMaps();
}
}
......@@ -662,5 +697,3 @@ void CD3D9Texture::setPitch(D3DFORMAT d3dformat)
} // end namespace irr
#endif // _IRR_COMPILE_WITH_DIRECT3D_9_
......@@ -29,7 +29,7 @@ public:
//! constructor
CD3D9Texture(IImage* image, CD3D9Driver* driver,
u32 flags, const io::path& name);
u32 flags, const io::path& name, void* mipmapData=0);
//! rendertarget constructor
CD3D9Texture(CD3D9Driver* driver, const core::dimension2d<u32>& size, const io::path& name,
......@@ -39,7 +39,7 @@ public:
virtual ~CD3D9Texture();
//! lock function
virtual void* lock(bool readOnly = false);
virtual void* lock(bool readOnly = false, u32 mipmapLevel=0);
//! unlock function
virtual void unlock();
......@@ -67,7 +67,7 @@ public:
//! Regenerates the mip map levels of the texture. Useful after locking and
//! modifying the texture
virtual void regenerateMipMapLevels();
virtual void regenerateMipMapLevels(void* mipmapData=0);
//! returns if it is a render target
virtual bool isRenderTarget() const;
......@@ -108,6 +108,7 @@ private:
core::dimension2d<u32> TextureSize;
core::dimension2d<u32> ImageSize;
s32 Pitch;
u32 MipLevelLocked;
ECOLOR_FORMAT ColorFormat;
bool HasMipMaps;
......
......@@ -486,12 +486,12 @@ video::ITexture* CNullDriver::findTexture(const io::path& filename)
//! Creates a texture from a loaded IImage.
ITexture* CNullDriver::addTexture(const io::path& name, IImage* image)
ITexture* CNullDriver::addTexture(const io::path& name, IImage* image, void* mipmapData)
{
if ( 0 == name.size() || !image)
return 0;
ITexture* t = createDeviceDependentTexture(image, name);
ITexture* t = createDeviceDependentTexture(image, name, mipmapData);
if (t)
{
addTexture(t);
......@@ -529,7 +529,7 @@ ITexture* CNullDriver::addTexture(const core::dimension2d<u32>& size,
//! returns a device dependent texture from a software surface (IImage)
//! THIS METHOD HAS TO BE OVERRIDDEN BY DERIVED DRIVERS WITH OWN TEXTURES
ITexture* CNullDriver::createDeviceDependentTexture(IImage* surface, const io::path& name)
ITexture* CNullDriver::createDeviceDependentTexture(IImage* surface, const io::path& name, void* mipmapData)
{
return new SDummyTexture(name);
}
......
......@@ -585,11 +585,11 @@ namespace video
void addTexture(video::ITexture* surface);
//! Creates a texture from a loaded IImage.
virtual ITexture* addTexture(const io::path& name, IImage* image);
virtual ITexture* addTexture(const io::path& name, IImage* image, void* mipmapData=0);
//! returns a device dependent texture from a software surface (IImage)
//! THIS METHOD HAS TO BE OVERRIDDEN BY DERIVED DRIVERS WITH OWN TEXTURES
virtual video::ITexture* createDeviceDependentTexture(IImage* surface, const io::path& name);
virtual video::ITexture* createDeviceDependentTexture(IImage* surface, const io::path& name, void* mipmapData=0);
//! checks triangle count and print warning if wrong
bool checkPrimitiveCount(u32 prmcnt) const;
......@@ -640,14 +640,14 @@ namespace video
{
SDummyTexture(const io::path& name) : ITexture(name), size(0,0) {};
virtual void* lock(bool readOnly = false) { return 0; };
virtual void* lock(bool readOnly = false, u32 mipmapLevel=0) { return 0; };
virtual void unlock(){}
virtual const core::dimension2d<u32>& getOriginalSize() const { return size; }
virtual const core::dimension2d<u32>& getSize() const { return size; }
virtual E_DRIVER_TYPE getDriverType() const { return video::EDT_NULL; }
virtual ECOLOR_FORMAT getColorFormat() const { return video::ECF_A1R5G5B5; };
virtual u32 getPitch() const { return 0; }
virtual void regenerateMipMapLevels() {};
virtual void regenerateMipMapLevels(void* mipmapData=0) {};
core::dimension2d<u32> size;
};
......
......@@ -2011,9 +2011,9 @@ inline void COpenGLDriver::createGLTextureMatrix(GLfloat *o, const core::matrix4
//! returns a device dependent texture from a software surface (IImage)
video::ITexture* COpenGLDriver::createDeviceDependentTexture(IImage* surface, const io::path& name)
video::ITexture* COpenGLDriver::createDeviceDependentTexture(IImage* surface, const io::path& name, void* mipmapData)
{
return new COpenGLTexture(surface, name, this);
return new COpenGLTexture(surface, name, mipmapData, this);
}
......
......@@ -338,7 +338,7 @@ namespace video
//! inits the parts of the open gl driver used on all platforms
bool genericDriverInit(const core::dimension2d<u32>& screenSize, bool stencilBuffer);
//! returns a device dependent texture from a software surface (IImage)
virtual video::ITexture* createDeviceDependentTexture(IImage* surface, const io::path& name);
virtual video::ITexture* createDeviceDependentTexture(IImage* surface, const io::path& name, void* mipmapData);
//! creates a transposed matrix in supplied GLfloat array to pass to OpenGL
inline void createGLMatrix(GLfloat gl_matrix[16], const core::matrix4& m);
......
......@@ -21,8 +21,8 @@ namespace video
{
//! constructor for usual textures
COpenGLTexture::COpenGLTexture(IImage* origImage, const io::path& name, COpenGLDriver* driver)
: ITexture(name), ColorFormat(ECF_A8R8G8B8), Driver(driver), Image(0),
COpenGLTexture::COpenGLTexture(IImage* origImage, const io::path& name, void* mipmapData, COpenGLDriver* driver)
: ITexture(name), ColorFormat(ECF_A8R8G8B8), Driver(driver), Image(0), MipImage(0),
TextureName(0), InternalFormat(GL_RGBA), PixelFormat(GL_BGRA_EXT),
PixelType(GL_UNSIGNED_BYTE),
IsRenderTarget(false), AutomaticMipmapUpdate(false),
......@@ -33,7 +33,7 @@ COpenGLTexture::COpenGLTexture(IImage* origImage, const io::path& name, COpenGLD
#endif
HasMipMaps = Driver->getTextureCreationFlag(ETCF_CREATE_MIP_MAPS);
getImageData(origImage);
getImageValues(origImage);
glGenTextures(1, &TextureName);
......@@ -48,7 +48,7 @@ COpenGLTexture::COpenGLTexture(IImage* origImage, const io::path& name, COpenGLD
// scale texture
origImage->copyToScaling(Image);
}
copyTexture();
uploadTexture(true, mipmapData);
if (!KeepImage)
{
Image->drop();
......@@ -56,9 +56,10 @@ COpenGLTexture::COpenGLTexture(IImage* origImage, const io::path& name, COpenGLD
}
}
//! constructor for basic setup (only for derived classes)
COpenGLTexture::COpenGLTexture(const io::path& name, COpenGLDriver* driver)
: ITexture(name), ColorFormat(ECF_A8R8G8B8), Driver(driver), Image(0),
: ITexture(name), ColorFormat(ECF_A8R8G8B8), Driver(driver), Image(0), MipImage(0),
TextureName(0), InternalFormat(GL_RGBA), PixelFormat(GL_BGRA_EXT),
PixelType(GL_UNSIGNED_BYTE),
HasMipMaps(true), IsRenderTarget(false), AutomaticMipmapUpdate(false),
......@@ -80,6 +81,7 @@ COpenGLTexture::~COpenGLTexture()
}
//! Choose best matching color format, based on texture creation flags
ECOLOR_FORMAT COpenGLTexture::getBestColorFormat(ECOLOR_FORMAT format)
{
ECOLOR_FORMAT destFormat = ECF_A8R8G8B8;
......@@ -123,6 +125,7 @@ ECOLOR_FORMAT COpenGLTexture::getBestColorFormat(ECOLOR_FORMAT format)
}
//! Get opengl values for the GPU texture storage
GLint COpenGLTexture::getOpenGLFormatAndParametersFromColorFormat(ECOLOR_FORMAT format,
GLint& filtering,
GLenum& colorformat,
......@@ -234,7 +237,8 @@ GLint COpenGLTexture::getOpenGLFormatAndParametersFromColorFormat(ECOLOR_FORMAT
}
void COpenGLTexture::getImageData(IImage* image)
// prepare values ImageSize, TextureSize, and ColorFormat based on image
void COpenGLTexture::getImageValues(IImage* image)
{
if (!image)
{
......@@ -268,25 +272,35 @@ void COpenGLTexture::getImageData(IImage* image)
//! copies the the texture into an open gl texture.
void COpenGLTexture::copyTexture(bool newTexture)
void COpenGLTexture::uploadTexture(bool newTexture, void* mipmapData, u32 level)
{
if (!Image)
// check which image needs to be uploaded
IImage* image = level?MipImage:Image;
if (!image)
{
os::Printer::log("No image for OpenGL texture to upload", ELL_ERROR);
return;
}
// get correct opengl color data values
GLenum oldInternalFormat = InternalFormat;
GLint filtering;
InternalFormat = getOpenGLFormatAndParametersFromColorFormat(ColorFormat, filtering, PixelFormat, PixelType);
// make sure we don't change the internal format of existing images
if (!newTexture)
InternalFormat=oldInternalFormat;
Driver->setActiveTexture(0, this);
if (Driver->testGLError())
os::Printer::log("Could not bind Texture", ELL_ERROR);
if (newTexture)
// mipmap handling for main texture
if (!level && newTexture)
{
#ifndef DISABLE_MIPMAPPING
#ifdef GL_SGIS_generate_mipmap
if (HasMipMaps && Driver->queryFeature(EVDF_MIP_MAP_AUTO_UPDATE))
// auto generate if possible and no mipmap data is given
if (HasMipMaps && !mipmapData && Driver->queryFeature(EVDF_MIP_MAP_AUTO_UPDATE))
{
if (Driver->getTextureCreationFlag(ETCF_OPTIMIZED_FOR_SPEED))
glHint(GL_GENERATE_MIPMAP_HINT_SGIS, GL_FASTEST);
......@@ -301,8 +315,10 @@ void COpenGLTexture::copyTexture(bool newTexture)
else
#endif
{
// Either generate manually due to missing capability
// or use predefined mipmap data
AutomaticMipmapUpdate=false;
regenerateMipMapLevels();
regenerateMipMapLevels(mipmapData);
}
if (HasMipMaps) // might have changed in regenerateMipMapLevels
{
......@@ -311,10 +327,10 @@ void COpenGLTexture::copyTexture(bool newTexture)
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}
else
#else
#else
HasMipMaps=false;
os::Printer::log("Did not create OpenGL texture mip maps.", ELL_ERROR);
#endif
os::Printer::log("Did not create OpenGL texture mip maps.", ELL_INFORMATION);
#endif
{
// enable bilinear filter without mipmaps
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
......@@ -322,14 +338,15 @@ void COpenGLTexture::copyTexture(bool newTexture)
}
}
void* source = Image->lock();
// now get image data and upload to GPU
void* source = image->lock();
if (newTexture)
glTexImage2D(GL_TEXTURE_2D, 0, InternalFormat, Image->getDimension().Width,
Image->getDimension().Height, 0, PixelFormat, PixelType, source);
glTexImage2D(GL_TEXTURE_2D, level, InternalFormat, image->getDimension().Width,
image->getDimension().Height, 0, PixelFormat, PixelType, source);
else
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, Image->getDimension().Width,
Image->getDimension().Height, PixelFormat, PixelType, source);
Image->unlock();
glTexSubImage2D(GL_TEXTURE_2D, level, 0, 0, image->getDimension().Width,
image->getDimension().Height, PixelFormat, PixelType, source);
image->unlock();
if (Driver->testGLError())
os::Printer::log("Could not glTexImage2D", ELL_ERROR);
......@@ -337,24 +354,47 @@ void COpenGLTexture::copyTexture(bool newTexture)
//! lock function
void* COpenGLTexture::lock(bool readOnly)
void* COpenGLTexture::lock(bool readOnly, u32 mipmapLevel)
{
// store info about which image is locked
IImage* image = (mipmapLevel==0)?Image:MipImage;
ReadOnlyLock |= readOnly;
MipLevelStored = mipmapLevel;
if (!Image || IsRenderTarget)
// if data not available or might have changed on GPU download it
if (!image || IsRenderTarget)
{
// prepare the data storage if necessary
if (!Image)
Image = new CImage(ECF_A8R8G8B8, ImageSize);
if (!Image)
if (!image)
{
if (mipmapLevel)
{
u32 i=0;
u32 width = TextureSize.Width;
u32 height = TextureSize.Height;
do
{
if (width>1)
width>>=1;
if (height>1)
height>>=1;
++i;
}
while (i != mipmapLevel);
image = new CImage(ECF_A8R8G8B8, core::dimension2du(width,height));
}
else
image = new CImage(ECF_A8R8G8B8, ImageSize);
ColorFormat = ECF_A8R8G8B8;
}
if (!image)
return 0;
u8* pPixels = static_cast<u8*>(Image->lock());
if (!pPixels)
{
u8* pixels = static_cast<u8*>(image->lock());
if (!pixels)
return 0;
}
// we need to keep the correct texture bound...
// we need to keep the correct texture bound later on
GLint tmpTexture;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &tmpTexture);
glBindTexture(GL_TEXTURE_2D, TextureName);
......@@ -365,7 +405,8 @@ void* COpenGLTexture::lock(bool readOnly)
glPixelStorei(GL_PACK_INVERT_MESA, GL_TRUE);
#endif
glGetTexImage(GL_TEXTURE_2D, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, pPixels);
// download GPU data as ARGB8 to pixels;
glGetTexImage(GL_TEXTURE_2D, mipmapLevel, GL_BGRA_EXT, GL_UNSIGNED_BYTE, pixels);
#ifdef GL_MESA_pack_invert
if (Driver->queryOpenGLFeature(COpenGLExtensionHandler::IRR_MESA_pack_invert))
......@@ -374,42 +415,57 @@ void* COpenGLTexture::lock(bool readOnly)
#endif
{
// opengl images are horizontally flipped, so we have to fix that here.
const s32 pitch=Image->getPitch();
u8* p2 = pPixels + (ImageSize.Height - 1) * pitch;
const s32 pitch=image->getPitch();
u8* p2 = pixels + (image->getDimension().Height - 1) * pitch;
u8* tmpBuffer = new u8[pitch];
for (u32 i=0; i < ImageSize.Height; i += 2)
for (u32 i=0; i < image->getDimension().Height; i += 2)
{
memcpy(tmpBuffer, pPixels, pitch);
memcpy(pPixels, p2, pitch);
memcpy(tmpBuffer, pixels, pitch);
memcpy(pixels, p2, pitch);
memcpy(p2, tmpBuffer, pitch);
pPixels += pitch;
pixels += pitch;
p2 -= pitch;
}
delete [] tmpBuffer;
}
Image->unlock();
image->unlock();
//reset old bound texture
glBindTexture(GL_TEXTURE_2D, tmpTexture);
}
return Image->lock();
return image->lock();
}
//! unlock function
void COpenGLTexture::unlock()
{
if (!Image)
// test if miplevel or main texture was locked
IImage* image = MipImage?MipImage:Image;
if (!image)
return;
Image->unlock();
// unlock image to see changes
image->unlock();
// copy texture data to GPU
if (!ReadOnlyLock)
copyTexture(false);
uploadTexture(false, 0, MipLevelStored);
ReadOnlyLock = false;
if (!KeepImage)
// cleanup local image
if (MipImage)
{
MipImage->drop();
MipImage=0;
}
else if (!KeepImage)
{
Image->drop();
Image=0;
}
// update information
if (Image)
ColorFormat=Image->getColorFormat();
else
ColorFormat=ECF_A8R8G8B8;
}
......@@ -459,7 +515,6 @@ GLuint COpenGLTexture::getOpenGLTextureName() const
//! Returns whether this texture has mipmaps
//! return true if texture has mipmaps
bool COpenGLTexture::hasMipMaps() const
{
return HasMipMaps;
......@@ -468,18 +523,18 @@ bool COpenGLTexture::hasMipMaps() const
//! Regenerates the mip map levels of the texture. Useful after locking and
//! modifying the texture
void COpenGLTexture::regenerateMipMapLevels()
void COpenGLTexture::regenerateMipMapLevels(void* mipmapData)
{
if (AutomaticMipmapUpdate || !HasMipMaps || !Image)
return;
if ((Image->getDimension().Width==1) && (Image->getDimension().Height==1))
return;
// Manually create mipmaps
// Manually create mipmaps or use prepared version
u32 width=Image->getDimension().Width;
u32 height=Image->getDimension().Height;
u32 i=0;
u8* target = new u8[Image->getImageDataSizeInBytes()];
u8* target = static_cast<u8*>(mipmapData);
do
{
if (width>1)
......@@ -487,13 +542,24 @@ void COpenGLTexture::regenerateMipMapLevels()
if (height>1)
height>>=1;
++i;
Image->copyToScaling(target, width, height, Image->getColorFormat());
if (!target)
target = new u8[width*height*Image->getBytesPerPixel()];
// create scaled version if no mipdata available
if (!mipmapData)
Image->copyToScaling(target, width, height, Image->getColorFormat());
glTexImage2D(GL_TEXTURE_2D, i, InternalFormat, width, height,
0, PixelFormat, PixelType, target);
// get next prepared mipmap data if available
if (mipmapData)
{
mipmapData = static_cast<u8*>(mipmapData)+width*height*Image->getBytesPerPixel();
target = static_cast<u8*>(mipmapData);
}
}
while (width!=1 || height!=1);
delete [] target;
Image->unlock();
// cleanup
if (!mipmapData)
delete [] target;
}
......
......@@ -51,13 +51,13 @@ class COpenGLTexture : public ITexture
public:
//! constructor
COpenGLTexture(IImage* surface, const io::path& name, COpenGLDriver* driver=0);
COpenGLTexture(IImage* surface, const io::path& name, void* mipmapData=0, COpenGLDriver* driver=0);
//! destructor
virtual ~COpenGLTexture();
//! lock function
virtual void* lock(bool readOnly = false);
virtual void* lock(bool readOnly=false, u32 mipmapLevel=0);
//! unlock function
virtual void unlock();
......@@ -83,9 +83,10 @@ public:
//! return whether this texture has mipmaps
virtual bool hasMipMaps() const;
//! Regenerates the mip map levels of the texture. Useful after
//! locking and modifying the texture
virtual void regenerateMipMapLevels();
//! Regenerates the mip map levels of the texture.
/** Useful after locking and modifying the texture
\param mipmapData Pointer to raw mipmap data, including all necessary mip levels, in the same format as the main texture image. If not set the mipmaps are derived from the main image. */
virtual void regenerateMipMapLevels(void* mipmapData=0);
//! Is it a render target?
virtual bool isRenderTarget() const;
......@@ -114,24 +115,28 @@ protected:
GLint getOpenGLFormatAndParametersFromColorFormat(
ECOLOR_FORMAT format, GLint& filtering, GLenum& colorformat, GLenum& type);
//! convert the image into an internal image with better properties for this driver.
void getImageData(IImage* image);
//! get important numbers of the image and hw texture
void getImageValues(IImage* image);
//! copies the texture into an OpenGL texture.
//! \param: newTexture is true if method is called from a newly created texture for the first time. Otherwise call with false to improve memory handling.
void copyTexture(bool newTexture=true);
/** \param newTexture True if method is called for a newly created texture for the first time. Otherwise call with false to improve memory handling.
\param mipmapData Pointer to raw mipmap data, including all necessary mip levels, in the same format as the main texture image.
\param mipLevel If set to non-zero, only that specific miplevel is updated, using the MipImage member. */
void uploadTexture(bool newTexture=false, void* mipmapData=0, u32 mipLevel=0);
core::dimension2d<u32> ImageSize;
core::dimension2d<u32> TextureSize;
ECOLOR_FORMAT ColorFormat;
COpenGLDriver* Driver;
IImage* Image;
IImage* MipImage;
GLuint TextureName;
GLint InternalFormat;
GLenum PixelFormat;
GLenum PixelType;
u8 MipLevelStored;
bool HasMipMaps;
bool IsRenderTarget;
bool AutomaticMipmapUpdate;
......
......@@ -241,9 +241,9 @@ bool CSoftwareDriver::endScene()
//! returns a device dependent texture from a software surface (IImage)
//! THIS METHOD HAS TO BE OVERRIDDEN BY DERIVED DRIVERS WITH OWN TEXTURES
ITexture* CSoftwareDriver::createDeviceDependentTexture(IImage* surface, const io::path& name)
ITexture* CSoftwareDriver::createDeviceDependentTexture(IImage* surface, const io::path& name, void* mipmapData)
{
return new CSoftwareTexture(surface, name);
return new CSoftwareTexture(surface, name, false, mipmapData);
}
......
......@@ -101,7 +101,7 @@ namespace video
//! returns a device dependent texture from a software surface (IImage)
//! THIS METHOD HAS TO BE OVERRIDDEN BY DERIVED DRIVERS WITH OWN TEXTURES
virtual video::ITexture* createDeviceDependentTexture(IImage* surface, const io::path& name);
virtual video::ITexture* createDeviceDependentTexture(IImage* surface, const io::path& name, void* mipmapData=0);
//! Creates a render target texture.
virtual ITexture* addRenderTargetTexture(const core::dimension2d<u32>& size,
......
......@@ -2062,13 +2062,12 @@ IImage* CBurningVideoDriver::createScreenShot()
//! returns a device dependent texture from a software surface (IImage)
//! THIS METHOD HAS TO BE OVERRIDDEN BY DERIVED DRIVERS WITH OWN TEXTURES
ITexture* CBurningVideoDriver::createDeviceDependentTexture(IImage* surface, const io::path& name)
ITexture* CBurningVideoDriver::createDeviceDependentTexture(IImage* surface, const io::path& name, void* mipmapData)
{
return new CSoftwareTexture2(
surface, name,
(getTextureCreationFlag(ETCF_CREATE_MIP_MAPS) ? CSoftwareTexture2::GEN_MIPMAP : 0 ) |
(getTextureCreationFlag(ETCF_ALLOW_NON_POWER_2) ? 0 : CSoftwareTexture2::NP2_SIZE )
);
(getTextureCreationFlag(ETCF_ALLOW_NON_POWER_2) ? 0 : CSoftwareTexture2::NP2_SIZE ), mipmapData);
}
......
......@@ -168,7 +168,7 @@ namespace video
//! returns a device dependent texture from a software surface (IImage)
//! THIS METHOD HAS TO BE OVERRIDDEN BY DERIVED DRIVERS WITH OWN TEXTURES
virtual video::ITexture* createDeviceDependentTexture(IImage* surface, const io::path& name);
virtual video::ITexture* createDeviceDependentTexture(IImage* surface, const io::path& name, void* mipmapData=0);
video::CImage* BackBuffer;
video::IImagePresenter* Presenter;
......
......@@ -14,7 +14,8 @@ namespace video
{
//! constructor
CSoftwareTexture::CSoftwareTexture(IImage* image, const io::path& name, bool renderTarget)
CSoftwareTexture::CSoftwareTexture(IImage* image, const io::path& name,
bool renderTarget, void* mipmapData)
: ITexture(name), Texture(0), IsRenderTarget(renderTarget)
{
#ifdef _DEBUG
......@@ -57,7 +58,7 @@ CSoftwareTexture::~CSoftwareTexture()
//! lock function
void* CSoftwareTexture::lock(bool readOnly)
void* CSoftwareTexture::lock(bool readOnly, u32 mipmapLevel)
{
return Image->lock();
}
......@@ -132,7 +133,7 @@ u32 CSoftwareTexture::getPitch() const
//! Regenerates the mip map levels of the texture. Useful after locking and
//! modifying the texture
void CSoftwareTexture::regenerateMipMapLevels()
void CSoftwareTexture::regenerateMipMapLevels(void* mipmapData)
{
// our software textures don't have mip maps
}
......
......@@ -21,13 +21,14 @@ class CSoftwareTexture : public ITexture
public:
//! constructor
CSoftwareTexture(IImage* surface, const io::path& name, bool renderTarget=false);
CSoftwareTexture(IImage* surface, const io::path& name,
bool renderTarget=false, void* mipmapData=0);
//! destructor
virtual ~CSoftwareTexture();
//! lock function
virtual void* lock(bool readOnly = false);
virtual void* lock(bool readOnly = false, u32 mipmapLevel=0);
//! unlock function
virtual void unlock();
......@@ -55,7 +56,7 @@ public:
//! Regenerates the mip map levels of the texture. Useful after locking and
//! modifying the texture
virtual void regenerateMipMapLevels();
virtual void regenerateMipMapLevels(void* mipmapData=0);
//! is it a render target?
virtual bool isRenderTarget() const;
......
......@@ -16,8 +16,9 @@ namespace video
{
//! constructor
CSoftwareTexture2::CSoftwareTexture2(IImage* image, const io::path& name, u32 flags )
: ITexture(name), MipMapLOD(0), Flags ( flags )
CSoftwareTexture2::CSoftwareTexture2(IImage* image, const io::path& name,
u32 flags, void* mipmapData)
: ITexture(name), MipMapLOD(0), Flags ( flags ), OriginalFormat(video::ECF_UNKNOWN)
{
#ifdef _DEBUG
setDebugName("CSoftwareTexture2");
......@@ -32,6 +33,7 @@ CSoftwareTexture2::CSoftwareTexture2(IImage* image, const io::path& name, u32 fl
if (image)
{
OrigSize = image->getDimension();
OriginalFormat = image->getColorFormat();
core::setbit_cond(Flags,
image->getColorFormat () == video::ECF_A8R8G8B8 ||
......@@ -66,8 +68,7 @@ CSoftwareTexture2::CSoftwareTexture2(IImage* image, const io::path& name, u32 fl
}
}
regenerateMipMapLevels();
setCurrentMipMapLOD(0);
regenerateMipMapLevels(mipmapData);
}
......@@ -84,7 +85,7 @@ CSoftwareTexture2::~CSoftwareTexture2()
//! Regenerates the mip map levels of the texture. Useful after locking and
//! modifying the texture
void CSoftwareTexture2::regenerateMipMapLevels()
void CSoftwareTexture2::regenerateMipMapLevels(void* mipmapData)
{
if ( !hasMipMaps () )
return;
......@@ -99,21 +100,48 @@ void CSoftwareTexture2::regenerateMipMapLevels()
}
core::dimension2d<u32> newSize;
core::dimension2d<u32> currentSize;
core::dimension2d<u32> origSize=OrigSize;
i = 1;
CImage * c = MipMap[0];
while ( i < SOFTWARE_DRIVER_2_MIPMAPPING_MAX )
for (i=1; i < SOFTWARE_DRIVER_2_MIPMAPPING_MAX; ++i)
{
currentSize = c->getDimension();
newSize.Width = core::s32_max ( 1, currentSize.Width >> SOFTWARE_DRIVER_2_MIPMAPPING_SCALE );
newSize.Height = core::s32_max ( 1, currentSize.Height >> SOFTWARE_DRIVER_2_MIPMAPPING_SCALE );
MipMap[i] = new CImage(BURNINGSHADER_COLOR_FORMAT, newSize);
MipMap[i]->fill ( 0 );
MipMap[0]->copyToScalingBoxFilter( MipMap[i], 0, false );
c = MipMap[i];
++i;
newSize = MipMap[i-1]->getDimension();
newSize.Width = core::s32_max ( 1, newSize.Width >> SOFTWARE_DRIVER_2_MIPMAPPING_SCALE );
newSize.Height = core::s32_max ( 1, newSize.Height >> SOFTWARE_DRIVER_2_MIPMAPPING_SCALE );
origSize.Width = core::s32_max(1, origSize.Width >> 1);
origSize.Height = core::s32_max(1, origSize.Height >> 1);
if (mipmapData)
{
if (OriginalFormat != BURNINGSHADER_COLOR_FORMAT)
{
IImage* tmpImage = new CImage(OriginalFormat, origSize, mipmapData, true, false);
MipMap[i] = new CImage(BURNINGSHADER_COLOR_FORMAT, newSize);
if (origSize==newSize)
tmpImage->copyTo(MipMap[i]);
else
tmpImage->copyToScalingBoxFilter(MipMap[i]);
tmpImage->drop();
}
else
{
if (origSize==newSize)
MipMap[i] = new CImage(BURNINGSHADER_COLOR_FORMAT, newSize, mipmapData, false);
else
{
MipMap[i] = new CImage(BURNINGSHADER_COLOR_FORMAT, newSize);
IImage* tmpImage = new CImage(BURNINGSHADER_COLOR_FORMAT, origSize, mipmapData, true, false);
tmpImage->copyToScalingBoxFilter(MipMap[i]);
tmpImage->drop();
}
}
mipmapData = (u8*)mipmapData+origSize.getArea()*IImage::getBitsPerPixelFromFormat(OriginalFormat)/8;
}
else
{
MipMap[i] = new CImage(BURNINGSHADER_COLOR_FORMAT, newSize);
MipMap[i]->fill ( 0 );
MipMap[0]->copyToScalingBoxFilter( MipMap[i], 0, false );
}
}
}
......@@ -122,4 +150,3 @@ void CSoftwareTexture2::regenerateMipMapLevels()
} // end namespace irr
#endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_
......@@ -25,19 +25,21 @@ public:
//! constructor
enum eTex2Flags
{
GEN_MIPMAP = 1,
GEN_MIPMAP = 1,
IS_RENDERTARGET = 2,
NP2_SIZE = 4,
HAS_ALPHA = 8
NP2_SIZE = 4,
HAS_ALPHA = 8
};
CSoftwareTexture2( IImage* surface, const io::path& name, u32 flags );
CSoftwareTexture2(IImage* surface, const io::path& name, u32 flags, void* mipmapData=0);
//! destructor
virtual ~CSoftwareTexture2();
//! lock function
virtual void* lock(bool readOnly = false)
virtual void* lock(bool readOnly = false, u32 mipmapLevel=0)
{
if (Flags & GEN_MIPMAP)
MipMapLOD=mipmapLevel;
return MipMap[MipMapLOD]->lock();
}
......@@ -99,14 +101,7 @@ public:
//! Regenerates the mip map levels of the texture. Useful after locking and
//! modifying the texture
virtual void regenerateMipMapLevels();
//! Select a Mipmap Level
virtual void setCurrentMipMapLOD ( s32 lod )
{
if ( Flags & GEN_MIPMAP )
MipMapLOD = lod;
}
virtual void regenerateMipMapLevels(void* mipmapData=0);
//! support mipmaps
virtual bool hasMipMaps() const
......@@ -131,8 +126,9 @@ private:
CImage * MipMap[SOFTWARE_DRIVER_2_MIPMAPPING_MAX];
s32 MipMapLOD;
u32 MipMapLOD;
u32 Flags;
ECOLOR_FORMAT OriginalFormat;
};
......
......@@ -10,11 +10,10 @@
namespace irr
{
namespace video
{
const tFixPointu IBurningShader::dithermask[ 4 * 4] =
const tFixPointu IBurningShader::dithermask[] =
{
0x00,0x80,0x20,0xa0,
0xc0,0x40,0xe0,0x60,
......@@ -23,7 +22,7 @@ namespace video
};
IBurningShader::IBurningShader(IDepthBuffer* zbuffer)
:RenderTarget(0),DepthBuffer(zbuffer)
: RenderTarget(0),DepthBuffer(zbuffer)
{
#ifdef _DEBUG
setDebugName("IBurningShader");
......@@ -70,7 +69,6 @@ namespace video
//(tVideoSample*)RenderTarget->lock() = (tVideoSample*)RenderTarget->lock();
//(fp24*) DepthBuffer->lock() = DepthBuffer->lock();
}
}
......@@ -91,9 +89,8 @@ namespace video
// select mignify and magnify ( lodLevel )
//SOFTWARE_DRIVER_2_MIPMAPPING_LOD_BIAS
it->lodLevel = lodLevel;
it->Texture->setCurrentMipMapLOD (
core::s32_clamp ( lodLevel + SOFTWARE_DRIVER_2_MIPMAPPING_LOD_BIAS, 0, SOFTWARE_DRIVER_2_MIPMAPPING_MAX - 1 )
);
it->data = (tVideoSample*) it->Texture->lock(true,
core::s32_clamp ( lodLevel + SOFTWARE_DRIVER_2_MIPMAPPING_LOD_BIAS, 0, SOFTWARE_DRIVER_2_MIPMAPPING_MAX - 1 ));
// prepare for optimal fixpoint
it->pitchlog2 = s32_log2_s32 ( it->Texture->getPitch() );
......@@ -101,12 +98,10 @@ namespace video
const core::dimension2d<u32> &dim = it->Texture->getSize();
it->textureXMask = s32_to_fixPoint ( dim.Width - 1 ) & FIX_POINT_UNSIGNED_MASK;
it->textureYMask = s32_to_fixPoint ( dim.Height - 1 ) & FIX_POINT_UNSIGNED_MASK;
it->data = (tVideoSample*) it->Texture->lock();
}
}
} // end namespace video
} // end namespace irr
......
......@@ -9,34 +9,34 @@ bool testArchive(IFileSystem* fs, const io::path& archiveName)
// make sure there is no archive mounted
if ( fs->getFileArchiveCount() )
{
logTestString("Already mounted archives found");
logTestString("Already mounted archives found\n");
return false;
}
if ( !fs->addFileArchive(archiveName, /*bool ignoreCase=*/true, /*bool ignorePaths=*/false) )
{
logTestString("Mounting archive failed");
logTestString("Mounting archive failed\n");
return false;
}
// make sure there is an archive mounted
if ( !fs->getFileArchiveCount() )
{
logTestString("Mounted archive not in list");
logTestString("Mounted archive not in list\n");
return false;
}
// mount again
if ( !fs->addFileArchive(archiveName, /*bool ignoreCase=*/true, /*bool ignorePaths=*/false) )
{
logTestString("Mounting a second time failed");
logTestString("Mounting a second time failed\n");
return false;
}
// make sure there is exactly one archive mounted
if ( fs->getFileArchiveCount() != 1 )
{
logTestString("Duplicate mount not recognized");
logTestString("Duplicate mount not recognized\n");
return false;
}
......@@ -52,21 +52,21 @@ bool testArchive(IFileSystem* fs, const io::path& archiveName)
io::path filename("mypath/mypath/myfile.txt");
if (!fs->existFile(filename))
{
logTestString("existFile with deep path failed");
logTestString("existFile with deep path failed\n");
return false;
}
filename="test/test.txt";
if (!fs->existFile(filename))
{
logTestString("existFile failed");
logTestString("existFile failed\n");
return false;
}
IReadFile* readFile = fs->createAndOpenFile(filename);
if ( !readFile )
{
logTestString("createAndOpenFilefailed");
logTestString("createAndOpenFilefailed\n");
return false;
}
......@@ -74,7 +74,7 @@ bool testArchive(IFileSystem* fs, const io::path& archiveName)
readFile->read(tmp, 12);
if (strncmp(tmp, "Hello world!", 12))
{
logTestString("Read bad data from archive: %s", tmp);
logTestString("Read bad data from archive: %s\n", tmp);
return false;
}
if (!fs->removeFileArchive(fs->getFileArchiveCount()-1))
......
......@@ -89,6 +89,7 @@ int main(int argumentCount, char * arguments[])
TEST(guiDisabledMenu);
TEST(makeColorKeyTexture);
TEST(renderTargetTexture);
TEST(textureFeatures);
TEST(textureRenderStates);
TEST(transparentAlphaChannelRef);
// TODO: Needs to be fixed first.
......@@ -103,7 +104,7 @@ int main(int argumentCount, char * arguments[])
unsigned int fails = 0;
bool firstRun=true;
const bool spawn=true;
const bool spawn=false;
// args: [testNumber] [testCount]
if(argumentCount > 1)
{
......
......@@ -310,6 +310,10 @@
RelativePath=".\testXML.cpp"
>
</File>
<File
RelativePath=".\textureFeatures.cpp"
>
</File>
<File
RelativePath=".\textureRenderStates.cpp"
>
......
// Copyright (C) 2008-2009 Christian Stehno, Colin MacDonald
// No rights reserved: this software is in the public domain.
#include "testUtils.h"
using namespace irr;
using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;
//! Tests locking miplevels
static bool lockAllMipLevels(E_DRIVER_TYPE driverType)
{
bool result=true;
IrrlichtDevice *device = createDevice( driverType, dimension2d<u32>(160, 120), 32);
if (!device)
return result; // Treat a failure to create a driver as benign; this saves a lot of #ifdefs
IVideoDriver* driver = device->getVideoDriver();
ISceneManager * smgr = device->getSceneManager();
scene::ISceneNode* n = smgr->addCubeSceneNode();
if (n)
{
// create the texture and miplevels with distinct colors
u32 texData[16*16];
for (u32 i=0; i<16*16; ++i)
texData[i]=0xff0000ff;
video::IImage* image = driver->createImageFromData(video::ECF_A8R8G8B8, core::dimension2du(16,16), texData, false);
u32 mipdata[8*16];
u32 index=0;
for (u32 j=8; j>0; j/=2)
{
u32 val=(j==8?0x00ff00ff:(j==4?0x0000ffff:(j==2?0xc2c200ff:0x001212ff)));
for (u32 i=0; i<j; ++i)
{
for (u32 k=0; k<j; ++k)
mipdata[index++]=val;
}
}
ITexture* tex = driver->addTexture("miptest", image, mipdata);
if (!tex)
// is probably an error in the mipdata handling
return false;
else
n->setMaterialTexture(0, tex);
image->drop();
}
(void)smgr->addCameraSceneNode();
driver->beginScene(true, true, SColor(255,100,101,140));
smgr->drawAll();
driver->endScene();
video::ITexture* tex = driver->findTexture("miptest");
video::SColor* bits = (video::SColor*)tex->lock(true, 0);
result |= (bits[0].color==0xff0000ff);
tex->unlock();
bits = (video::SColor*)tex->lock(true, 1);
result |= (bits[0].color==0x00ff00ff);
tex->unlock();
bits = (video::SColor*)tex->lock(true, 2);
result |= (bits[0].color==0x0000ffff);
tex->unlock();
bits = (video::SColor*)tex->lock(true, 3);
result |= (bits[0].color==0xc2c200ff);
tex->unlock();
bits = (video::SColor*)tex->lock(true, 4);
result |= (bits[0].color==0x001212ff);
tex->unlock();
device->drop();
return result;
}
bool textureFeatures(void)
{
bool passed = true;
passed &= lockAllMipLevels(EDT_OPENGL);
passed &= lockAllMipLevels(EDT_SOFTWARE);
passed &= lockAllMipLevels(EDT_BURNINGSVIDEO);
passed &= lockAllMipLevels(EDT_DIRECT3D9);
passed &= lockAllMipLevels(EDT_DIRECT3D8);
return passed;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment