- Added support for texture cube in OpenGL driver.

- Fixed issue related to regenerateMipMapLevels in OpenGL driver.
- Added missing files to VS2012 project.

git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/branches/ogl-es@4610 dfc29bdd-3216-0410-991c-e03cc46cb475
master
nadro 2013-11-18 22:41:30 +00:00
parent 2d4193888e
commit 5dca9a0a06
12 changed files with 454 additions and 114 deletions

View File

@ -133,6 +133,9 @@ namespace video
//! Support for ETC2 compressed textures.
EVDF_TEXTURE_COMPRESSED_ETC2,
//! Support for cube map textures.
EVDF_TEXTURE_CUBE_MAP,
//! Only used for counting the elements of this enum
EVDF_COUNT
};

View File

@ -86,6 +86,38 @@ enum E_TEXTURE_LOCK_MODE
ETLM_WRITE_ONLY
};
//! Enumeration describing the type of ITexture.
enum E_TEXTURE_TYPE
{
//! 2D texture.
ETT_2D,
//! Cube texture.
ETT_CUBE
};
//! Enumeration describing the type of cube texture surfaces.
enum E_TEXTURE_CUBE_SURFACE
{
//! Positive x-face of the cubemap
ETCS_POSX = 0,
//! Negative x-face of the cubemap
ETCS_NEGX = 1,
//! Positive y-face of the cubemap
ETCS_POSY = 2,
//! Negative y-face of the cubemap
ETCS_NEGY = 3,
//! Positive z-face of the cubemap
ETCS_POSZ = 4,
//! Negative z-face of the cubemap
ETCS_NEGZ = 5
};
//! Interface of a Video Driver dependent Texture.
/** An ITexture is created by an IVideoDriver by using IVideoDriver::addTexture
or IVideoDriver::getTexture. After that, the texture may only be used by this
@ -100,7 +132,7 @@ class ITexture : public virtual IReferenceCounted
public:
//! constructor
ITexture(const io::path& name) : NamedPath(name)
ITexture(const io::path& name, E_TEXTURE_TYPE type = ETT_2D) : NamedPath(name), Type(type)
{
}
@ -189,6 +221,9 @@ public:
//! Get name of texture (in most cases this is the filename)
const io::SNamedPath& getName() const { return NamedPath; }
//! Returns the type of texture
E_TEXTURE_TYPE getType() const { return Type; }
protected:
@ -209,6 +244,8 @@ protected:
}
io::SNamedPath NamedPath;
E_TEXTURE_TYPE Type;
};

View File

@ -427,6 +427,21 @@ namespace video
should not be dropped. See IReferenceCounted::drop() for more
information. */
virtual ITexture* addTexture(const io::path& name, IImage* image, void* mipmapData=0) = 0;
//! Creates a cube texture from loaded IImages.
/** \param name A name for the texture. Later calls of
getTexture() with this name will return this texture
\param posXImage Image (positive X) the texture is created from.
\param negXImage Image (negative X) the texture is created from.
\param posYImage Image (positive Y) the texture is created from.
\param negYImage Image (negative Y) the texture is created from.
\param posZImage Image (positive Z) the texture is created from.
\param negZImage Image (negative Z) the texture is created from.
\return Pointer to the newly created texture. This pointer
should not be dropped. See IReferenceCounted::drop() for more
information. */
virtual ITexture* addTextureCube(const io::path& name, IImage* posXImage, IImage* negXImage,
IImage* posYImage, IImage* negYImage, IImage* posZImage, IImage* negZImage) = 0;
//! Adds a new render target texture to the texture cache.
/** \param size Size of the texture, in pixels. Width and

View File

@ -562,22 +562,6 @@ video::ITexture* CNullDriver::findTexture(const io::path& filename)
}
//! Creates a texture from a loaded IImage.
ITexture* CNullDriver::addTexture(const io::path& name, IImage* image, void* mipmapData)
{
if ( 0 == name.size() || !image)
return 0;
ITexture* t = createDeviceDependentTexture(image, name, mipmapData);
if (t)
{
addTexture(t);
t->drop();
}
return t;
}
//! creates a Texture
ITexture* CNullDriver::addTexture(const core::dimension2d<u32>& size,
const io::path& name, ECOLOR_FORMAT format)
@ -605,6 +589,37 @@ ITexture* CNullDriver::addTexture(const core::dimension2d<u32>& size,
}
//! Creates a texture from a loaded IImage.
ITexture* CNullDriver::addTexture(const io::path& name, IImage* image, void* mipmapData)
{
if ( 0 == name.size() || !image)
return 0;
ITexture* t = createDeviceDependentTexture(image, name, mipmapData);
if (t)
{
addTexture(t);
t->drop();
}
return t;
}
//! Creates a cube texture from loaded IImages.
ITexture* CNullDriver::addTextureCube(const io::path& name, IImage* posXImage, IImage* negXImage,
IImage* posYImage, IImage* negYImage, IImage* posZImage, IImage* negZImage)
{
if ( 0 == name.size() || !posXImage || !negXImage || !posYImage || !negYImage || !posZImage || !negZImage)
return 0;
ITexture* t = createDeviceDependentTextureCube(name, posXImage, negXImage, posYImage, negYImage, posZImage, negZImage);
if (t)
{
addTexture(t);
t->drop();
}
return t;
}
//! returns a device dependent texture from a software surface (IImage)
//! THIS METHOD HAS TO BE OVERRIDDEN BY DERIVED DRIVERS WITH OWN TEXTURES
@ -614,6 +629,14 @@ ITexture* CNullDriver::createDeviceDependentTexture(IImage* surface, const io::p
}
//! returns a device dependent texture from a software surface (IImage)
//! THIS METHOD HAS TO BE OVERRIDDEN BY DERIVED DRIVERS WITH OWN TEXTURES
ITexture* CNullDriver::createDeviceDependentTextureCube(const io::path& name, IImage* posXImage, IImage* negXImage,
IImage* posYImage, IImage* negYImage, IImage* posZImage, IImage* negZImage)
{
return new SDummyTexture(name);
}
//! set or reset special render targets
bool CNullDriver::setRenderTarget(video::E_RENDER_TARGET target, bool clearTarget,
bool clearZBuffer, SColor color)
@ -2444,6 +2467,32 @@ bool CNullDriver::checkColorFormat(ECOLOR_FORMAT format, const core::dimension2d
}
// Check support for compression texture format.
bool CNullDriver::checkTextureCube(IImage* posXImage, IImage* negXImage, IImage* posYImage, IImage* negYImage,
IImage* posZImage, IImage* negZImage) const
{
if (!queryFeature(EVDF_TEXTURE_CUBE_MAP))
return false;
IImage* image[6] = {
posXImage,
negXImage,
posYImage,
negYImage,
posZImage,
negZImage
};
for (u32 i = 1; i < 6; ++i)
{
if (image[0]->getDimension() != image[i]->getDimension() || image[0]->getColorFormat() != image[i]->getColorFormat())
return false;
}
return true;
}
//! creates a video driver
IVideoDriver* createNullDriver(io::IFileSystem* io, const core::dimension2d<u32>& screenSize)
{

View File

@ -100,6 +100,13 @@ namespace video
//! creates a Texture
virtual ITexture* addTexture(const core::dimension2d<u32>& size, const io::path& name, ECOLOR_FORMAT format = ECF_A8R8G8B8);
//! Creates a texture from a loaded IImage.
virtual ITexture* addTexture(const io::path& name, IImage* image, void* mipmapData=0);
//! Creates a cube texture from loaded IImages.
virtual ITexture* addTextureCube(const io::path& name, IImage* posXImage, IImage* negXImage,
IImage* posYImage, IImage* negYImage, IImage* posZImage, IImage* negZImage);
//! sets a render target
virtual bool setRenderTarget(video::ITexture* texture, bool clearBackBuffer,
bool clearZBuffer, SColor color);
@ -667,17 +674,19 @@ namespace video
void deleteAllTextures();
//! opens the file and loads it into the surface
video::ITexture* loadTextureFromFile(io::IReadFile* file, const io::path& hashName = "");
ITexture* loadTextureFromFile(io::IReadFile* file, const io::path& hashName = "");
//! adds a surface, not loaded or created by the Irrlicht Engine
void addTexture(video::ITexture* surface);
//! Creates a texture from a loaded IImage.
virtual ITexture* addTexture(const io::path& name, IImage* image, void* mipmapData=0);
void addTexture(ITexture* surface);
//! 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, void* mipmapData=0);
virtual ITexture* createDeviceDependentTexture(IImage* surface, const io::path& name, 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 ITexture* createDeviceDependentTextureCube(const io::path& name, IImage* posXImage, IImage* negXImage,
IImage* posYImage, IImage* negYImage, IImage* posZImage, IImage* negZImage);
//! checks triangle count and print warning if wrong
bool checkPrimitiveCount(u32 prmcnt) const;
@ -694,6 +703,10 @@ namespace video
// Check support for compression texture format.
bool checkColorFormat(ECOLOR_FORMAT format, const core::dimension2d<u32>& textureSize) const;
// Check support for compression texture format.
bool checkTextureCube(IImage* posXImage, IImage* negXImage, IImage* posYImage, IImage* negYImage,
IImage* posZImage, IImage* negZImage) const;
//! normal map lookup 32 bit version
inline f32 nml32(int x, int y, int pitch, int height, s32 *p) const
{

View File

@ -2188,7 +2188,7 @@ bool COpenGLDriver::disableTextures(u32 fromStage)
for (u32 i=fromStage; i<MaxSupportedTextures; ++i)
{
result &= setActiveTexture(i, 0);
BridgeCalls->setTexture(i, true);
BridgeCalls->setTexture(i, GL_TEXTURE_2D, true);
}
return result;
}
@ -2227,7 +2227,7 @@ inline void COpenGLDriver::getGLTextureMatrix(GLfloat *o, const core::matrix4& m
//! returns a device dependent texture from a software surface (IImage)
video::ITexture* COpenGLDriver::createDeviceDependentTexture(IImage* surface, const io::path& name, void* mipmapData)
ITexture* COpenGLDriver::createDeviceDependentTexture(IImage* surface, const io::path& name, void* mipmapData)
{
COpenGLTexture* texture = 0;
@ -2238,6 +2238,23 @@ video::ITexture* COpenGLDriver::createDeviceDependentTexture(IImage* surface, co
}
//! returns a device dependent texture from a software surface (IImage)
ITexture* COpenGLDriver::createDeviceDependentTextureCube(const io::path& name, IImage* posXImage, IImage* negXImage,
IImage* posYImage, IImage* negYImage, IImage* posZImage, IImage* negZImage)
{
COpenGLTexture* texture = 0;
if (posXImage && negXImage && posYImage && negYImage && posZImage && negZImage &&
checkTextureCube(posXImage, negXImage, posYImage, negYImage, posZImage, negZImage) &&
checkColorFormat(posXImage->getColorFormat(), posXImage->getDimension()))
{
texture = new COpenGLTexture(name, posXImage, negXImage, posYImage, negYImage, posZImage, negZImage, this);
}
return texture;
}
//! Sets a material. All 3d drawing functions draw geometry now using this material.
void COpenGLDriver::setMaterial(const SMaterial& material)
{
@ -2864,6 +2881,7 @@ void COpenGLDriver::setTextureRenderStates(const SMaterial& material, bool reset
for (s32 i = MaxTextureUnits-1; i>= 0; --i)
{
const COpenGLTexture* tmpTexture = static_cast<const COpenGLTexture*>(CurrentTexture[i]);
GLenum tmpTextureType = (tmpTexture) ? tmpTexture->getOpenGLTextureType() : GL_TEXTURE_2D;
if(fixedPipeline)
{
@ -2872,13 +2890,13 @@ void COpenGLDriver::setTextureRenderStates(const SMaterial& material, bool reset
if (!CurrentTexture[i])
{
BridgeCalls->setTexture(i, fixedPipeline);
BridgeCalls->setTexture(i, tmpTextureType, fixedPipeline);
continue;
}
else
{
BridgeCalls->setTexture(i, fixedPipeline);
BridgeCalls->setTexture(i, tmpTextureType, fixedPipeline);
setTransform ((E_TRANSFORMATION_STATE) (ETS_TEXTURE_0 + i), material.getTextureMatrix(i));
}
@ -2887,7 +2905,7 @@ void COpenGLDriver::setTextureRenderStates(const SMaterial& material, bool reset
{
if (CurrentTexture[i])
{
BridgeCalls->setTexture(i, fixedPipeline);
BridgeCalls->setTexture(i, tmpTextureType, fixedPipeline);
}
else
continue;
@ -2904,10 +2922,10 @@ void COpenGLDriver::setTextureRenderStates(const SMaterial& material, bool reset
if (material.TextureLayer[i].LODBias)
{
const float tmp = core::clamp(material.TextureLayer[i].LODBias * 0.125f, -MaxTextureLODBias, MaxTextureLODBias);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, tmp);
glTexParameterf(tmpTextureType, GL_TEXTURE_LOD_BIAS, tmp);
}
else
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, 0.f);
glTexParameterf(tmpTextureType, GL_TEXTURE_LOD_BIAS, 0.f);
tmpTexture->getStatesCache().LODBias = material.TextureLayer[i].LODBias;
}
@ -2938,7 +2956,7 @@ void COpenGLDriver::setTextureRenderStates(const SMaterial& material, bool reset
if(!tmpTexture->getStatesCache().IsCached || material.TextureLayer[i].BilinearFilter != tmpTexture->getStatesCache().BilinearFilter ||
material.TextureLayer[i].TrilinearFilter != tmpTexture->getStatesCache().TrilinearFilter)
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
glTexParameteri(tmpTextureType, GL_TEXTURE_MAG_FILTER,
(material.TextureLayer[i].BilinearFilter || material.TextureLayer[i].TrilinearFilter) ? GL_LINEAR : GL_NEAREST);
tmpTexture->getStatesCache().BilinearFilter = material.TextureLayer[i].BilinearFilter;
@ -2950,7 +2968,7 @@ void COpenGLDriver::setTextureRenderStates(const SMaterial& material, bool reset
if(!tmpTexture->getStatesCache().IsCached || material.TextureLayer[i].BilinearFilter != tmpTexture->getStatesCache().BilinearFilter ||
material.TextureLayer[i].TrilinearFilter != tmpTexture->getStatesCache().TrilinearFilter || !tmpTexture->getStatesCache().MipMapStatus)
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
glTexParameteri(tmpTextureType, GL_TEXTURE_MIN_FILTER,
material.TextureLayer[i].TrilinearFilter ? GL_LINEAR_MIPMAP_LINEAR :
material.TextureLayer[i].BilinearFilter ? GL_LINEAR_MIPMAP_NEAREST :
GL_NEAREST_MIPMAP_NEAREST);
@ -2965,7 +2983,7 @@ void COpenGLDriver::setTextureRenderStates(const SMaterial& material, bool reset
if(!tmpTexture->getStatesCache().IsCached || material.TextureLayer[i].BilinearFilter != tmpTexture->getStatesCache().BilinearFilter ||
material.TextureLayer[i].TrilinearFilter != tmpTexture->getStatesCache().TrilinearFilter || tmpTexture->getStatesCache().MipMapStatus)
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
glTexParameteri(tmpTextureType, GL_TEXTURE_MIN_FILTER,
(material.TextureLayer[i].BilinearFilter || material.TextureLayer[i].TrilinearFilter) ? GL_LINEAR : GL_NEAREST);
tmpTexture->getStatesCache().BilinearFilter = material.TextureLayer[i].BilinearFilter;
@ -2978,7 +2996,7 @@ void COpenGLDriver::setTextureRenderStates(const SMaterial& material, bool reset
if (FeatureAvailable[IRR_EXT_texture_filter_anisotropic] &&
(!tmpTexture->getStatesCache().IsCached || material.TextureLayer[i].AnisotropicFilter != tmpTexture->getStatesCache().AnisotropicFilter))
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT,
glTexParameteri(tmpTextureType, GL_TEXTURE_MAX_ANISOTROPY_EXT,
material.TextureLayer[i].AnisotropicFilter>1 ? core::min_(MaxAnisotropy, material.TextureLayer[i].AnisotropicFilter) : 1);
tmpTexture->getStatesCache().AnisotropicFilter = material.TextureLayer[i].AnisotropicFilter;
@ -2987,13 +3005,13 @@ void COpenGLDriver::setTextureRenderStates(const SMaterial& material, bool reset
if(!tmpTexture->getStatesCache().IsCached || material.TextureLayer[i].TextureWrapU != tmpTexture->getStatesCache().WrapU)
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, getTextureWrapMode(material.TextureLayer[i].TextureWrapU));
glTexParameteri(tmpTextureType, GL_TEXTURE_WRAP_S, getTextureWrapMode(material.TextureLayer[i].TextureWrapU));
tmpTexture->getStatesCache().WrapU = material.TextureLayer[i].TextureWrapU;
}
if(!tmpTexture->getStatesCache().IsCached || material.TextureLayer[i].TextureWrapV != tmpTexture->getStatesCache().WrapV)
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, getTextureWrapMode(material.TextureLayer[i].TextureWrapV));
glTexParameteri(tmpTextureType, GL_TEXTURE_WRAP_T, getTextureWrapMode(material.TextureLayer[i].TextureWrapV));
tmpTexture->getStatesCache().WrapV = material.TextureLayer[i].TextureWrapV;
}
@ -4608,6 +4626,7 @@ COpenGLCallBridge::COpenGLCallBridge(COpenGLDriver* driver) : Driver(driver),
for (u32 i = 0; i < MATERIAL_MAX_TEXTURES; ++i)
{
Texture[i] = 0;
TextureType[i] = GL_TEXTURE_2D;
TextureFixedPipeline[i] = true;
}
@ -4811,30 +4830,43 @@ void COpenGLCallBridge::setClientActiveTexture(GLenum texture)
}
}
void COpenGLCallBridge::setTexture(u32 stage, bool fixedPipeline)
void COpenGLCallBridge::getTexture(u32 stage, GLenum& type, bool& fixedPipeline)
{
if (stage < MATERIAL_MAX_TEXTURES)
{
if((fixedPipeline && TextureFixedPipeline[stage] != fixedPipeline) || Texture[stage] != Driver->CurrentTexture[stage])
type = TextureType[stage];
fixedPipeline = TextureFixedPipeline[stage];
}
}
void COpenGLCallBridge::setTexture(u32 stage, GLenum type, bool fixedPipeline)
{
if (stage < MATERIAL_MAX_TEXTURES)
{
if((fixedPipeline && TextureFixedPipeline[stage] != fixedPipeline) || Texture[stage] != Driver->CurrentTexture[stage] || type != TextureType[stage])
{
setActiveTexture(GL_TEXTURE0_ARB + stage);
if(Driver->CurrentTexture[stage])
{
if(fixedPipeline)
glEnable(GL_TEXTURE_2D);
{
glDisable(TextureType[stage]);
glEnable(type);
}
glBindTexture(GL_TEXTURE_2D, static_cast<const COpenGLTexture*>(Driver->CurrentTexture[stage])->getOpenGLTextureName());
glBindTexture(type, static_cast<const COpenGLTexture*>(Driver->CurrentTexture[stage])->getOpenGLTextureName());
}
else
{
glBindTexture(GL_TEXTURE_2D, 0);
glBindTexture(type, 0);
if(fixedPipeline)
glDisable(GL_TEXTURE_2D);
glDisable(TextureType[stage]);
}
TextureFixedPipeline[stage] = fixedPipeline;
TextureType[stage] = type;
Texture[stage] = Driver->CurrentTexture[stage];
}
}

View File

@ -441,8 +441,13 @@ namespace video
//! inits the parts of the open gl driver used on all platforms
bool genericDriverInit();
//! returns a device dependent texture from a software surface (IImage)
virtual video::ITexture* createDeviceDependentTexture(IImage* surface, const io::path& name, void* mipmapData);
virtual ITexture* createDeviceDependentTexture(IImage* surface, const io::path& name, void* mipmapData);
//! returns a device dependent texture from a software surface (IImage)
virtual ITexture* createDeviceDependentTextureCube(const io::path& name, IImage* posXImage, IImage* negXImage,
IImage* posYImage, IImage* negYImage, IImage* posZImage, IImage* negZImage);
//! creates a transposed matrix in supplied GLfloat array to pass to OpenGL
inline void getGLMatrix(GLfloat gl_matrix[16], const core::matrix4& m);
@ -671,7 +676,9 @@ namespace video
void setClientActiveTexture(GLenum texture);
void setTexture(u32 stage, bool fixedPipeline);
void getTexture(u32 stage, GLenum& type, bool& fixedPipeline);
void setTexture(u32 stage, GLenum type, bool fixedPipeline);
private:
COpenGLDriver* Driver;
@ -702,6 +709,7 @@ namespace video
GLenum ClientActiveTexture;
const ITexture* Texture[MATERIAL_MAX_TEXTURES];
GLenum TextureType[MATERIAL_MAX_TEXTURES];
bool TextureFixedPipeline[MATERIAL_MAX_TEXTURES];
};

View File

@ -797,6 +797,8 @@ bool COpenGLExtensionHandler::queryFeature(E_VIDEO_DRIVER_FEATURE feature) const
return false;
case EVDF_TEXTURE_COMPRESSED_ETC2:
return FeatureAvailable[IRR_ARB_ES3_compatibility];
case EVDF_TEXTURE_CUBE_MAP:
return FeatureAvailable[IRR_ARB_texture_cube_map];
default:
return false;
};

View File

@ -1,4 +1,4 @@
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// Copyright (C) 2002-2012 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
@ -21,11 +21,11 @@ namespace video
//! constructor for usual textures
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),
: ITexture(name, ETT_2D), ColorFormat(ECF_A8R8G8B8), Driver(driver), Image(0), MipImage(0),
TextureName(0), TextureType(GL_TEXTURE_2D), InternalFormat(GL_RGBA), PixelFormat(GL_BGRA_EXT),
PixelType(GL_UNSIGNED_BYTE), MipLevelStored(0), MipmapLegacyMode(true),
IsRenderTarget(false), IsCompressed(false), AutomaticMipmapUpdate(false),
ReadOnlyLock(false), KeepImage(false)
ReadOnlyLock(false), KeepImage(true)
{
#ifdef _DEBUG
setDebugName("COpenGLTexture");
@ -36,39 +36,112 @@ COpenGLTexture::COpenGLTexture(IImage* origImage, const io::path& name, void* mi
if (IsCompressed)
{
Image = origImage;
Image->grab();
Image.push_back(origImage);
Image[0]->grab();
KeepImage = false;
}
else if (ImageSize==TextureSize)
{
Image = Driver->createImage(ColorFormat, ImageSize);
origImage->copyTo(Image);
Image.push_back(Driver->createImage(ColorFormat, ImageSize));
origImage->copyTo(Image[0]);
}
else
{
Image = Driver->createImage(ColorFormat, TextureSize);
origImage->copyToScaling(Image);
Image.push_back(Driver->createImage(ColorFormat, TextureSize));
origImage->copyToScaling(Image[0]);
}
glGenTextures(1, &TextureName);
uploadTexture(true, mipmapData);
uploadTexture(true, 0, true, mipmapData);
if (!KeepImage)
{
Image->drop();
Image=0;
Image[0]->drop();
Image.clear();
}
}
//! constructor for cube textures
COpenGLTexture::COpenGLTexture(const io::path& name, IImage* posXImage, IImage* negXImage, IImage* posYImage,
IImage* negYImage, IImage* posZImage, IImage* negZImage, COpenGLDriver* driver)
: ITexture(name, ETT_CUBE), ColorFormat(ECF_A8R8G8B8), Driver(driver), Image(0), MipImage(0),
TextureName(0), TextureType(GL_TEXTURE_CUBE_MAP), InternalFormat(GL_RGBA), PixelFormat(GL_BGRA_EXT),
PixelType(GL_UNSIGNED_BYTE), MipLevelStored(0), MipmapLegacyMode(true),
IsRenderTarget(false), IsCompressed(false), AutomaticMipmapUpdate(false),
ReadOnlyLock(false), KeepImage(true)
{
#ifdef _DEBUG
setDebugName("COpenGLTexture");
#endif
HasMipMaps = Driver->getTextureCreationFlag(ETCF_CREATE_MIP_MAPS);
getImageValues(posXImage);
if (IsCompressed)
{
Image.push_back(posXImage);
Image.push_back(negXImage);
Image.push_back(posYImage);
Image.push_back(negYImage);
Image.push_back(posZImage);
Image.push_back(negZImage);
for (u32 i = 0; i < 6; ++i)
Image[i]->grab();
KeepImage = false;
}
else if (ImageSize==TextureSize)
{
for (u32 i = 0; i < 6; ++i)
Image.push_back(Driver->createImage(ColorFormat, ImageSize));
posXImage->copyTo(Image[0]);
negXImage->copyTo(Image[1]);
posYImage->copyTo(Image[2]);
negYImage->copyTo(Image[3]);
posZImage->copyTo(Image[4]);
negZImage->copyTo(Image[5]);
}
else
{
for (u32 i = 0; i < 6; ++i)
Image.push_back(Driver->createImage(ColorFormat, ImageSize));
posXImage->copyToScaling(Image[0]);
negXImage->copyToScaling(Image[1]);
posYImage->copyToScaling(Image[2]);
negYImage->copyToScaling(Image[3]);
posZImage->copyToScaling(Image[4]);
negZImage->copyToScaling(Image[5]);
}
glGenTextures(1, &TextureName);
for (u32 i = 0; i < 5; ++i)
uploadTexture(true, i, false);
uploadTexture(true, 5, true);
if (!KeepImage)
{
for (u32 i = 0; i < Image.size(); ++i)
Image[i]->drop();
Image.clear();
}
}
//! 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), MipImage(0),
TextureName(0), InternalFormat(GL_RGBA), PixelFormat(GL_BGRA_EXT),
: ITexture(name, ETT_2D), ColorFormat(ECF_A8R8G8B8), Driver(driver), Image(0), MipImage(0),
TextureName(0), TextureType(GL_TEXTURE_2D), InternalFormat(GL_RGBA), PixelFormat(GL_BGRA_EXT),
PixelType(GL_UNSIGNED_BYTE), MipLevelStored(0), HasMipMaps(true),
MipmapLegacyMode(true), IsRenderTarget(false), IsCompressed(false),
AutomaticMipmapUpdate(false), ReadOnlyLock(false), KeepImage(false)
AutomaticMipmapUpdate(false), ReadOnlyLock(false), KeepImage(true)
{
#ifdef _DEBUG
setDebugName("COpenGLTexture");
@ -83,7 +156,7 @@ COpenGLTexture::~COpenGLTexture()
if (Driver->CurrentTexture[i] == this)
{
Driver->setActiveTexture(i, 0);
Driver->getBridgeCalls()->setTexture(i, true);
Driver->getBridgeCalls()->setTexture(i, TextureType, true);
}
// Remove this texture from active materials as well
@ -99,8 +172,8 @@ COpenGLTexture::~COpenGLTexture()
if (TextureName)
glDeleteTextures(1, &TextureName);
if (Image)
Image->drop();
for (u32 i = 0; i < Image.size(); ++i)
Image[i]->drop();
}
@ -388,10 +461,10 @@ void COpenGLTexture::getImageValues(IImage* image)
//! copies the the texture into an open gl texture.
void COpenGLTexture::uploadTexture(bool newTexture, void* mipmapData, u32 level)
void COpenGLTexture::uploadTexture(bool newTexture, u32 imageNumber, bool regMipmap, void* mipmapData, u32 level)
{
// check which image needs to be uploaded
IImage* image = level?MipImage:Image;
IImage* image = level?MipImage:Image[imageNumber];
if (!image)
{
os::Printer::log("No image for OpenGL texture to upload", ELL_ERROR);
@ -408,7 +481,7 @@ void COpenGLTexture::uploadTexture(bool newTexture, void* mipmapData, u32 level)
InternalFormat = oldInternalFormat;
Driver->setActiveTexture(0, this);
Driver->getBridgeCalls()->setTexture(0, true);
Driver->getBridgeCalls()->setTexture(0, TextureType, true);
if (Driver->testGLError())
os::Printer::log("Could not bind Texture", ELL_ERROR);
@ -417,7 +490,7 @@ void COpenGLTexture::uploadTexture(bool newTexture, void* mipmapData, u32 level)
if (!level && newTexture)
{
// auto generate if possible and no mipmap data is given
if (!IsCompressed && HasMipMaps && !mipmapData && Driver->queryFeature(EVDF_MIP_MAP_AUTO_UPDATE))
if (!IsCompressed && HasMipMaps && !mipmapData && Driver->queryFeature(EVDF_MIP_MAP_AUTO_UPDATE) && regMipmap)
{
if (!Driver->queryFeature(EVDF_FRAMEBUFFER_OBJECT))
{
@ -429,7 +502,7 @@ void COpenGLTexture::uploadTexture(bool newTexture, void* mipmapData, u32 level)
else
glHint(GL_GENERATE_MIPMAP_HINT_SGIS, GL_DONT_CARE);
glTexParameteri( GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE );
glTexParameteri(TextureType, GL_GENERATE_MIPMAP, GL_TRUE );
MipmapLegacyMode=true;
AutomaticMipmapUpdate=true;
#endif
@ -457,8 +530,39 @@ void COpenGLTexture::uploadTexture(bool newTexture, void* mipmapData, u32 level)
StatesCache.TrilinearFilter = false;
StatesCache.MipMapStatus = false;
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering);
glTexParameteri(TextureType, GL_TEXTURE_MIN_FILTER, filtering);
glTexParameteri(TextureType, GL_TEXTURE_MAG_FILTER, filtering);
}
// get texture type
GLenum tmpTextureType = GL_TEXTURE_2D;
if (TextureType == GL_TEXTURE_CUBE_MAP)
{
switch(imageNumber)
{
case 0:
tmpTextureType = GL_TEXTURE_CUBE_MAP_POSITIVE_X;
break;
case 1:
tmpTextureType = GL_TEXTURE_CUBE_MAP_NEGATIVE_X;
break;
case 2:
tmpTextureType = GL_TEXTURE_CUBE_MAP_POSITIVE_Y;
break;
case 3:
tmpTextureType = GL_TEXTURE_CUBE_MAP_NEGATIVE_Y;
break;
case 4:
tmpTextureType = GL_TEXTURE_CUBE_MAP_POSITIVE_Z;
break;
case 5:
tmpTextureType = GL_TEXTURE_CUBE_MAP_NEGATIVE_Z;
break;
default:
break;
}
}
// now get image data and upload to GPU
@ -470,27 +574,27 @@ void COpenGLTexture::uploadTexture(bool newTexture, void* mipmapData, u32 level)
{
if (IsCompressed)
{
Driver->extGlCompressedTexImage2D(GL_TEXTURE_2D, 0, InternalFormat, image->getDimension().Width,
Driver->extGlCompressedTexImage2D(tmpTextureType, 0, InternalFormat, image->getDimension().Width,
image->getDimension().Height, 0, compressedImageSize, source);
}
else
glTexImage2D(GL_TEXTURE_2D, level, InternalFormat, image->getDimension().Width,
glTexImage2D(tmpTextureType, level, InternalFormat, image->getDimension().Width,
image->getDimension().Height, 0, PixelFormat, PixelType, source);
}
else
{
if (IsCompressed)
{
Driver->extGlCompressedTexSubImage2D(GL_TEXTURE_2D, level, 0, 0, image->getDimension().Width,
Driver->extGlCompressedTexSubImage2D(tmpTextureType, 0, 0, 0, image->getDimension().Width,
image->getDimension().Height, PixelFormat, compressedImageSize, source);
}
else
glTexSubImage2D(GL_TEXTURE_2D, level, 0, 0, image->getDimension().Width,
glTexSubImage2D(tmpTextureType, level, 0, 0, image->getDimension().Width,
image->getDimension().Height, PixelFormat, PixelType, source);
}
image->unlock();
if (!level && newTexture)
if (!level && newTexture && regMipmap)
{
if (IsCompressed && !mipmapData)
{
@ -518,8 +622,8 @@ void COpenGLTexture::uploadTexture(bool newTexture, void* mipmapData, u32 level)
StatesCache.TrilinearFilter = false;
StatesCache.MipMapStatus = false;
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filteringMipMaps);
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filtering);
glTexParameteri(TextureType, GL_TEXTURE_MIN_FILTER, filteringMipMaps);
glTexParameteri(TextureType, GL_TEXTURE_MAG_FILTER, filtering);
}
}
@ -527,18 +631,29 @@ void COpenGLTexture::uploadTexture(bool newTexture, void* mipmapData, u32 level)
os::Printer::log("Could not glTexImage2D", ELL_ERROR);
Driver->setActiveTexture(0, 0);
Driver->getBridgeCalls()->setTexture(0, true);
Driver->getBridgeCalls()->setTexture(0, TextureType, true);
}
//! lock function
void* COpenGLTexture::lock(E_TEXTURE_LOCK_MODE mode, u32 mipmapLevel)
{
if (IsCompressed) // TO-DO
if (IsCompressed || Type != ETT_2D) // TO-DO
return 0;
// store info about which image is locked
IImage* image = (mipmapLevel==0)?Image:MipImage;
IImage* image = 0;
if (mipmapLevel==0)
{
if (Image.size() > 0)
image = Image[0];
}
else
{
image = MipImage;
}
ReadOnlyLock |= (mode==ETLM_READ_ONLY);
MipLevelStored = mipmapLevel;
if (!ReadOnlyLock && mipmapLevel)
@ -547,7 +662,7 @@ void* COpenGLTexture::lock(E_TEXTURE_LOCK_MODE mode, u32 mipmapLevel)
if (Driver->queryFeature(EVDF_MIP_MAP_AUTO_UPDATE))
{
// do not automatically generate and update mipmaps
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_FALSE);
glTexParameteri(TextureType, GL_GENERATE_MIPMAP, GL_FALSE);
}
#endif
AutomaticMipmapUpdate=false;
@ -576,7 +691,14 @@ void* COpenGLTexture::lock(E_TEXTURE_LOCK_MODE mode, u32 mipmapLevel)
MipImage = image = Driver->createImage(ECF_A8R8G8B8, core::dimension2du(width,height));
}
else
Image = image = Driver->createImage(ECF_A8R8G8B8, ImageSize);
{
image = Driver->createImage(ECF_A8R8G8B8, ImageSize);
if (Image.size() == 0)
Image.push_back(image);
else
Image[0] = image;
}
ColorFormat = ECF_A8R8G8B8;
}
if (!image)
@ -589,9 +711,12 @@ void* COpenGLTexture::lock(E_TEXTURE_LOCK_MODE mode, u32 mipmapLevel)
return 0;
// we need to keep the correct texture bound later on
GLint tmpTexture;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &tmpTexture);
glBindTexture(GL_TEXTURE_2D, TextureName);
const COpenGLTexture* tmpTexture = static_cast<const COpenGLTexture*>(Driver->CurrentTexture[0]);
GLuint tmpTextureType = GL_TEXTURE_2D;
GLint tmpTextureName = (tmpTexture) ? tmpTexture->getOpenGLTextureName() : 0;
bool tmpFixedPipeline = false;
Driver->getBridgeCalls()->getTexture(0, tmpTextureType, tmpFixedPipeline);
glBindTexture(TextureType, TextureName);
// we need to flip textures vertical
// however, it seems that this does not hold for mipmap
@ -604,7 +729,7 @@ void* COpenGLTexture::lock(E_TEXTURE_LOCK_MODE mode, u32 mipmapLevel)
#endif
// download GPU data as ARGB8 to pixels;
glGetTexImage(GL_TEXTURE_2D, mipmapLevel, GL_BGRA_EXT, GL_UNSIGNED_BYTE, pixels);
glGetTexImage(TextureType, mipmapLevel, GL_BGRA_EXT, GL_UNSIGNED_BYTE, pixels);
if (!mipmapLevel)
{
@ -632,7 +757,7 @@ void* COpenGLTexture::lock(E_TEXTURE_LOCK_MODE mode, u32 mipmapLevel)
image->unlock();
//reset old bound texture
glBindTexture(GL_TEXTURE_2D, tmpTexture);
glBindTexture(tmpTextureType, tmpTextureName);
}
}
return image->lock();
@ -642,18 +767,29 @@ void* COpenGLTexture::lock(E_TEXTURE_LOCK_MODE mode, u32 mipmapLevel)
//! unlock function
void COpenGLTexture::unlock()
{
if (IsCompressed) // TO-DO
if (IsCompressed || Type != ETT_2D) // TO-DO
return;
// test if miplevel or main texture was locked
IImage* image = MipImage?MipImage:Image;
IImage* image = 0;
if (!MipImage)
{
if (Image.size() > 0)
image = Image[0];
}
else
{
image = MipImage;
}
if (!image)
return;
// unlock image to see changes
image->unlock();
// copy texture data to GPU
if (!ReadOnlyLock)
uploadTexture(false, 0, MipLevelStored);
uploadTexture(false, 0, true, 0, MipLevelStored);
ReadOnlyLock = false;
// cleanup local image
if (MipImage)
@ -663,12 +799,12 @@ void COpenGLTexture::unlock()
}
else if (!KeepImage)
{
Image->drop();
Image=0;
Image[0]->drop();
Image.clear();
}
// update information
if (Image)
ColorFormat=Image->getColorFormat();
if (Image.size() > 0)
ColorFormat=Image[0]->getColorFormat();
else
ColorFormat=ECF_A8R8G8B8;
}
@ -705,8 +841,8 @@ ECOLOR_FORMAT COpenGLTexture::getColorFormat() const
//! returns pitch of texture (in bytes)
u32 COpenGLTexture::getPitch() const
{
if (Image)
return Image->getPitch();
if (Image.size() > 0)
return Image[0]->getPitch();
else
return 0;
}
@ -719,6 +855,13 @@ GLuint COpenGLTexture::getOpenGLTextureName() const
}
//! return open gl texture type
GLenum COpenGLTexture::getOpenGLTextureType() const
{
return TextureType;
}
//! Returns whether this texture has mipmaps
bool COpenGLTexture::hasMipMaps() const
{
@ -746,23 +889,42 @@ void COpenGLTexture::regenerateMipMapLevels(void* mipmapData)
return;
// hardware doesn't support generate mipmaps for certain texture but image data doesn't exist or is wrong.
if (!AutomaticMipmapUpdate && (!Image || (Image && ((Image->getDimension().Width==1) && (Image->getDimension().Height==1)))))
if (!AutomaticMipmapUpdate && (Image.size() == 0 || (Image.size() > 0 && ((Image[0]->getDimension().Width==1) && (Image[0]->getDimension().Height==1)))))
return;
}
// hardware moethods for generate mipmaps.
if (!mipmapData && AutomaticMipmapUpdate && !MipmapLegacyMode)
{
glEnable(GL_TEXTURE_2D);
Driver->extGlGenerateMipmap(GL_TEXTURE_2D);
glEnable(TextureType);
const COpenGLTexture* tmpTexture = static_cast<const COpenGLTexture*>(Driver->CurrentTexture[0]);
GLuint tmpTextureType = GL_TEXTURE_2D;
GLint tmpTextureName = (tmpTexture) ? tmpTexture->getOpenGLTextureName() : 0;
bool tmpFixedPipeline = false;
Driver->getBridgeCalls()->getTexture(0, tmpTextureType, tmpFixedPipeline);
glBindTexture(TextureType, TextureName);
Driver->extGlGenerateMipmap(TextureType);
glBindTexture(tmpTextureType, tmpTextureName);
return;
}
// only 2D textures are supported in manual creation mipmaps process.
if (Type != ETT_2D)
return;
const COpenGLTexture* tmpTexture = static_cast<const COpenGLTexture*>(Driver->CurrentTexture[0]);
GLuint tmpTextureType = GL_TEXTURE_2D;
GLint tmpTextureName = (tmpTexture) ? tmpTexture->getOpenGLTextureName() : 0;
bool tmpFixedPipeline = false;
Driver->getBridgeCalls()->getTexture(0, tmpTextureType, tmpFixedPipeline);
glBindTexture(TextureType, TextureName);
// Manually create mipmaps or use prepared version
u32 compressedImageSize = 0;
u32 width=Image->getDimension().Width;
u32 height=Image->getDimension().Height;
u32 width=Image[0]->getDimension().Width;
u32 height=Image[0]->getDimension().Height;
u32 i=0;
u8* target = static_cast<u8*>(mipmapData);
do
@ -775,21 +937,21 @@ void COpenGLTexture::regenerateMipMapLevels(void* mipmapData)
++i;
if (!target)
target = new u8[width*height*Image->getBytesPerPixel()];
target = new u8[width*height*Image[0]->getBytesPerPixel()];
// create scaled version if no mipdata available
if (!mipmapData)
Image->copyToScaling(target, width, height, Image->getColorFormat());
Image[0]->copyToScaling(target, width, height, Image[0]->getColorFormat());
if (IsCompressed)
{
compressedImageSize = IImage::getCompressedImageSize(ColorFormat, width, height);
Driver->extGlCompressedTexImage2D(GL_TEXTURE_2D, i, InternalFormat, width,
Driver->extGlCompressedTexImage2D(TextureType, i, InternalFormat, width,
height, 0, compressedImageSize, target);
}
else
glTexImage2D(GL_TEXTURE_2D, i, InternalFormat, width, height,
glTexImage2D(TextureType, i, InternalFormat, width, height,
0, PixelFormat, PixelType, target);
// get next prepared mipmap data if available
@ -798,7 +960,7 @@ void COpenGLTexture::regenerateMipMapLevels(void* mipmapData)
if (IsCompressed)
mipmapData = static_cast<u8*>(mipmapData)+compressedImageSize;
else
mipmapData = static_cast<u8*>(mipmapData)+width*height*Image->getBytesPerPixel();
mipmapData = static_cast<u8*>(mipmapData)+width*height*Image[0]->getBytesPerPixel();
target = static_cast<u8*>(mipmapData);
}
@ -807,6 +969,8 @@ void COpenGLTexture::regenerateMipMapLevels(void* mipmapData)
// cleanup
if (!mipmapData)
delete [] target;
glBindTexture(tmpTextureType, tmpTextureName);
}
@ -838,13 +1002,13 @@ void COpenGLTexture::bindRTT()
void COpenGLTexture::unbindRTT()
{
Driver->setActiveTexture(0, this);
Driver->getBridgeCalls()->setTexture(0, true);
Driver->getBridgeCalls()->setTexture(0, TextureType, true);
// Copy Our ViewPort To The Texture
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, getSize().Width, getSize().Height);
glCopyTexSubImage2D(TextureType, 0, 0, 0, 0, 0, getSize().Width, getSize().Height);
Driver->setActiveTexture(0, 0);
Driver->getBridgeCalls()->setTexture(0, true);
Driver->getBridgeCalls()->setTexture(0, TextureType, true);
}
@ -893,7 +1057,7 @@ COpenGLFBOTexture::COpenGLFBOTexture(const core::dimension2d<u32>& size,
glGenTextures(1, &TextureName);
Driver->setActiveTexture(0, this);
Driver->getBridgeCalls()->setTexture(0, true);
Driver->getBridgeCalls()->setTexture(0, TextureType, true);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filtering);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
@ -927,7 +1091,7 @@ COpenGLFBOTexture::COpenGLFBOTexture(const core::dimension2d<u32>& size,
unbindRTT();
Driver->setActiveTexture(0, 0);
Driver->getBridgeCalls()->setTexture(0, true);
Driver->getBridgeCalls()->setTexture(0, TextureType, true);
}

View File

@ -8,6 +8,7 @@
#include "ITexture.h"
#include "IImage.h"
#include "SMaterialLayer.h"
#include "irrArray.h"
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_OPENGL_
@ -75,6 +76,10 @@ public:
//! constructor
COpenGLTexture(IImage* surface, const io::path& name, void* mipmapData=0, COpenGLDriver* driver=0);
//! constructor
COpenGLTexture(const io::path& name, IImage* posXImage, IImage* negXImage, IImage* posYImage,
IImage* negYImage, IImage* posZImage, IImage* negZImage, COpenGLDriver* driver=0);
//! destructor
virtual ~COpenGLTexture();
@ -102,6 +107,9 @@ public:
//! return open gl texture name
GLuint getOpenGLTextureName() const;
//! return open gl texture type
GLenum getOpenGLTextureType() const;
//! return whether this texture has mipmaps
virtual bool hasMipMaps() const;
@ -145,18 +153,21 @@ protected:
//! copies the texture into an OpenGL texture.
/** \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 imageNumber Inform which image should be used for upload.
\param regMipmap Inform if regenerate mipmap should be call.
\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);
void uploadTexture(bool newTexture=false, u32 imageNumber=0, bool regMipmap = false, void* mipmapData=0, u32 mipLevel=0);
core::dimension2d<u32> ImageSize;
core::dimension2d<u32> TextureSize;
ECOLOR_FORMAT ColorFormat;
COpenGLDriver* Driver;
IImage* Image;
core::array<IImage*> Image;
IImage* MipImage;
GLuint TextureName;
GLenum TextureType;
GLint InternalFormat;
GLenum PixelFormat;
GLenum PixelType;

View File

@ -1019,6 +1019,7 @@
<ClInclude Include="COGLESTexture.h" />
<ClInclude Include="COpenGLCgMaterialRenderer.h" />
<ClInclude Include="CSceneManager.h" />
<ClInclude Include="CWGLManager.h" />
<ClInclude Include="Octree.h" />
<ClInclude Include="CSMFMeshFileLoader.h" />
<ClInclude Include="C3DSMeshFileLoader.h" />
@ -1306,6 +1307,7 @@
<ClCompile Include="CQ3LevelMesh.cpp" />
<ClCompile Include="CSkinnedMesh.cpp" />
<ClCompile Include="CSTLMeshFileLoader.cpp" />
<ClCompile Include="CWGLManager.cpp" />
<ClCompile Include="CXMeshFileLoader.cpp" />
<ClCompile Include="CAnimatedMeshSceneNode.cpp" />
<ClCompile Include="CBillboardSceneNode.cpp" />
@ -1589,4 +1591,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>

View File

@ -1354,6 +1354,8 @@
<ClInclude Include="CImageLoaderPVR.h">
<Filter>Irrlicht\video\Null\Loader</Filter>
</ClInclude>
<ClInclude Include="CEGLManager.h" />
<ClInclude Include="CWGLManager.h" />
</ItemGroup>
<ItemGroup>
<None Include="..\..\changes.txt">
@ -2327,6 +2329,8 @@
<ClCompile Include="CImageLoaderPVR.cpp">
<Filter>Irrlicht\video\Null\Loader</Filter>
</ClCompile>
<ClCompile Include="CEGLManager.cpp" />
<ClCompile Include="CWGLManager.cpp" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="Irrlicht.rc" />