Browse Source

Using strongly-typed enums in AbstractTexture and derived classes.

Allows safer passing of values, more descriptive and shorter enum names
and also using the same enum names/values in InternalFormat and
ColorFormat.
pull/279/head
Vladimír Vondruš 15 years ago
parent
commit
e9a556cc10
  1. 21
      src/AbstractTexture.cpp
  2. 56
      src/AbstractTexture.h
  3. 16
      src/CubeMapTexture.h
  4. 8
      src/Texture.cpp
  5. 6
      src/Texture.h

21
src/AbstractTexture.cpp

@ -29,25 +29,30 @@ texture_assert(4); texture_assert(12); texture_assert(20); texture_assert(28);
texture_assert(5); texture_assert(13); texture_assert(21); texture_assert(29); texture_assert(5); texture_assert(13); texture_assert(21); texture_assert(29);
texture_assert(6); texture_assert(14); texture_assert(22); texture_assert(30); texture_assert(6); texture_assert(14); texture_assert(22); texture_assert(30);
texture_assert(7); texture_assert(15); texture_assert(23); texture_assert(31); texture_assert(7); texture_assert(15); texture_assert(23); texture_assert(31);
#undef texture_assert
/* Check correctness of binary OR in setMinificationFilter(). If nobody fucks /* Check correctness of binary OR in setMinificationFilter(). If nobody fucks
anything up, this assert should produce the same results on all dimensions, anything up, this assert should produce the same results on all dimensions,
thus testing only on AbstractTexture. */ thus testing only on AbstractTexture. */
static_assert(((AbstractTexture::NearestNeighborFilter|AbstractTexture::BaseMipLevel) == GL_NEAREST) && #define filter_or(filter, mipmap) \
((AbstractTexture::NearestNeighborFilter|AbstractTexture::NearestMipLevel) == GL_NEAREST_MIPMAP_NEAREST) && (static_cast<GLint>(AbstractTexture::Filter::filter)|static_cast<GLint>(AbstractTexture::Mipmap::mipmap))
((AbstractTexture::NearestNeighborFilter|AbstractTexture::LinearMipInterpolation) == GL_NEAREST_MIPMAP_LINEAR) && static_assert((filter_or(NearestNeighbor, BaseLevel) == GL_NEAREST) &&
((AbstractTexture::LinearFilter|AbstractTexture::BaseMipLevel) == GL_LINEAR) && (filter_or(NearestNeighbor, NearestLevel) == GL_NEAREST_MIPMAP_NEAREST) &&
((AbstractTexture::LinearFilter|AbstractTexture::NearestMipLevel) == GL_LINEAR_MIPMAP_NEAREST) && (filter_or(NearestNeighbor, LinearInterpolation) == GL_NEAREST_MIPMAP_LINEAR) &&
((AbstractTexture::LinearFilter|AbstractTexture::LinearMipInterpolation) == GL_LINEAR_MIPMAP_LINEAR), (filter_or(LinearInterpolation, BaseLevel) == GL_LINEAR) &&
(filter_or(LinearInterpolation, NearestLevel) == GL_LINEAR_MIPMAP_NEAREST) &&
(filter_or(LinearInterpolation, LinearInterpolation) == GL_LINEAR_MIPMAP_LINEAR),
"Unsupported constants for GL texture filtering"); "Unsupported constants for GL texture filtering");
#undef filter_or
#endif #endif
void AbstractTexture::setMinificationFilter(Filter filter, Mipmap mipmap) { void AbstractTexture::setMinificationFilter(Filter filter, Mipmap mipmap) {
/* Only base mip level is supported on rectangle textures */ /* Only base mip level is supported on rectangle textures */
if(target == GL_TEXTURE_RECTANGLE) mipmap = BaseMipLevel; if(target == GL_TEXTURE_RECTANGLE) mipmap = Mipmap::BaseLevel;
bind(); bind();
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, filter|mipmap); glTexParameteri(target, GL_TEXTURE_MIN_FILTER,
static_cast<GLint>(filter)|static_cast<GLint>(mipmap));
unbind(); unbind();
} }

56
src/AbstractTexture.h

@ -34,39 +34,39 @@ class AbstractTexture {
public: public:
/** @brief Texture filtering */ /** @brief Texture filtering */
enum Filter { enum class Filter: GLint {
/** /**
* Nearest neighbor filtering * Nearest neighbor filtering
*/ */
NearestNeighborFilter = GL_NEAREST, NearestNeighbor = GL_NEAREST,
/** /**
* Linear filtering * Linear interpolation filtering
*/ */
LinearFilter = GL_LINEAR LinearInterpolation = GL_LINEAR
}; };
/** @brief Mip level selection */ /** @brief Mip level selection */
enum Mipmap { enum class Mipmap: GLint {
/** /**
* Select base mip level * Select base mip level
*/ */
BaseMipLevel = GL_NEAREST & ~GL_NEAREST, BaseLevel = GL_NEAREST & ~GL_NEAREST,
/** /**
* Select nearest mip level. Unavailable on rectangle textures. * Select nearest mip level. Unavailable on rectangle textures.
*/ */
NearestMipLevel = GL_NEAREST_MIPMAP_NEAREST & ~GL_NEAREST, NearestLevel = GL_NEAREST_MIPMAP_NEAREST & ~GL_NEAREST,
/** /**
* Linear interpolation of nearest mip levels. Unavailable on * Linear interpolation of nearest mip levels. Unavailable on
* rectangle textures. * rectangle textures.
*/ */
LinearMipInterpolation = GL_NEAREST_MIPMAP_LINEAR & ~GL_NEAREST LinearInterpolation = GL_NEAREST_MIPMAP_LINEAR & ~GL_NEAREST
}; };
/** @brief Texture wrapping on the edge */ /** @brief Texture wrapping on the edge */
enum Wrapping { enum class Wrapping: GLint {
/** /**
* Repeat texture. Unavailable on rectangle textures. * Repeat texture. Unavailable on rectangle textures.
*/ */
@ -91,7 +91,13 @@ class AbstractTexture {
}; };
/** @brief Internal format */ /** @brief Internal format */
enum InternalFormat { enum class InternalFormat: GLint {
Red = GL_RED,
RedGreen = GL_RG,
RGB = GL_RGB,
RGBA = GL_RGBA,
BGR = GL_BGR,
BGRA = GL_BGRA,
CompressedRed = GL_COMPRESSED_RED, CompressedRed = GL_COMPRESSED_RED,
CompressedRedGreen = GL_COMPRESSED_RG, CompressedRedGreen = GL_COMPRESSED_RG,
CompressedRGB = GL_COMPRESSED_RGB, CompressedRGB = GL_COMPRESSED_RGB,
@ -99,7 +105,7 @@ class AbstractTexture {
}; };
/** @brief Color format */ /** @brief Color format */
enum ColorFormat { enum class ColorFormat: GLenum {
Red = GL_RED, Red = GL_RED,
RedGreen = GL_RG, RedGreen = GL_RG,
RGB = GL_RGB, RGB = GL_RGB,
@ -164,7 +170,7 @@ class AbstractTexture {
* @attention This and setMagnificationFilter() must be called after * @attention This and setMagnificationFilter() must be called after
* creating the texture, otherwise it will be unusable. * creating the texture, otherwise it will be unusable.
*/ */
void setMinificationFilter(Filter filter, Mipmap mipmap = BaseMipLevel); void setMinificationFilter(Filter filter, Mipmap mipmap = Mipmap::BaseLevel);
/** /**
* @brief Set magnification filter * @brief Set magnification filter
@ -177,7 +183,7 @@ class AbstractTexture {
*/ */
inline void setMagnificationFilter(Filter filter) { inline void setMagnificationFilter(Filter filter) {
bind(); bind();
glTexParameteri(target, GL_TEXTURE_MAG_FILTER, filter); glTexParameteri(target, GL_TEXTURE_MAG_FILTER, static_cast<GLint>(filter));
unbind(); unbind();
} }
@ -223,9 +229,7 @@ class AbstractTexture {
* @brief Set texture data * @brief Set texture data
* @param target Target, such as @c GL_TEXTURE_RECTANGLE * @param target Target, such as @c GL_TEXTURE_RECTANGLE
* @param mipLevel Mip level * @param mipLevel Mip level
* @param internalFormat Internal texture format. One value from * @param internalFormat Internal texture format
* @ref AbstractTexture::InternalFormat "InternalFormat" or
* @ref AbstractTexture::ColorFormat "ColorFormat" enum.
* @param dimensions %Texture dimensions * @param dimensions %Texture dimensions
* @param colorFormat Color format of passed data. Data size * @param colorFormat Color format of passed data. Data size
* per color channel is detected from format of passed data * per color channel is detected from format of passed data
@ -235,7 +239,7 @@ class AbstractTexture {
* Calls @c glTexImage1D, @c glTexImage2D, @c glTexImage3D depending * Calls @c glTexImage1D, @c glTexImage2D, @c glTexImage3D depending
* on dimension count. * on dimension count.
*/ */
template<class T> inline static void set(GLenum target, GLint mipLevel, int internalFormat, const Math::Vector<GLsizei, textureDimensions>& dimensions, ColorFormat colorFormat, const T* data); template<class T> inline static void set(GLenum target, GLint mipLevel, InternalFormat internalFormat, const Math::Vector<GLsizei, textureDimensions>& dimensions, ColorFormat colorFormat, const T* data);
/** /**
* @brief Set texture subdata * @brief Set texture subdata
@ -264,34 +268,34 @@ class AbstractTexture {
template<> struct AbstractTexture::DataHelper<1> { template<> struct AbstractTexture::DataHelper<1> {
inline constexpr static GLenum target() { return GL_TEXTURE_1D; } inline constexpr static GLenum target() { return GL_TEXTURE_1D; }
template<class T> inline static void set(GLenum target, GLint mipLevel, int internalFormat, const Math::Vector<GLsizei, 1>& dimensions, ColorFormat colorFormat, const T* data) { template<class T> inline static void set(GLenum target, GLint mipLevel, InternalFormat internalFormat, const Math::Vector<GLsizei, 1>& dimensions, ColorFormat colorFormat, const T* data) {
glTexImage1D(target, mipLevel, internalFormat, dimensions.at(0), 0, colorFormat, TypeTraits<T>::glType(), data); glTexImage1D(target, mipLevel, static_cast<GLint>(internalFormat), dimensions.at(0), 0, static_cast<GLenum>(colorFormat), TypeTraits<T>::glType(), data);
} }
template<class T> inline static void setSub(GLenum target, GLint mipLevel, const Math::Vector<GLsizei, 1>& offset, const Math::Vector<GLsizei, 1>& dimensions, ColorFormat colorFormat, const T* data) { template<class T> inline static void setSub(GLenum target, GLint mipLevel, const Math::Vector<GLsizei, 1>& offset, const Math::Vector<GLsizei, 1>& dimensions, ColorFormat colorFormat, const T* data) {
glTexSubImage1D(target, mipLevel, offset.at(0), dimensions.at(0), colorFormat, TypeTraits<T>::glType(), data); glTexSubImage1D(target, mipLevel, offset.at(0), dimensions.at(0), static_cast<GLenum>(colorFormat), TypeTraits<T>::glType(), data);
} }
}; };
template<> struct AbstractTexture::DataHelper<2> { template<> struct AbstractTexture::DataHelper<2> {
inline constexpr static GLenum target() { return GL_TEXTURE_2D; } inline constexpr static GLenum target() { return GL_TEXTURE_2D; }
template<class T> inline static void set(GLenum target, GLint mipLevel, int internalFormat, const Math::Vector<GLsizei, 2>& dimensions, ColorFormat colorFormat, const T* data) { template<class T> inline static void set(GLenum target, GLint mipLevel, InternalFormat internalFormat, const Math::Vector<GLsizei, 2>& dimensions, ColorFormat colorFormat, const T* data) {
glTexImage2D(target, mipLevel, internalFormat, dimensions.at(0), dimensions.at(1), 0, colorFormat, TypeTraits<T>::glType(), data); glTexImage2D(target, mipLevel, static_cast<GLint>(internalFormat), dimensions.at(0), dimensions.at(1), 0, static_cast<GLenum>(colorFormat), TypeTraits<T>::glType(), data);
} }
template<class T> inline static void setSub(GLenum target, GLint mipLevel, const Math::Vector<GLsizei, 2>& offset, const Math::Vector<GLsizei, 2>& dimensions, ColorFormat colorFormat, const T* data) { template<class T> inline static void setSub(GLenum target, GLint mipLevel, const Math::Vector<GLsizei, 2>& offset, const Math::Vector<GLsizei, 2>& dimensions, ColorFormat colorFormat, const T* data) {
glTexSubImage2D(target, mipLevel, offset.at(0), offset.at(1), dimensions.at(0), dimensions.at(1), colorFormat, TypeTraits<T>::glType(), data); glTexSubImage2D(target, mipLevel, offset.at(0), offset.at(1), dimensions.at(0), dimensions.at(1), static_cast<GLenum>(colorFormat), TypeTraits<T>::glType(), data);
} }
}; };
template<> struct AbstractTexture::DataHelper<3> { template<> struct AbstractTexture::DataHelper<3> {
inline constexpr static GLenum target() { return GL_TEXTURE_3D; } inline constexpr static GLenum target() { return GL_TEXTURE_3D; }
template<class T> inline static void set(GLenum target, GLint mipLevel, int internalFormat, const Math::Vector<GLsizei, 3>& dimensions, ColorFormat colorFormat, const T* data) { template<class T> inline static void set(GLenum target, GLint mipLevel, InternalFormat internalFormat, const Math::Vector<GLsizei, 3>& dimensions, ColorFormat colorFormat, const T* data) {
glTexImage3D(target, mipLevel, internalFormat, dimensions.at(0), dimensions.at(1), dimensions.at(2), 0, colorFormat, TypeTraits<T>::glType(), data); glTexImage3D(target, mipLevel, static_cast<GLint>(internalFormat), dimensions.at(0), dimensions.at(1), dimensions.at(2), 0, static_cast<GLenum>(colorFormat), TypeTraits<T>::glType(), data);
} }
template<class T> inline static void setSub(GLenum target, GLint mipLevel, const Math::Vector<GLsizei, 2>& offset, const Math::Vector<GLsizei, 2>& dimensions, ColorFormat colorFormat, const T* data) { template<class T> inline static void setSub(GLenum target, GLint mipLevel, const Math::Vector<GLsizei, 2>& offset, const Math::Vector<GLsizei, 2>& dimensions, ColorFormat colorFormat, const T* data) {
glTexSubImage3D(target, mipLevel, offset.at(0), offset.at(1), offset.at(2), dimensions.at(0), dimensions.at(1), dimensions.at(2), colorFormat, TypeTraits<T>::glType(), data); glTexSubImage3D(target, mipLevel, offset.at(0), offset.at(1), offset.at(2), dimensions.at(0), dimensions.at(1), dimensions.at(2), static_cast<GLenum>(colorFormat), TypeTraits<T>::glType(), data);
} }
}; };
#endif #endif

16
src/CubeMapTexture.h

@ -56,7 +56,7 @@ class CubeMapTexture: public Texture2D {
protected: protected:
/** @brief Deleted. Use setDataPositiveX() and others instead. */ /** @brief Deleted. Use setDataPositiveX() and others instead. */
template<class T> inline void setData(GLint mipLevel, int internalFormat, const Math::Vector<GLsizei, Dimensions>& _dimensions, ColorFormat colorFormat, const T* data) = delete; template<class T> inline void setData(GLint mipLevel, InternalFormat internalFormat, const Math::Vector<GLsizei, Dimensions>& _dimensions, ColorFormat colorFormat, const T* data) = delete;
/** @brief Deleted. Use setSubDataPositiveX() and others instead. */ /** @brief Deleted. Use setSubDataPositiveX() and others instead. */
template<class T> inline void setSubData(GLint mipLevel, const Math::Vector<GLsizei, Dimensions>& offset, const Math::Vector<GLsizei, Dimensions>& _dimensions, ColorFormat colorFormat, const T* data) = delete; template<class T> inline void setSubData(GLint mipLevel, const Math::Vector<GLsizei, Dimensions>& offset, const Math::Vector<GLsizei, Dimensions>& _dimensions, ColorFormat colorFormat, const T* data) = delete;
@ -66,7 +66,7 @@ class CubeMapTexture: public Texture2D {
* *
* @copydetails Texture::setData() * @copydetails Texture::setData()
*/ */
template<class T> inline void setDataPositiveX(GLint mipLevel, int internalFormat, const Math::Vector<GLsizei, Dimensions>& _dimensions, ColorFormat colorFormat, const T* data) { template<class T> inline void setDataPositiveX(GLint mipLevel, InternalFormat internalFormat, const Math::Vector<GLsizei, Dimensions>& _dimensions, ColorFormat colorFormat, const T* data) {
setData(GL_TEXTURE_CUBE_MAP_POSITIVE_X, mipLevel, internalFormat, _dimensions, colorFormat, data); setData(GL_TEXTURE_CUBE_MAP_POSITIVE_X, mipLevel, internalFormat, _dimensions, colorFormat, data);
} }
@ -84,7 +84,7 @@ class CubeMapTexture: public Texture2D {
* *
* @copydetails Texture::setData() * @copydetails Texture::setData()
*/ */
template<class T> inline void setDataNegativeX(GLint mipLevel, int internalFormat, const Math::Vector<GLsizei, Dimensions>& _dimensions, ColorFormat colorFormat, const T* data) { template<class T> inline void setDataNegativeX(GLint mipLevel, InternalFormat internalFormat, const Math::Vector<GLsizei, Dimensions>& _dimensions, ColorFormat colorFormat, const T* data) {
setData(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, mipLevel, internalFormat, _dimensions, colorFormat, data); setData(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, mipLevel, internalFormat, _dimensions, colorFormat, data);
} }
@ -102,7 +102,7 @@ class CubeMapTexture: public Texture2D {
* *
* @copydetails Texture::setData() * @copydetails Texture::setData()
*/ */
template<class T> inline void setDataPositiveY(GLint mipLevel, int internalFormat, const Math::Vector<GLsizei, Dimensions>& _dimensions, ColorFormat colorFormat, const T* data) { template<class T> inline void setDataPositiveY(GLint mipLevel, InternalFormat internalFormat, const Math::Vector<GLsizei, Dimensions>& _dimensions, ColorFormat colorFormat, const T* data) {
setData(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, mipLevel, internalFormat, _dimensions, colorFormat, data); setData(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, mipLevel, internalFormat, _dimensions, colorFormat, data);
} }
@ -120,7 +120,7 @@ class CubeMapTexture: public Texture2D {
* *
* @copydetails Texture::setData() * @copydetails Texture::setData()
*/ */
template<class T> inline void setDataNegativeY(GLint mipLevel, int internalFormat, const Math::Vector<GLsizei, Dimensions>& _dimensions, ColorFormat colorFormat, const T* data) { template<class T> inline void setDataNegativeY(GLint mipLevel, InternalFormat internalFormat, const Math::Vector<GLsizei, Dimensions>& _dimensions, ColorFormat colorFormat, const T* data) {
setData(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, mipLevel, internalFormat, _dimensions, colorFormat, data); setData(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, mipLevel, internalFormat, _dimensions, colorFormat, data);
} }
@ -138,7 +138,7 @@ class CubeMapTexture: public Texture2D {
* *
* @copydetails Texture::setData() * @copydetails Texture::setData()
*/ */
template<class T> inline void setDataPositiveZ(GLint mipLevel, int internalFormat, const Math::Vector<GLsizei, Dimensions>& _dimensions, ColorFormat colorFormat, const T* data) { template<class T> inline void setDataPositiveZ(GLint mipLevel, InternalFormat internalFormat, const Math::Vector<GLsizei, Dimensions>& _dimensions, ColorFormat colorFormat, const T* data) {
setData(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, mipLevel, internalFormat, _dimensions, colorFormat, data); setData(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, mipLevel, internalFormat, _dimensions, colorFormat, data);
} }
@ -156,7 +156,7 @@ class CubeMapTexture: public Texture2D {
* *
* @copydetails Texture::setData() * @copydetails Texture::setData()
*/ */
template<class T> inline void setDataNegativeZ(GLint mipLevel, int internalFormat, const Math::Vector<GLsizei, Dimensions>& _dimensions, ColorFormat colorFormat, const T* data) { template<class T> inline void setDataNegativeZ(GLint mipLevel, InternalFormat internalFormat, const Math::Vector<GLsizei, Dimensions>& _dimensions, ColorFormat colorFormat, const T* data) {
setData(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, mipLevel, internalFormat, _dimensions, colorFormat, data); setData(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, mipLevel, internalFormat, _dimensions, colorFormat, data);
} }
@ -170,7 +170,7 @@ class CubeMapTexture: public Texture2D {
} }
private: private:
template<class T> void setData(GLenum target, GLint mipLevel, int internalFormat, const Math::Vector<GLsizei, Dimensions>& _dimensions, ColorFormat colorFormat, const T* data) { template<class T> void setData(GLenum target, GLint mipLevel, InternalFormat internalFormat, const Math::Vector<GLsizei, Dimensions>& _dimensions, ColorFormat colorFormat, const T* data) {
bind(); bind();
DataHelper<Dimensions>::template set<typename TypeTraits<T>::TextureType>(target, mipLevel, internalFormat, _dimensions, colorFormat, data); DataHelper<Dimensions>::template set<typename TypeTraits<T>::TextureType>(target, mipLevel, internalFormat, _dimensions, colorFormat, data);
unbind(); unbind();

8
src/Texture.cpp

@ -21,18 +21,18 @@ template<size_t dimensions> void Texture<dimensions>::setWrapping(const Math::Ve
bind(); bind();
for(int i = 0; i != dimensions; ++i) { for(int i = 0; i != dimensions; ++i) {
/* Repeat wrap modes are not available on rectangle textures. */ /* Repeat wrap modes are not available on rectangle textures. */
if(target == GL_TEXTURE_RECTANGLE && (wrapping.at(i) == Repeat || wrapping.at(i) == MirroredRepeat)) if(target == GL_TEXTURE_RECTANGLE && (wrapping.at(i) == Wrapping::Repeat || wrapping.at(i) == Wrapping::MirroredRepeat))
continue; continue;
switch(i) { switch(i) {
case 0: case 0:
glTexParameteri(target, GL_TEXTURE_WRAP_S, wrapping.at(i)); glTexParameteri(target, GL_TEXTURE_WRAP_S, static_cast<GLint>(wrapping.at(i)));
break; break;
case 1: case 1:
glTexParameteri(target, GL_TEXTURE_WRAP_T, wrapping.at(i)); glTexParameteri(target, GL_TEXTURE_WRAP_T, static_cast<GLint>(wrapping.at(i)));
break; break;
case 2: case 2:
glTexParameteri(target, GL_TEXTURE_WRAP_R, wrapping.at(i)); glTexParameteri(target, GL_TEXTURE_WRAP_R, static_cast<GLint>(wrapping.at(i)));
break; break;
} }
} }

6
src/Texture.h

@ -79,15 +79,13 @@ template<size_t dimensions> class Texture: public AbstractTexture {
/** /**
* @brief Set texture data * @brief Set texture data
* @param mipLevel Mip level * @param mipLevel Mip level
* @param internalFormat Internal texture format. One value from * @param internalFormat Internal texture format
* @ref Texture::InternalFormat "InternalFormat" or
* @ref Texture::ColorFormat "ColorFormat" enum.
* @param _dimensions %Texture dimensions * @param _dimensions %Texture dimensions
* @param colorFormat Color format of passed data. Data size per * @param colorFormat Color format of passed data. Data size per
* color channel is detected from format of passed data array. * color channel is detected from format of passed data array.
* @param data %Texture data * @param data %Texture data
*/ */
template<class T> inline void setData(GLint mipLevel, int internalFormat, const Math::Vector<GLsizei, dimensions>& _dimensions, ColorFormat colorFormat, const T* data) { template<class T> inline void setData(GLint mipLevel, InternalFormat internalFormat, const Math::Vector<GLsizei, dimensions>& _dimensions, ColorFormat colorFormat, const T* data) {
bind(); bind();
DataHelper<dimensions>::template set<typename TypeTraits<T>::TextureType>(target, mipLevel, internalFormat, _dimensions, colorFormat, data); DataHelper<dimensions>::template set<typename TypeTraits<T>::TextureType>(target, mipLevel, internalFormat, _dimensions, colorFormat, data);
unbind(); unbind();

Loading…
Cancel
Save