2012-05-29 13:31:11 +00:00
|
|
|
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
|
|
|
|
// Copyright (C) 2010 Winch Gate Property Limited
|
|
|
|
//
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU Affero General Public License as
|
|
|
|
// published by the Free Software Foundation, either version 3 of the
|
|
|
|
// License, or (at your option) any later version.
|
|
|
|
//
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU Affero General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU Affero General Public License
|
|
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
#include "stddirect3d.h"
|
|
|
|
|
|
|
|
#include "nel/3d/vertex_buffer.h"
|
|
|
|
#include "nel/3d/light.h"
|
|
|
|
#include "nel/3d/index_buffer.h"
|
|
|
|
#include "nel/misc/rect.h"
|
|
|
|
#include "nel/misc/di_event_emitter.h"
|
|
|
|
#include "nel/misc/mouse_device.h"
|
|
|
|
#include "nel/3d/viewport.h"
|
|
|
|
#include "nel/3d/scissor.h"
|
|
|
|
#include "nel/3d/u_driver.h"
|
|
|
|
|
|
|
|
#include "driver_direct3d.h"
|
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
using namespace NLMISC;
|
|
|
|
|
|
|
|
|
|
|
|
namespace NL3D
|
|
|
|
{
|
|
|
|
|
|
|
|
std::vector<uint8> CDriverD3D::_TempBuffer;
|
|
|
|
|
|
|
|
// ***************************************************************************
|
|
|
|
|
|
|
|
CTextureDrvInfosD3D::CTextureDrvInfosD3D(IDriver *drv, ItTexDrvInfoPtrMap it, CDriverD3D *drvD3D, bool renderTarget)
|
|
|
|
: ITextureDrvInfos(drv, it)
|
|
|
|
{
|
|
|
|
H_AUTO_D3D(CTextureDrvInfosD3D_CTextureDrvInfosD3D)
|
|
|
|
Texture = NULL;
|
|
|
|
Texture2d = NULL;
|
|
|
|
TextureCube = NULL;
|
|
|
|
TextureMemory = 0;
|
|
|
|
RenderTarget = renderTarget;
|
|
|
|
FirstMipMap = 0;
|
|
|
|
|
|
|
|
// Nb: at Driver dtor, all tex infos are deleted, so _Driver is always valid.
|
|
|
|
_Driver= drvD3D;
|
|
|
|
|
|
|
|
WrapS = D3DTADDRESS_WRAP;
|
|
|
|
WrapT = D3DTADDRESS_WRAP;
|
|
|
|
MagFilter = D3DTEXF_POINT;
|
|
|
|
MinFilter = D3DTEXF_POINT;
|
|
|
|
MipFilter = D3DTEXF_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ***************************************************************************
|
|
|
|
|
|
|
|
CTextureDrvInfosD3D::~CTextureDrvInfosD3D()
|
|
|
|
{
|
|
|
|
H_AUTO_D3D(CTextureDrvInfosD3D_CTextureDrvInfosD3DDtor)
|
|
|
|
if (Texture)
|
|
|
|
{
|
|
|
|
// If a texture is in the cache state -> set to null (texture no more used)
|
|
|
|
for (uint32 i = 0; i < CDriverD3D::MaxTexture; ++i)
|
|
|
|
if (_Driver->_TexturePtrStateCache[i].Texture == Texture)
|
|
|
|
_Driver->setTexture(i, (LPDIRECT3DBASETEXTURE9)NULL);
|
|
|
|
|
|
|
|
Texture->Release();
|
|
|
|
Texture = NULL;
|
|
|
|
Texture2d = NULL;
|
|
|
|
TextureCube = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// release profiling texture mem.
|
|
|
|
_Driver->_AllocatedTextureMemory -= TextureMemory;
|
|
|
|
|
|
|
|
// release in TextureUsed.
|
|
|
|
_Driver->_TextureUsed.erase (this);
|
|
|
|
}
|
|
|
|
|
|
|
|
// ***************************************************************************
|
|
|
|
|
|
|
|
bool CDriverD3D::setupTexture (ITexture& tex)
|
|
|
|
{
|
|
|
|
H_AUTO_D3D(CDriverD3D_setupTexture )
|
|
|
|
bool nTmp;
|
|
|
|
return setupTextureEx (tex, true, nTmp, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
// ***************************************************************************
|
|
|
|
|
|
|
|
const D3DTEXTUREADDRESS RemapTextureAdressTypeNeL2D3D[ITexture::WrapModeCount]=
|
|
|
|
{
|
|
|
|
D3DTADDRESS_WRAP, // Repeat
|
|
|
|
D3DTADDRESS_CLAMP, // Clamp
|
|
|
|
};
|
|
|
|
|
|
|
|
// ***************************************************************************
|
|
|
|
|
|
|
|
const D3DTEXTUREFILTERTYPE RemapMagTextureFilterTypeNeL2D3D[ITexture::MagFilterCount]=
|
|
|
|
{
|
|
|
|
D3DTEXF_POINT, // Nearest
|
|
|
|
D3DTEXF_LINEAR, // Linear
|
|
|
|
};
|
|
|
|
|
|
|
|
// ***************************************************************************
|
|
|
|
|
|
|
|
const D3DTEXTUREFILTERTYPE RemapMinTextureFilterTypeNeL2D3D[ITexture::MinFilterCount]=
|
|
|
|
{
|
|
|
|
D3DTEXF_POINT, // NearestMipMapOff
|
|
|
|
D3DTEXF_POINT, // NearestMipMapNearest
|
|
|
|
D3DTEXF_POINT, // NearestMipMapLinear
|
|
|
|
D3DTEXF_LINEAR, // LinearMipMapOff
|
|
|
|
D3DTEXF_LINEAR, // LinearMipMapNearest
|
|
|
|
D3DTEXF_LINEAR, // LinearMipMapLinear
|
|
|
|
};
|
|
|
|
|
|
|
|
// ***************************************************************************
|
|
|
|
|
|
|
|
const D3DTEXTUREFILTERTYPE RemapMipTextureFilterTypeNeL2D3D[ITexture::MinFilterCount]=
|
|
|
|
{
|
|
|
|
D3DTEXF_NONE, // NearestMipMapOff
|
|
|
|
D3DTEXF_POINT, // NearestMipMapNearest
|
|
|
|
D3DTEXF_LINEAR, // NearestMipMapLinear
|
|
|
|
D3DTEXF_NONE, // LinearMipMapOff
|
|
|
|
D3DTEXF_POINT, // LinearMipMapNearest
|
|
|
|
D3DTEXF_LINEAR, // LinearMipMapLinear
|
|
|
|
};
|
|
|
|
|
|
|
|
// ***************************************************************************
|
|
|
|
|
|
|
|
const D3DFORMAT RemapTextureFormatTypeNeL2D3D[CBitmap::ModeCount]=
|
|
|
|
{
|
|
|
|
D3DFMT_A8R8G8B8, // RGBA
|
|
|
|
D3DFMT_L8, // Luminance
|
|
|
|
D3DFMT_A8, // Alpha
|
|
|
|
D3DFMT_A8L8, // AlphaLuminance
|
|
|
|
D3DFMT_DXT1, // DXTC1
|
|
|
|
D3DFMT_DXT1, // DXTC1Alpha
|
|
|
|
D3DFMT_DXT3, // DXTC3
|
|
|
|
D3DFMT_DXT5, // DXTC5
|
|
|
|
D3DFMT_V8U8, // DsDt
|
|
|
|
};
|
|
|
|
|
|
|
|
// ***************************************************************************
|
|
|
|
|
|
|
|
const bool RemapTextureFormatCompressedTypeNeL2D3D[CBitmap::ModeCount]=
|
|
|
|
{
|
|
|
|
false, // RGBA
|
|
|
|
false, // Luminance
|
|
|
|
false, // Alpha
|
|
|
|
false, // AlphaLuminance
|
|
|
|
true, // DXTC1
|
|
|
|
true, // DXTC1Alpha
|
|
|
|
true, // DXTC3
|
|
|
|
true, // DXTC5
|
|
|
|
false, // DsDt
|
|
|
|
};
|
|
|
|
|
|
|
|
// ***************************************************************************
|
|
|
|
|
|
|
|
const D3DCUBEMAP_FACES RemapCubeFaceTypeNeL2D3D[6]=
|
|
|
|
{
|
|
|
|
D3DCUBEMAP_FACE_POSITIVE_X, // positive_x
|
|
|
|
D3DCUBEMAP_FACE_NEGATIVE_X, // negative_x
|
|
|
|
D3DCUBEMAP_FACE_POSITIVE_Z, // positive_y
|
|
|
|
D3DCUBEMAP_FACE_NEGATIVE_Z, // negative_y
|
|
|
|
D3DCUBEMAP_FACE_POSITIVE_Y, // positive_z
|
|
|
|
D3DCUBEMAP_FACE_NEGATIVE_Y, // negative_z
|
|
|
|
};
|
|
|
|
|
|
|
|
// ***************************************************************************
|
|
|
|
|
|
|
|
D3DFORMAT CDriverD3D::getD3DDestTextureFormat (ITexture& tex)
|
|
|
|
{
|
|
|
|
H_AUTO_D3D(CDriverD3D_getD3DDestTextureFormat )
|
|
|
|
ITexture::TUploadFormat texfmt= tex.getUploadFormat();
|
|
|
|
|
|
|
|
// If auto, retrieve the pixel format of the bitmap.
|
|
|
|
if(texfmt == ITexture::Auto)
|
|
|
|
{
|
|
|
|
switch(tex.getPixelFormat())
|
|
|
|
{
|
|
|
|
case CBitmap::RGBA:
|
|
|
|
if(_ForceDXTCCompression && tex.allowDegradation() )
|
|
|
|
texfmt= ITexture::DXTC5;
|
|
|
|
else
|
|
|
|
texfmt= ITexture::RGBA8888;
|
|
|
|
break;
|
|
|
|
case CBitmap::DXTC1:
|
|
|
|
texfmt= ITexture::DXTC1;
|
|
|
|
break;
|
|
|
|
case CBitmap::DXTC1Alpha:
|
|
|
|
texfmt= ITexture::DXTC1Alpha;
|
|
|
|
break;
|
|
|
|
case CBitmap::DXTC3:
|
|
|
|
texfmt= ITexture::DXTC3;
|
|
|
|
break;
|
|
|
|
case CBitmap::DXTC5:
|
|
|
|
texfmt= ITexture::DXTC5;
|
|
|
|
break;
|
|
|
|
case CBitmap::Luminance:
|
|
|
|
texfmt= ITexture::Luminance;
|
|
|
|
break;
|
|
|
|
case CBitmap::Alpha:
|
|
|
|
texfmt= ITexture::Alpha;
|
|
|
|
break;
|
|
|
|
case CBitmap::AlphaLuminance:
|
|
|
|
texfmt= ITexture::AlphaLuminance;
|
|
|
|
break;
|
|
|
|
case CBitmap::DsDt:
|
|
|
|
texfmt= ITexture::DsDt;
|
|
|
|
break;
|
|
|
|
default: texfmt= ITexture::RGBA8888; break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get standard prefered tex format.
|
|
|
|
nlassert (texfmt<ITexture::UploadFormatCount);
|
|
|
|
return _PreferedTextureFormat[texfmt];
|
|
|
|
}
|
|
|
|
|
|
|
|
// ***************************************************************************
|
|
|
|
|
|
|
|
uint getPixelFormatSize (D3DFORMAT destFormat)
|
|
|
|
{
|
|
|
|
uint bits = 0;
|
|
|
|
switch (destFormat)
|
|
|
|
{
|
|
|
|
case D3DFMT_R8G8B8: bits=32; break;
|
|
|
|
case D3DFMT_A8R8G8B8: bits=32; break;
|
|
|
|
case D3DFMT_X8R8G8B8: bits=32; break;
|
|
|
|
case D3DFMT_R5G6B5: bits=16; break;
|
|
|
|
case D3DFMT_X1R5G5B5: bits=16; break;
|
|
|
|
case D3DFMT_A1R5G5B5: bits=16; break;
|
|
|
|
case D3DFMT_A4R4G4B4: bits=16; break;
|
|
|
|
case D3DFMT_R3G3B2: bits=8; break;
|
|
|
|
case D3DFMT_A8: bits=8; break;
|
|
|
|
case D3DFMT_A8R3G3B2: bits=16; break;
|
|
|
|
case D3DFMT_X4R4G4B4: bits=16; break;
|
|
|
|
case D3DFMT_A2B10G10R10: bits=32; break;
|
|
|
|
case D3DFMT_A8B8G8R8: bits=32; break;
|
|
|
|
case D3DFMT_X8B8G8R8: bits=32; break;
|
|
|
|
case D3DFMT_G16R16: bits=32; break;
|
|
|
|
case D3DFMT_A2R10G10B10: bits=32; break;
|
|
|
|
case D3DFMT_A16B16G16R16: bits=64; break;
|
|
|
|
case D3DFMT_A8P8: bits=16; break;
|
|
|
|
case D3DFMT_P8: bits=8; break;
|
|
|
|
case D3DFMT_L8: bits=8; break;
|
|
|
|
case D3DFMT_L16: bits=16; break;
|
|
|
|
case D3DFMT_A8L8: bits=16; break;
|
|
|
|
case D3DFMT_A4L4: bits=8; break;
|
|
|
|
case D3DFMT_V8U8: bits=16; break;
|
|
|
|
case D3DFMT_Q8W8V8U8: bits=32; break;
|
|
|
|
case D3DFMT_V16U16: bits=32; break;
|
|
|
|
case D3DFMT_Q16W16V16U16: bits=64; break;
|
|
|
|
case D3DFMT_CxV8U8: bits=16; break;
|
|
|
|
case D3DFMT_L6V5U5: bits=16; break;
|
|
|
|
case D3DFMT_X8L8V8U8: bits=32; break;
|
|
|
|
case D3DFMT_A2W10V10U10: bits=32; break;
|
|
|
|
case D3DFMT_G8R8_G8B8: bits=24; break;
|
|
|
|
case D3DFMT_R8G8_B8G8: bits=24; break;
|
|
|
|
case D3DFMT_DXT1: bits=4; break;
|
|
|
|
case D3DFMT_DXT2: bits=8; break;
|
|
|
|
case D3DFMT_DXT3: bits=8; break;
|
|
|
|
case D3DFMT_DXT4: bits=8; break;
|
|
|
|
case D3DFMT_DXT5: bits=8; break;
|
|
|
|
default: nlstop; break; // unkown pixel format
|
|
|
|
}
|
|
|
|
return bits;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ***************************************************************************
|
|
|
|
|
|
|
|
uint32 CDriverD3D::computeTextureMemoryUsage (uint width, uint height, uint levels, D3DFORMAT destFormat, bool cube)
|
|
|
|
{
|
|
|
|
H_AUTO_D3D(CDriverD3D_computeTextureMemoryUsage )
|
|
|
|
// Get bit per pixel
|
|
|
|
uint bits = getPixelFormatSize (destFormat);
|
|
|
|
uint32 size = 0;
|
|
|
|
while (levels>0)
|
|
|
|
{
|
|
|
|
size += (width * height * bits) >> 3;
|
|
|
|
width = max((uint)(width>>1), 1U);
|
|
|
|
height = max((uint)(height>>1), 1U);
|
|
|
|
levels--;
|
|
|
|
}
|
|
|
|
if (cube)
|
|
|
|
size *= 6;
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ***************************************************************************
|
|
|
|
|
|
|
|
bool CDriverD3D::generateD3DTexture (ITexture& tex, bool textureDegradation, D3DFORMAT &destFormat, D3DFORMAT &srcFormat, bool &cube)
|
|
|
|
{
|
|
|
|
H_AUTO_D3D(CDriverD3D_generateD3DTexture )
|
|
|
|
// Regenerate all the texture.
|
|
|
|
tex.generate();
|
|
|
|
|
|
|
|
// Is a cube texture ?
|
|
|
|
cube = tex.isTextureCube();
|
|
|
|
|
|
|
|
// D3D infos
|
|
|
|
CTextureDrvInfosD3D* d3dtext;
|
|
|
|
d3dtext= getTextureD3D(tex);
|
|
|
|
|
|
|
|
// For each face
|
|
|
|
UINT width = 0;
|
|
|
|
UINT height = 0;
|
|
|
|
UINT levels = 0;
|
|
|
|
bool srcFormatCompressed = true;
|
|
|
|
bool renderTarget = false;
|
|
|
|
const uint faceCount = cube?6:1;
|
|
|
|
uint face;
|
|
|
|
uint firstMipMap = 0;
|
|
|
|
for (face=0; face<faceCount; face++)
|
|
|
|
{
|
|
|
|
// Get the texture pointer
|
|
|
|
ITexture *texture = cube?(static_cast<CTextureCube*>(&tex)->getTexture((CTextureCube::TFace)face)):&tex;
|
|
|
|
|
|
|
|
// getD3DTextureFormat choose a d3d dest and a src format. src format should be the tex one.
|
|
|
|
if (face==0)
|
|
|
|
{
|
|
|
|
srcFormatCompressed = RemapTextureFormatCompressedTypeNeL2D3D[texture->getPixelFormat()];
|
|
|
|
srcFormat = RemapTextureFormatTypeNeL2D3D[texture->getPixelFormat()];
|
|
|
|
destFormat = getD3DDestTextureFormat (*texture);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// All cube texture must have the same format
|
|
|
|
nlassert (srcFormatCompressed == RemapTextureFormatCompressedTypeNeL2D3D[texture->getPixelFormat()]);
|
|
|
|
nlassert (srcFormat == RemapTextureFormatTypeNeL2D3D[texture->getPixelFormat()]);
|
|
|
|
nlassert (destFormat == getD3DDestTextureFormat (*texture));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Should not happen
|
|
|
|
nlassert (!((srcFormatCompressed) && (destFormat == D3DFMT_A8R8G8B8)));
|
|
|
|
|
|
|
|
// Get new texture format
|
|
|
|
width = texture->getWidth();
|
|
|
|
height = texture->getHeight();
|
|
|
|
levels = texture->getMipMapCount();
|
|
|
|
if (levels == 1 && !srcFormatCompressed)
|
|
|
|
{
|
|
|
|
// if not built-in mipmap levels, compute how many of them are needed
|
|
|
|
levels = texture->computeNeededMipMapCount();
|
|
|
|
}
|
|
|
|
if (cube && !_CubbedMipMapSupported)
|
|
|
|
{
|
|
|
|
levels = 1;
|
|
|
|
}
|
|
|
|
renderTarget = texture->getRenderTarget();
|
|
|
|
|
|
|
|
// Texture degradation
|
|
|
|
if (_ForceTextureResizePower>0 && texture->allowDegradation() && (!srcFormatCompressed || levels>1) && textureDegradation)
|
|
|
|
{
|
|
|
|
// New size
|
|
|
|
width = max(1U, (UINT)(texture->getWidth(0) >> _ForceTextureResizePower));
|
|
|
|
height = max(1U, (UINT)(texture->getHeight(0) >> _ForceTextureResizePower));
|
|
|
|
levels = (levels>_ForceTextureResizePower)?levels-_ForceTextureResizePower:1;
|
|
|
|
|
|
|
|
// Modify source texture
|
|
|
|
if (srcFormatCompressed)
|
|
|
|
{
|
|
|
|
if (cube && !_CubbedMipMapSupported)
|
|
|
|
{
|
|
|
|
// just uses one the level of interest and not the others
|
|
|
|
firstMipMap = (texture->getMipMapCount()>_ForceTextureResizePower)?_ForceTextureResizePower : texture->getMipMapCount() - 1;
|
|
|
|
levels = 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Skip a compressed mipmap
|
|
|
|
firstMipMap = texture->getMipMapCount()-levels;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Resample the non-compressed texture
|
|
|
|
texture->resample(width, height);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Generate mipmap
|
|
|
|
if (!srcFormatCompressed)
|
|
|
|
{
|
|
|
|
if (texture->mipMapOn() && levels > 1)
|
|
|
|
{
|
|
|
|
texture->buildMipMaps();
|
|
|
|
levels= texture->getMipMapCount();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
levels= 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If compressed, width and height must be 4x4 aligned
|
|
|
|
if (srcFormatCompressed)
|
|
|
|
{
|
|
|
|
if (width & 3)
|
|
|
|
width = (width & ~3)+4;
|
|
|
|
if (height & 3)
|
|
|
|
height = (height & ~3)+4;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Got an old texture ?
|
|
|
|
if (d3dtext->Texture &&
|
|
|
|
(
|
|
|
|
(d3dtext->Width != width) ||
|
|
|
|
(d3dtext->Height != height) ||
|
|
|
|
(d3dtext->Levels != levels) ||
|
|
|
|
(d3dtext->FirstMipMap != firstMipMap) ||
|
|
|
|
(d3dtext->DestFormat != destFormat) ||
|
|
|
|
(d3dtext->IsCube != cube) ||
|
|
|
|
(d3dtext->RenderTarget != renderTarget)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
{
|
|
|
|
// Delete this texture
|
|
|
|
if (d3dtext->Texture)
|
|
|
|
{
|
|
|
|
d3dtext->Texture->Release();
|
|
|
|
d3dtext->Texture = NULL;
|
|
|
|
d3dtext->Texture2d = NULL;
|
|
|
|
d3dtext->TextureCube = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
// profiling: count TextureMemory usage.
|
|
|
|
_AllocatedTextureMemory -= d3dtext->TextureMemory;
|
|
|
|
d3dtext->TextureMemory = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Texture must be created ?
|
|
|
|
if (d3dtext->Texture == NULL)
|
|
|
|
{
|
|
|
|
// profiling: count TextureMemory usage.
|
2012-09-25 22:02:27 +00:00
|
|
|
uint32 textureMemory = computeTextureMemoryUsage (width, height, levels, destFormat, cube);
|
2012-05-29 13:31:11 +00:00
|
|
|
|
|
|
|
// Create the texture
|
|
|
|
bool createSuccess;
|
|
|
|
|
|
|
|
if (cube)
|
|
|
|
{
|
|
|
|
createSuccess = _DeviceInterface->CreateCubeTexture(width, levels, renderTarget?D3DUSAGE_RENDERTARGET:0, destFormat, renderTarget?D3DPOOL_DEFAULT:D3DPOOL_MANAGED, &(d3dtext->TextureCube), NULL) == D3D_OK;
|
|
|
|
d3dtext->Texture = d3dtext->TextureCube;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2012-10-27 16:44:38 +00:00
|
|
|
/*
|
2012-05-29 13:31:11 +00:00
|
|
|
// textures with mipmaps doesn't support not power of two sizes
|
|
|
|
// only DXTC formats are beginning with a 'D'
|
|
|
|
if (supportNonPowerOfTwoTextures() && (!isPowerOf2(width) || !isPowerOf2(height)) && levels == 1)
|
|
|
|
{
|
|
|
|
// support for non-power of two sizes for textures need these lines
|
|
|
|
_DeviceInterface->SetRenderState(D3DRS_WRAP0, 0);
|
|
|
|
_DeviceInterface->SetSamplerState(0, D3DSAMP_ADDRESSU, D3DTADDRESS_CLAMP);
|
|
|
|
_DeviceInterface->SetSamplerState(0, D3DSAMP_ADDRESSV, D3DTADDRESS_CLAMP);
|
|
|
|
_DeviceInterface->SetSamplerState(0, D3DSAMP_ADDRESSW, D3DTADDRESS_CLAMP);
|
|
|
|
}
|
2012-10-27 16:44:38 +00:00
|
|
|
*/
|
2012-05-29 13:31:11 +00:00
|
|
|
|
2012-09-25 22:02:27 +00:00
|
|
|
HRESULT hr = _DeviceInterface->CreateTexture (width, height, levels, renderTarget?D3DUSAGE_RENDERTARGET:0, destFormat, renderTarget?D3DPOOL_DEFAULT:D3DPOOL_MANAGED, &(d3dtext->Texture2d), NULL);
|
|
|
|
|
|
|
|
if (hr != D3D_OK)
|
|
|
|
{
|
|
|
|
nlwarning("CreateTexture failed with code 0x%x for texture %s in %ux%u", hr, tex.getShareName().c_str(), width, height);
|
|
|
|
}
|
|
|
|
|
|
|
|
createSuccess = hr == D3D_OK;
|
2012-05-29 13:31:11 +00:00
|
|
|
d3dtext->Texture = d3dtext->Texture2d;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!createSuccess)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Stats
|
2012-09-25 22:02:27 +00:00
|
|
|
d3dtext->TextureMemory = textureMemory;
|
2012-05-29 13:31:11 +00:00
|
|
|
_AllocatedTextureMemory += d3dtext->TextureMemory;
|
|
|
|
|
|
|
|
// Copy parameters
|
|
|
|
d3dtext->Width = width;
|
|
|
|
d3dtext->Height = height;
|
|
|
|
d3dtext->Levels = uint8(levels);
|
|
|
|
d3dtext->FirstMipMap = uint8(firstMipMap);
|
|
|
|
d3dtext->DestFormat = destFormat;
|
|
|
|
d3dtext->SrcCompressed = srcFormatCompressed;
|
|
|
|
d3dtext->IsCube = cube;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ***************************************************************************
|
|
|
|
inline void CDriverD3D::setupTextureWrapMode(ITexture& tex)
|
|
|
|
{
|
|
|
|
CTextureDrvInfosD3D *d3dtext = CDriverD3D::getTextureD3D(tex);
|
|
|
|
nlassert(d3dtext);
|
|
|
|
d3dtext->WrapS = RemapTextureAdressTypeNeL2D3D[tex.getWrapS()];
|
|
|
|
d3dtext->WrapT = RemapTextureAdressTypeNeL2D3D[tex.getWrapT()];
|
|
|
|
d3dtext->MagFilter = RemapMagTextureFilterTypeNeL2D3D[tex.getMagFilter()];
|
|
|
|
d3dtext->MinFilter = RemapMinTextureFilterTypeNeL2D3D[tex.getMinFilter()];
|
|
|
|
d3dtext->MipFilter = RemapMipTextureFilterTypeNeL2D3D[tex.getMinFilter()];
|
2012-10-27 15:46:13 +00:00
|
|
|
|
|
|
|
// only enable for min filter, because it's never supported for mag filter
|
|
|
|
if (_AnisotropicFilter > 1 && tex.getMinFilter() > ITexture::NearestMipMapLinear)
|
|
|
|
{
|
|
|
|
if (tex.isTextureCube())
|
|
|
|
{
|
|
|
|
if (_AnisotropicMinCubeSupported) d3dtext->MinFilter = D3DTEXF_ANISOTROPIC;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (_AnisotropicMinSupported) d3dtext->MinFilter = D3DTEXF_ANISOTROPIC;
|
|
|
|
}
|
|
|
|
}
|
2012-05-29 13:31:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool CDriverD3D::setupTextureEx (ITexture& tex, bool bUpload, bool &bAllUploaded, bool bMustRecreateSharedTexture)
|
|
|
|
{
|
|
|
|
H_AUTO_D3D(CDriverD3D_setupTextureEx )
|
|
|
|
bAllUploaded = false;
|
|
|
|
|
|
|
|
|
|
|
|
// 0. Create/Retrieve the driver texture.
|
|
|
|
//=======================================
|
|
|
|
bool mustCreate = false;
|
|
|
|
if ( !tex.TextureDrvShare )
|
|
|
|
{
|
|
|
|
// insert into driver list. (so it is deleted when driver is deleted).
|
|
|
|
ItTexDrvSharePtrList it= _TexDrvShares.insert(_TexDrvShares.end(), (NL3D::CTextureDrvShare*)NULL);
|
|
|
|
// create and set iterator, for future deletion.
|
|
|
|
*it= tex.TextureDrvShare= new CTextureDrvShare(this, it, &tex);
|
|
|
|
|
|
|
|
// Must (re)-create the texture.
|
|
|
|
mustCreate = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Does the texture has been touched ?
|
|
|
|
if ( (!tex.touched()) && (!mustCreate) )
|
|
|
|
{
|
|
|
|
setupTextureWrapMode(tex); // update basics parameters if needed
|
|
|
|
return true; // Do not do anything
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 1. If modified, may (re)load texture part or all of the texture.
|
|
|
|
//=================================================================
|
|
|
|
|
|
|
|
|
|
|
|
bool mustLoadAll= false;
|
|
|
|
bool mustLoadPart= false;
|
|
|
|
|
|
|
|
// A. Share mgt.
|
|
|
|
//==============
|
|
|
|
if(tex.supportSharing())
|
|
|
|
{
|
|
|
|
// Try to get the shared texture.
|
|
|
|
|
|
|
|
// Create the shared Name.
|
|
|
|
std::string name;
|
|
|
|
getTextureShareName (tex, name);
|
|
|
|
|
|
|
|
// insert or get the texture.
|
|
|
|
{
|
|
|
|
CSynchronized<TTexDrvInfoPtrMap>::CAccessor access(&_SyncTexDrvInfos);
|
|
|
|
TTexDrvInfoPtrMap &rTexDrvInfos = access.value();
|
|
|
|
|
|
|
|
ItTexDrvInfoPtrMap itTex;
|
|
|
|
itTex= rTexDrvInfos.find(name);
|
|
|
|
|
|
|
|
// texture not found?
|
|
|
|
if( itTex==rTexDrvInfos.end() )
|
|
|
|
{
|
|
|
|
// insert into driver map. (so it is deleted when driver is deleted).
|
|
|
|
itTex= (rTexDrvInfos.insert(make_pair(name, (ITextureDrvInfos*)NULL))).first;
|
|
|
|
// create and set iterator, for future deletion.
|
|
|
|
itTex->second= tex.TextureDrvShare->DrvTexture= new CTextureDrvInfosD3D(this, itTex, this, tex.getRenderTarget());
|
|
|
|
|
|
|
|
// need to load ALL this texture.
|
|
|
|
mustLoadAll= true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
tex.TextureDrvShare->DrvTexture= itTex->second;
|
|
|
|
|
|
|
|
if(bMustRecreateSharedTexture)
|
|
|
|
// reload this shared texture (user request)
|
|
|
|
mustLoadAll= true;
|
|
|
|
else
|
|
|
|
// Do not need to reload this texture, even if the format/mipmap has changed, since we found this
|
|
|
|
// couple in the map.
|
|
|
|
mustLoadAll= false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Do not test if part of texture may need to be computed, because Rect invalidation is incompatible
|
|
|
|
// with texture sharing.
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// If texture not already created.
|
|
|
|
if(!tex.TextureDrvShare->DrvTexture)
|
|
|
|
{
|
|
|
|
// Must create it. Create auto a D3D id (in constructor).
|
|
|
|
// Do not insert into the map. This un-shared texture will be deleted at deletion of the texture.
|
|
|
|
// Inform ITextureDrvInfos by passing NULL _Driver.
|
|
|
|
tex.TextureDrvShare->DrvTexture= new CTextureDrvInfosD3D(NULL, ItTexDrvInfoPtrMap(), this, tex.getRenderTarget());
|
|
|
|
|
|
|
|
// need to load ALL this texture.
|
|
|
|
mustLoadAll= true;
|
|
|
|
}
|
|
|
|
else if(tex.isAllInvalidated())
|
|
|
|
mustLoadAll= true;
|
|
|
|
else if(tex.touched())
|
|
|
|
mustLoadPart= true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(tex.isTextureCube() && (!_TextureCubeSupported))
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// B. Setup texture.
|
|
|
|
//==================
|
|
|
|
if(mustLoadAll || mustLoadPart)
|
|
|
|
{
|
|
|
|
CTextureDrvInfosD3D* d3dtext;
|
|
|
|
d3dtext= getTextureD3D(tex);
|
|
|
|
|
|
|
|
// a. Load All the texture case.
|
|
|
|
//==============================
|
|
|
|
if (mustLoadAll)
|
|
|
|
{
|
|
|
|
D3DFORMAT srcFormat;
|
|
|
|
D3DFORMAT destFormat;
|
|
|
|
bool cube;
|
|
|
|
if (generateD3DTexture (tex, true, destFormat, srcFormat, cube))
|
|
|
|
{
|
|
|
|
if((tex.getSize()>0) || cube)
|
|
|
|
{
|
|
|
|
// Can support multi part upload ?
|
|
|
|
if ((destFormat != srcFormat) && d3dtext->SrcCompressed)
|
|
|
|
{
|
|
|
|
// No, force upload
|
|
|
|
bUpload = true; // Force all upload
|
|
|
|
}
|
|
|
|
|
|
|
|
// Must upload the texture ?
|
|
|
|
if (bUpload && !tex.getRenderTarget())
|
|
|
|
{
|
|
|
|
// Update the pixels
|
|
|
|
uint i;
|
|
|
|
UINT destLevel = 0;
|
|
|
|
uint blockCount = d3dtext->Height>>(d3dtext->SrcCompressed?2:0);
|
|
|
|
uint lineWidth = d3dtext->Width;
|
|
|
|
const uint srcPixelSize = getPixelFormatSize (srcFormat);
|
|
|
|
for(i=d3dtext->FirstMipMap;i<uint(d3dtext->FirstMipMap)+uint(d3dtext->Levels);i++, destLevel++)
|
|
|
|
{
|
|
|
|
// Size of a line
|
|
|
|
const uint blockSize = ((lineWidth*srcPixelSize)>>3)<<(d3dtext->SrcCompressed?2:0);
|
|
|
|
|
|
|
|
// Several faces for cube texture
|
|
|
|
const uint numFaces = d3dtext->IsCube?6:1;
|
|
|
|
uint face;
|
|
|
|
for (face=0; face<numFaces; face++)
|
|
|
|
{
|
|
|
|
// Get the cube texture
|
|
|
|
ITexture *texture = d3dtext->IsCube?(static_cast<CTextureCube*>(&tex)->getTexture((CTextureCube::TFace)face)):&tex;
|
|
|
|
if (texture)
|
|
|
|
{
|
|
|
|
// Same format ?
|
|
|
|
if (destFormat == srcFormat)
|
|
|
|
{
|
|
|
|
// Lock the surface level
|
|
|
|
D3DLOCKED_RECT rect;
|
|
|
|
bool locked = false;
|
|
|
|
if (!d3dtext->IsCube)
|
|
|
|
locked = d3dtext->Texture2d->LockRect (destLevel, &rect, NULL, 0) == D3D_OK;
|
|
|
|
else
|
|
|
|
locked = d3dtext->TextureCube->LockRect (RemapCubeFaceTypeNeL2D3D[face], destLevel, &rect, NULL, 0) == D3D_OK;
|
|
|
|
|
|
|
|
// Rect locked ?
|
|
|
|
if (locked)
|
|
|
|
{
|
|
|
|
uint block;
|
|
|
|
for (block=0; block<blockCount; block++)
|
|
|
|
{
|
|
|
|
// Copy the block
|
|
|
|
const uint8 *src = &(texture->getPixels(i)[block*blockSize]);
|
|
|
|
uint8 *dest = ((uint8*)rect.pBits)+block*rect.Pitch;
|
|
|
|
if (destFormat == D3DFMT_A8R8G8B8)
|
|
|
|
copyRGBA2BGRA ((uint32*)dest, (const uint32*)src, blockSize>>2);
|
|
|
|
else
|
|
|
|
memcpy (dest, src, blockSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Unlock
|
|
|
|
if (!d3dtext->IsCube)
|
|
|
|
d3dtext->Texture2d->UnlockRect (destLevel);
|
|
|
|
else
|
|
|
|
d3dtext->TextureCube->UnlockRect (RemapCubeFaceTypeNeL2D3D[face], destLevel);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Convert the surface using a D3DX method
|
|
|
|
IDirect3DSurface9 *pDestSurface;
|
|
|
|
bool surfaceOk = false;
|
|
|
|
if (!d3dtext->IsCube)
|
|
|
|
surfaceOk = d3dtext->Texture2d->GetSurfaceLevel(destLevel, &pDestSurface) == D3D_OK;
|
|
|
|
else
|
|
|
|
surfaceOk = d3dtext->TextureCube->GetCubeMapSurface(RemapCubeFaceTypeNeL2D3D[face], destLevel, &pDestSurface) == D3D_OK;
|
|
|
|
|
|
|
|
// Surface has been retrieved ?
|
|
|
|
if (surfaceOk)
|
|
|
|
{
|
|
|
|
if (srcFormat == D3DFMT_A8R8G8B8)
|
|
|
|
{
|
|
|
|
const uint8 *src = &(texture->getPixels(i)[0]);
|
|
|
|
|
|
|
|
// Fill the temp buffer with BGRA info
|
|
|
|
_TempBuffer.resize (blockCount*blockSize);
|
|
|
|
uint8 *dest = &(_TempBuffer[0]);
|
|
|
|
uint line;
|
|
|
|
for (line=0; line<blockCount; line++)
|
|
|
|
{
|
|
|
|
copyRGBA2BGRA ((uint32*)dest, (uint32*)(src+line*blockSize), lineWidth);
|
|
|
|
dest += blockSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Upload the texture part
|
|
|
|
RECT srcRect;
|
|
|
|
srcRect.top = 0;
|
|
|
|
srcRect.bottom = blockCount;
|
|
|
|
srcRect.left = 0;
|
|
|
|
srcRect.right = lineWidth;
|
|
|
|
D3DXLoadSurfaceFromMemory (pDestSurface, NULL, NULL, &(_TempBuffer[0]), srcFormat,
|
|
|
|
blockSize, NULL, &srcRect, D3DX_FILTER_NONE, 0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
RECT rect;
|
|
|
|
rect.top = 0;
|
|
|
|
rect.bottom = blockCount;
|
|
|
|
rect.left = 0;
|
|
|
|
rect.right = lineWidth;
|
|
|
|
D3DXLoadSurfaceFromMemory (pDestSurface, NULL, NULL, &(texture->getPixels(i)[0]), srcFormat,
|
|
|
|
blockSize, NULL, &rect, D3DX_FILTER_NONE, 0);
|
|
|
|
}
|
|
|
|
pDestSurface->Release();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Next level
|
|
|
|
lineWidth = max((UINT)(lineWidth>>1), (UINT)(d3dtext->SrcCompressed?4:1));
|
|
|
|
blockCount = max((UINT)(blockCount>>1), 1U);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Upload now
|
|
|
|
if (!d3dtext->IsCube)
|
|
|
|
d3dtext->Texture->PreLoad();
|
|
|
|
else
|
|
|
|
d3dtext->Texture->PreLoad();
|
|
|
|
bAllUploaded = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// b. Load part of the texture case.
|
|
|
|
//==================================
|
|
|
|
// Replace parts of a compressed image. Maybe don't work with the actual system of invalidateRect()...
|
|
|
|
else if (mustLoadPart && !d3dtext->SrcCompressed)
|
|
|
|
{
|
|
|
|
D3DFORMAT destFormat;
|
|
|
|
D3DFORMAT srcFormat;
|
|
|
|
bool cube;
|
|
|
|
if (CDriverD3D::generateD3DTexture (tex, false, destFormat, srcFormat, cube))
|
|
|
|
{
|
|
|
|
// No degradation in load part
|
|
|
|
nlassert (d3dtext->FirstMipMap == 0);
|
|
|
|
|
|
|
|
if(tex.getSize()>0 && bUpload && !tex.getRenderTarget())
|
|
|
|
{
|
|
|
|
// For all rect, update the texture/mipmap.
|
|
|
|
//===============================================
|
|
|
|
list<NLMISC::CRect>::iterator itRect;
|
|
|
|
for(itRect=tex._ListInvalidRect.begin(); itRect!=tex._ListInvalidRect.end(); itRect++)
|
|
|
|
{
|
|
|
|
CRect &rect = *itRect;
|
|
|
|
sint x0= rect.X;
|
|
|
|
sint y0= rect.Y;
|
|
|
|
sint x1= rect.X+rect.Width;
|
|
|
|
sint y1= rect.Y+rect.Height;
|
|
|
|
|
|
|
|
// Update the pixels
|
|
|
|
uint i;
|
|
|
|
UINT destLevel = 0;
|
|
|
|
for(i=d3dtext->FirstMipMap;i<uint(d3dtext->FirstMipMap)+uint(d3dtext->Levels);i++, destLevel++)
|
|
|
|
{
|
|
|
|
CRect rectDest;
|
|
|
|
rectDest.X = x0;
|
|
|
|
rectDest.Y = y0;
|
|
|
|
rectDest.Width = x1-x0;
|
|
|
|
rectDest.Height = y1-y0;
|
|
|
|
uploadTextureInternal (tex, rectDest, uint8(destLevel), uint8(i), destFormat, srcFormat);
|
|
|
|
|
|
|
|
// floor .
|
|
|
|
x0= x0/2;
|
|
|
|
y0= y0/2;
|
|
|
|
// ceil.
|
|
|
|
x1= (x1+1)/2;
|
|
|
|
y1= (y1+1)/2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Release, if wanted.
|
|
|
|
if(tex.getReleasable())
|
|
|
|
tex.release();
|
|
|
|
}
|
|
|
|
|
|
|
|
setupTextureWrapMode(tex);
|
|
|
|
// The texture is correctly setuped.
|
|
|
|
tex.clearTouched();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ***************************************************************************
|
|
|
|
|
|
|
|
bool CDriverD3D::uploadTexture (ITexture& tex, CRect& rect, uint8 nNumMipMap)
|
|
|
|
{
|
|
|
|
H_AUTO_D3D(CDriverD3D_uploadTexture )
|
|
|
|
if (tex.TextureDrvShare == NULL)
|
|
|
|
return false; // Texture not created
|
|
|
|
if (tex.TextureDrvShare->DrvTexture == NULL)
|
|
|
|
return false; // Texture not created
|
|
|
|
if (tex.isTextureCube())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
CTextureDrvInfosD3D* d3dtext = getTextureD3D(tex);
|
|
|
|
// if the texture src is in DXTC MipMaped, and mipmapskip is enabled, skip first levels the user want to upload
|
|
|
|
if(d3dtext->FirstMipMap > nNumMipMap)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
nlassert (rect.X < (sint)d3dtext->Width);
|
|
|
|
nlassert (rect.Y < (sint)d3dtext->Height);
|
|
|
|
nlassert (rect.X + rect.Width <= (sint)d3dtext->Width);
|
|
|
|
nlassert (rect.Y + rect.Height <= (sint)d3dtext->Height);
|
|
|
|
nlassert(nNumMipMap<(uint8)tex.getMipMapCount());
|
|
|
|
|
|
|
|
// validate rect.
|
|
|
|
sint x0 = rect.X;
|
|
|
|
sint y0 = rect.Y;
|
|
|
|
sint x1 = rect.X+rect.Width;
|
|
|
|
sint y1 = rect.Y+rect.Height;
|
|
|
|
sint w = tex.getWidth (nNumMipMap);
|
|
|
|
sint h = tex.getHeight (nNumMipMap);
|
|
|
|
clamp (x0, 0, w);
|
|
|
|
clamp (y0, 0, h);
|
|
|
|
clamp (x1, x0, w);
|
|
|
|
clamp (y1, y0, h);
|
|
|
|
rect.X = x0;
|
|
|
|
rect.Y = y0;
|
|
|
|
rect.Width = x1 - x0;
|
|
|
|
rect.Height = y1 - y0;
|
|
|
|
|
|
|
|
// Texture format
|
|
|
|
nlassert (!tex.isTextureCube());
|
|
|
|
D3DFORMAT srcFormat = RemapTextureFormatTypeNeL2D3D[tex.getPixelFormat()];
|
|
|
|
D3DFORMAT destFormat = getD3DDestTextureFormat (tex);
|
|
|
|
|
|
|
|
return uploadTextureInternal (tex, rect, nNumMipMap-d3dtext->FirstMipMap, nNumMipMap, destFormat, srcFormat);
|
|
|
|
}
|
|
|
|
|
|
|
|
// ***************************************************************************
|
|
|
|
|
|
|
|
bool CDriverD3D::uploadTextureInternal (ITexture& tex, CRect& rect, uint8 destMipmap, uint8 srcMipmap,
|
|
|
|
D3DFORMAT destFormat, D3DFORMAT srcFormat)
|
|
|
|
{
|
|
|
|
H_AUTO_D3D(CDriverD3D_uploadTextureInternal)
|
2012-07-28 10:40:36 +00:00
|
|
|
|
|
|
|
if (rect.Width == 0 || rect.Height == 0)
|
|
|
|
{
|
|
|
|
nlwarning("Rectangle width or height cannot be 0");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-05-29 13:31:11 +00:00
|
|
|
// The D3D texture
|
|
|
|
CTextureDrvInfosD3D* d3dtext = getTextureD3D(tex);
|
|
|
|
|
|
|
|
// The pixel size
|
|
|
|
const uint pixelSize = CBitmap::bitPerPixels[tex.getPixelFormat()];
|
|
|
|
|
|
|
|
// The line width of that mipmap level
|
|
|
|
uint lineWidth = max(d3dtext->Width>>destMipmap, uint(d3dtext->SrcCompressed?4:1));
|
|
|
|
|
|
|
|
sint x0= rect.X;
|
|
|
|
sint y0= rect.Y;
|
|
|
|
sint x1= rect.X+rect.Width;
|
|
|
|
sint y1= rect.Y+rect.Height;
|
|
|
|
sint x1Copy = x1;
|
|
|
|
sint y1Copy = y1;
|
|
|
|
|
|
|
|
if (d3dtext->SrcCompressed)
|
|
|
|
{
|
|
|
|
nlassert ((x0 & 0x3) == 0);
|
|
|
|
nlassert ((y0 & 0x3) == 0);
|
|
|
|
nlassert (((x1 & 0x3) == 0) || (x1<4));
|
|
|
|
nlassert (((y1 & 0x3) == 0) || (y1<4));
|
|
|
|
x1Copy = std::max(4, x1);
|
|
|
|
y1Copy = std::max(4, y1);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Size of a line
|
|
|
|
const uint lineSize = ((lineWidth*pixelSize)>>3)<<(d3dtext->SrcCompressed?2:0);
|
|
|
|
const uint offsetX = (x0*pixelSize)>>3;
|
|
|
|
|
|
|
|
// Block of line (for compressed textures)
|
|
|
|
uint lineStart = y0;
|
|
|
|
uint lineEnd = y1Copy;
|
|
|
|
|
|
|
|
// Pitch for compressed texture
|
|
|
|
if (d3dtext->SrcCompressed)
|
|
|
|
{
|
|
|
|
lineStart >>= 2;
|
|
|
|
lineEnd >>= 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Same format ?
|
|
|
|
if (destFormat == srcFormat)
|
|
|
|
{
|
|
|
|
// Lock the surface level
|
|
|
|
D3DLOCKED_RECT rect;
|
|
|
|
RECT region;
|
|
|
|
region.left = x0;
|
|
|
|
region.right = x1;
|
|
|
|
region.top = y0;
|
|
|
|
region.bottom = y1;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const sint dataToCopy = (((x1Copy-x0)*pixelSize)>>3)<<(d3dtext->SrcCompressed?2:0);
|
|
|
|
if (d3dtext->Texture2d->LockRect (destMipmap, &rect, ®ion, 0) == D3D_OK)
|
|
|
|
{
|
|
|
|
uint line;
|
|
|
|
for (line=lineStart; line<lineEnd; line++)
|
|
|
|
{
|
|
|
|
// Copy the line
|
|
|
|
const uint8 *src = &(tex.getPixels(srcMipmap)[line*lineSize+offsetX]);
|
|
|
|
uint8 *dest = ((uint8*)rect.pBits)+(line-lineStart)*rect.Pitch;
|
|
|
|
if (destFormat == D3DFMT_A8R8G8B8)
|
|
|
|
copyRGBA2BGRA ((uint32*)dest, (const uint32*)src, dataToCopy>>2);
|
|
|
|
else
|
|
|
|
memcpy (dest, src, dataToCopy);
|
|
|
|
}
|
|
|
|
d3dtext->Texture2d->UnlockRect (destMipmap);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Convert the surface using a D3DX method
|
|
|
|
IDirect3DSurface9 *pDestSurface;
|
|
|
|
|
|
|
|
// Surface has been retrieved ?
|
|
|
|
if (d3dtext->Texture2d->GetSurfaceLevel(destMipmap, &pDestSurface) == D3D_OK)
|
|
|
|
{
|
|
|
|
RECT destRect;
|
|
|
|
destRect.top = y0;
|
|
|
|
destRect.bottom = y1;
|
|
|
|
destRect.left = x0;
|
|
|
|
destRect.right = x1;
|
|
|
|
|
|
|
|
if (srcFormat == D3DFMT_A8R8G8B8)
|
|
|
|
{
|
|
|
|
const uint8 *src = &(tex.getPixels(srcMipmap)[0]);
|
|
|
|
|
|
|
|
// Fill the temp buffer with BGRA info
|
|
|
|
const sint lineWidth = x1-x0;
|
|
|
|
_TempBuffer.resize (((y1-y0)*lineWidth)<<2);
|
|
|
|
uint8 *dest = &(_TempBuffer[0]);
|
|
|
|
uint line;
|
|
|
|
for (line=y0; line<(uint)y1; line++)
|
|
|
|
{
|
|
|
|
copyRGBA2BGRA ((uint32*)dest, (uint32*)(src+line*lineSize+(x0<<2)), lineWidth);
|
|
|
|
dest += lineWidth<<2;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Upload the texture part
|
|
|
|
RECT srcRect;
|
|
|
|
srcRect.top = 0;
|
|
|
|
srcRect.bottom = y1-y0;
|
|
|
|
srcRect.left = 0;
|
|
|
|
srcRect.right = lineWidth;
|
|
|
|
if (D3DXLoadSurfaceFromMemory (pDestSurface, NULL, &destRect, &(_TempBuffer[0]), srcFormat,
|
|
|
|
lineWidth<<2, NULL, &srcRect, D3DX_FILTER_NONE, 0) != D3D_OK)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
RECT srcRect;
|
|
|
|
srcRect.top = y0;
|
|
|
|
srcRect.bottom = y1;
|
|
|
|
srcRect.left = x0;
|
|
|
|
srcRect.right = x1;
|
|
|
|
const uint8 *src = &(tex.getPixels(srcMipmap)[0]);
|
|
|
|
if (D3DXLoadSurfaceFromMemory (pDestSurface, NULL, &destRect, src, srcFormat,
|
|
|
|
lineSize, NULL, &srcRect, D3DX_FILTER_NONE, 0) != D3D_OK)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
pDestSurface->Release();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ***************************************************************************
|
|
|
|
|
|
|
|
bool CDriverD3D::isTextureExist(const ITexture&tex)
|
|
|
|
{
|
|
|
|
H_AUTO_D3D(CDriverD3D_isTextureExist)
|
|
|
|
bool result;
|
|
|
|
|
|
|
|
// Create the shared Name.
|
|
|
|
std::string name;
|
|
|
|
getTextureShareName (tex, name);
|
|
|
|
|
|
|
|
{
|
|
|
|
CSynchronized<TTexDrvInfoPtrMap>::CAccessor access(&_SyncTexDrvInfos);
|
|
|
|
TTexDrvInfoPtrMap &rTexDrvInfos = access.value();
|
|
|
|
result = (rTexDrvInfos.find(name) != rTexDrvInfos.end());
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ***************************************************************************
|
|
|
|
|
|
|
|
void CDriverD3D::swapTextureHandle(ITexture &tex0, ITexture &tex1)
|
|
|
|
{
|
|
|
|
H_AUTO_D3D(CDriverD3D_swapTextureHandle)
|
|
|
|
// ensure creation of both texture
|
|
|
|
setupTexture(tex0);
|
|
|
|
setupTexture(tex1);
|
|
|
|
|
|
|
|
// avoid any problem, disable all textures
|
|
|
|
for(uint stage=0; stage<inlGetNumTextStages() ; stage++)
|
|
|
|
{
|
|
|
|
setTexture (stage, (LPDIRECT3DBASETEXTURE9)NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
// get the handle.
|
|
|
|
CTextureDrvInfosD3D *t0= getTextureD3D(tex0);
|
|
|
|
CTextureDrvInfosD3D *t1= getTextureD3D(tex1);
|
|
|
|
|
|
|
|
/* Swap contents. Can't swap directly the pointers cause would have to change all CTextureDrvShare which point on
|
|
|
|
Can't do swap(*t0, *t1), because must keep the correct _DriverIterator
|
|
|
|
*/
|
|
|
|
swap(t0->Texture, t1->Texture);
|
|
|
|
swap(t0->Texture2d, t1->Texture2d);
|
|
|
|
swap(t0->TextureCube, t1->TextureCube);
|
|
|
|
swap(t0->DestFormat, t1->DestFormat);
|
|
|
|
swap(t0->Width, t1->Width);
|
|
|
|
swap(t0->Height, t1->Height);
|
|
|
|
swap(t0->SrcCompressed, t1->SrcCompressed);
|
|
|
|
swap(t0->IsCube, t1->IsCube);
|
|
|
|
swap(t0->Levels, t1->Levels);
|
|
|
|
swap(t0->FirstMipMap, t1->FirstMipMap);
|
|
|
|
swap(t0->TextureMemory, t1->TextureMemory);
|
|
|
|
swap(t0->WrapS, t1->WrapS);
|
|
|
|
swap(t0->WrapT, t1->WrapT);
|
|
|
|
swap(t0->MagFilter, t1->MagFilter);
|
|
|
|
swap(t0->MinFilter, t1->MinFilter);
|
|
|
|
swap(t0->MipFilter, t1->MipFilter);
|
|
|
|
}
|
|
|
|
|
|
|
|
// ***************************************************************************
|
|
|
|
|
|
|
|
uint CDriverD3D::getTextureHandle(const ITexture &tex)
|
|
|
|
{
|
|
|
|
H_AUTO_D3D(CDriverD3D_getTextureHandle)
|
|
|
|
// If DrvShare not setuped
|
|
|
|
if(!tex.TextureDrvShare)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
CTextureDrvInfosD3D *d3dtext= getTextureD3D(const_cast<ITexture&>(tex));
|
|
|
|
|
|
|
|
// If DrvInfo not setuped
|
|
|
|
if(!d3dtext)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return (uint)(d3dtext->Texture);
|
|
|
|
}
|
|
|
|
|
|
|
|
// ***************************************************************************
|
|
|
|
|
|
|
|
bool CDriverD3D::setRenderTarget (ITexture *tex, uint32 /* x */, uint32 /* y */, uint32 /* width */, uint32 /* height */, uint32 mipmapLevel, uint32 cubeFace)
|
|
|
|
{
|
|
|
|
H_AUTO_D3D(CDriverD3D_setRenderTarget )
|
|
|
|
// Check the texture is a render target
|
|
|
|
if (tex)
|
|
|
|
nlassertex (tex->getRenderTarget(), ("The texture must be a render target. Call ITexture::setRenderTarget(true)."));
|
|
|
|
|
|
|
|
if (tex == NULL)
|
|
|
|
{
|
|
|
|
_InvertCullMode = false;
|
|
|
|
if (_BackBuffer)
|
|
|
|
{
|
|
|
|
setRenderTarget (_BackBuffer, NULL, 0, 0);
|
|
|
|
_BackBuffer->Release();
|
|
|
|
_BackBuffer = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
_InvertCullMode = true;
|
|
|
|
if (!_BackBuffer)
|
|
|
|
{
|
|
|
|
updateRenderVariables ();
|
|
|
|
_DeviceInterface->GetRenderTarget (0, &_BackBuffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Alread setuped ?
|
|
|
|
if (tex->TextureDrvShare)
|
|
|
|
{
|
|
|
|
// Get texture info
|
|
|
|
CTextureDrvInfosD3D *d3dtext = getTextureD3D(*tex);
|
|
|
|
|
|
|
|
// Renderable ? Erase and rebuild
|
|
|
|
if (!d3dtext->RenderTarget)
|
|
|
|
// Touch the texture
|
|
|
|
tex->touch();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Setup the new texture
|
|
|
|
bool nTmp;
|
|
|
|
if (!setupTextureEx (*tex, false, nTmp, false))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// Get texture info
|
|
|
|
CTextureDrvInfosD3D *d3dtext = getTextureD3D(*tex);
|
|
|
|
|
|
|
|
// Setup texture for texture rendering
|
|
|
|
IDirect3DSurface9 *pDestSurface;
|
|
|
|
bool surfaceOk = false;
|
|
|
|
if (!d3dtext->IsCube)
|
|
|
|
surfaceOk = d3dtext->Texture2d->GetSurfaceLevel(mipmapLevel, &pDestSurface) == D3D_OK;
|
|
|
|
else
|
|
|
|
surfaceOk = d3dtext->TextureCube->GetCubeMapSurface(RemapCubeFaceTypeNeL2D3D[cubeFace], mipmapLevel, &pDestSurface) == D3D_OK;
|
|
|
|
if (surfaceOk)
|
|
|
|
{
|
|
|
|
setRenderTarget (pDestSurface, tex, (uint8)mipmapLevel, (uint8)cubeFace);
|
|
|
|
pDestSurface->Release();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Handle backside
|
|
|
|
if (!_DoubleSided)
|
|
|
|
{
|
|
|
|
if (_CullMode == CCW)
|
|
|
|
{
|
|
|
|
setRenderState (D3DRS_CULLMODE, _InvertCullMode?D3DCULL_CCW:D3DCULL_CW);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
setRenderState (D3DRS_CULLMODE, _InvertCullMode?D3DCULL_CW:D3DCULL_CCW);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
2013-07-01 22:53:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ITexture *CDriverD3D::getRenderTarget() const
|
|
|
|
{
|
|
|
|
return _RenderTarget.Texture;
|
2012-05-29 13:31:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ***************************************************************************
|
|
|
|
|
|
|
|
bool CDriverD3D::copyTargetToTexture (ITexture * /* tex */, uint32 /* offsetx */, uint32 /* offsety */, uint32 /* x */, uint32 /* y */, uint32 /* width */,
|
|
|
|
uint32 /* height */, uint32 /* mipmapLevel */)
|
|
|
|
{
|
|
|
|
H_AUTO_D3D(CDriverD3D_copyTargetToTexture)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ***************************************************************************
|
|
|
|
|
|
|
|
bool CDriverD3D::getRenderTargetSize (uint32 &width, uint32 &height)
|
|
|
|
{
|
|
|
|
H_AUTO_D3D(CDriverD3D_getRenderTargetSize)
|
|
|
|
// Target is the frame buffer ?
|
|
|
|
if (_RenderTarget.Texture)
|
|
|
|
{
|
|
|
|
CTextureDrvInfosD3D* d3dtext = getTextureD3D(*_RenderTarget.Texture);
|
|
|
|
width = max ((uint32)1, (uint32)(d3dtext->Width >> (_RenderTarget.Level)));
|
|
|
|
height = max ((uint32)1, (uint32)(d3dtext->Height >> (_RenderTarget.Level)));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
getWindowSize (width, height);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ***************************************************************************
|
|
|
|
|
|
|
|
|
|
|
|
} // NL3D
|