Instead specify the desired amount of mipmap levels when loading an
image. This can be more robustly checked against the defined storage.
ifmt(RGB),
min_filter(NEAREST_MIPMAP_LINEAR),
mag_filter(LINEAR),
ifmt(RGB),
min_filter(NEAREST_MIPMAP_LINEAR),
mag_filter(LINEAR),
max_anisotropy(1.0f),
wrap_s(REPEAT),
wrap_t(REPEAT),
max_anisotropy(1.0f),
wrap_s(REPEAT),
wrap_t(REPEAT),
glTexParameteriv(target, GL_TEXTURE_SWIZZLE_RGBA, swizzle_orders+swizzle*4);
}
}
glTexParameteriv(target, GL_TEXTURE_SWIZZLE_RGBA, swizzle_orders+swizzle*4);
}
}
- if(mask&MIPMAP_LEVELS)
- set_parameter_i(GL_TEXTURE_MAX_LEVEL, (mipmap_levels ? mipmap_levels-1 : 1000));
}
void Texture::set_parameter_i(GLenum param, int value) const
}
void Texture::set_parameter_i(GLenum param, int value) const
set_mag_filter(f==NEAREST ? NEAREST : LINEAR);
}
set_mag_filter(f==NEAREST ? NEAREST : LINEAR);
}
-void Texture::set_mipmap_levels(unsigned l)
-{
- mipmap_levels = l;
- update_parameter(MIPMAP_LEVELS);
-}
-
void Texture::set_max_anisotropy(float a)
{
if(a<1.0f)
void Texture::set_max_anisotropy(float a)
{
if(a<1.0f)
}
void Texture::load_image(const string &fn, bool srgb)
}
void Texture::load_image(const string &fn, bool srgb)
+{
+ load_image(fn, 0, srgb);
+}
+
+void Texture::load_image(const string &fn, unsigned lv, bool srgb)
{
Graphics::Image img;
img.load_file(fn);
{
Graphics::Image img;
img.load_file(fn);
+ image(img, lv, srgb);
+}
+
+void Texture::image(const Graphics::Image &img, bool srgb)
+{
+ image(img, 0, srgb);
}
void Texture::bind_to(unsigned i) const
}
void Texture::bind_to(unsigned i) const
void Texture::Loader::init()
{
void Texture::Loader::init()
{
if(Resources *res = dynamic_cast<Resources *>(coll))
srgb = res->get_srgb_conversion();
else
if(Resources *res = dynamic_cast<Resources *>(coll))
srgb = res->get_srgb_conversion();
else
throw IO::file_not_found(fn);
img.load_io(*io);
throw IO::file_not_found(fn);
img.load_io(*io);
+ obj.image(img, levels, srgb);
}
void Texture::Loader::filter(TextureFilter f)
}
void Texture::Loader::filter(TextureFilter f)
IO::Memory mem(data.data(), data.size());
img.load_io(mem);
IO::Memory mem(data.data(), data.size());
img.load_io(mem);
+ obj.image(img, levels, srgb);
}
void Texture::Loader::mag_filter(TextureFilter f)
}
void Texture::Loader::mag_filter(TextureFilter f)
void Texture::Loader::mipmap_levels(unsigned l)
{
void Texture::Loader::mipmap_levels(unsigned l)
{
- obj.set_mipmap_levels(l);
}
void Texture::Loader::wrap(TextureWrap w)
}
void Texture::Loader::wrap(TextureWrap w)
class Loader: public DataFile::CollectionObjectLoader<Texture>
{
protected:
class Loader: public DataFile::CollectionObjectLoader<Texture>
{
protected:
COMPARE = 64,
COMPARE_FUNC = 128,
MAX_ANISOTROPY = 256,
COMPARE = 64,
COMPARE_FUNC = 128,
MAX_ANISOTROPY = 256,
- FORMAT_SWIZZLE = 512,
- MIPMAP_LEVELS = 1024
FormatSwizzle swizzle;
TextureFilter min_filter;
TextureFilter mag_filter;
FormatSwizzle swizzle;
TextureFilter min_filter;
TextureFilter mag_filter;
- unsigned mipmap_levels;
float max_anisotropy;
TextureWrap wrap_s;
TextureWrap wrap_t;
float max_anisotropy;
TextureWrap wrap_s;
TextureWrap wrap_t;
is not applicable to magnification, LINEAR is used instead. */
void set_filter(TextureFilter);
is not applicable to magnification, LINEAR is used instead. */
void set_filter(TextureFilter);
- void set_mipmap_levels(unsigned);
+ DEPRECATED void set_mipmap_levels(unsigned) { }
void set_max_anisotropy(float);
void set_max_anisotropy(float);
/// Loads a Graphics::Image from a file and uploads it to the texture.
virtual void load_image(const std::string &, bool srgb = false);
/// Loads a Graphics::Image from a file and uploads it to the texture.
virtual void load_image(const std::string &, bool srgb = false);
+ virtual void load_image(const std::string &, unsigned, bool srgb = false);
+
/** Uploads an image to the texture. If storage has not been defined, it
will be set to match the image. Otherwise the image must be compatible
with the defined storage. Semantics depend on the type of texture.
If srgb is true and storage is determined by this call, then an sRGB pixel
format will be used. */
/** Uploads an image to the texture. If storage has not been defined, it
will be set to match the image. Otherwise the image must be compatible
with the defined storage. Semantics depend on the type of texture.
If srgb is true and storage is determined by this call, then an sRGB pixel
format will be used. */
- virtual void image(const Graphics::Image &, bool srgb = false) = 0;
+ virtual void image(const Graphics::Image &, bool srgb = false);
+
+ virtual void image(const Graphics::Image &, unsigned, bool srgb = false) = 0;
GLenum get_target() const { return target; }
unsigned get_id() const { return id; }
GLenum get_target() const { return target; }
unsigned get_id() const { return id; }
return sub_image(level, 0, w, fmt, type, data);
BindRestore _bind(this);
return sub_image(level, 0, w, fmt, type, data);
BindRestore _bind(this);
+
+ if(!allocated)
+ glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, levels-1);
glTexImage1D(target, level, ifmt, w, 0, get_upload_format(fmt), type, data);
allocated |= 1<<level;
if(auto_gen_mipmap && level==0)
{
generate_mipmap();
glTexImage1D(target, level, ifmt, w, 0, get_upload_format(fmt), type, data);
allocated |= 1<<level;
if(auto_gen_mipmap && level==0)
{
generate_mipmap();
- allocated |= (1<<get_n_levels())-1;
+ allocated |= (1<<levels)-1;
-void Texture1D::image(const Graphics::Image &img, bool srgb)
+void Texture1D::image(const Graphics::Image &img, unsigned lv, bool srgb)
{
if(img.get_height()!=1)
throw incompatible_data("Texture1D::image");
{
if(img.get_height()!=1)
throw incompatible_data("Texture1D::image");
PixelFormat fmt = pixelformat_from_graphics(img.get_format());
if(width==0)
{
PixelFormat fmt = pixelformat_from_graphics(img.get_format());
if(width==0)
{
- unsigned l = (is_mipmapped(min_filter) ? mipmap_levels ? mipmap_levels : 0 : 1);
+ unsigned l = (is_mipmapped(min_filter) ? lv : 1);
storage(storage_pixelformat_from_graphics(img.get_format(), srgb), w, l);
}
else if(w!=width)
storage(storage_pixelformat_from_graphics(img.get_format(), srgb), w, l);
}
else if(w!=width)
void allocate(unsigned);
void image(unsigned, PixelFormat, DataType, const void *);
void sub_image(unsigned, int, unsigned, PixelFormat, DataType, const void *);
void allocate(unsigned);
void image(unsigned, PixelFormat, DataType, const void *);
void sub_image(unsigned, int, unsigned, PixelFormat, DataType, const void *);
- virtual void image(const Graphics::Image &, bool = false);
+ virtual void image(const Graphics::Image &, unsigned, bool = false);
+ using Texture::image;
unsigned get_width() const { return width; }
private:
unsigned get_width() const { return width; }
private:
return sub_image(level, 0, 0, w, h, fmt, type, data);
BindRestore _bind(this);
return sub_image(level, 0, 0, w, h, fmt, type, data);
BindRestore _bind(this);
+
+ if(!allocated)
+ glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, levels-1);
glTexImage2D(target, level, ifmt, w, h, 0, get_upload_format(fmt), type, data);
allocated |= 1<<level;
if(auto_gen_mipmap && level==0)
{
generate_mipmap();
glTexImage2D(target, level, ifmt, w, h, 0, get_upload_format(fmt), type, data);
allocated |= 1<<level;
if(auto_gen_mipmap && level==0)
{
generate_mipmap();
- allocated |= (1<<get_n_levels())-1;
+ allocated |= (1<<levels)-1;
-void Texture2D::image(const Graphics::Image &img, bool srgb)
+void Texture2D::image(const Graphics::Image &img, unsigned lv, bool srgb)
- image(img, srgb, false);
+ image(img, lv, srgb, false);
-void Texture2D::image(const Graphics::Image &img, bool srgb, bool from_buffer)
+void Texture2D::image(const Graphics::Image &img, unsigned lv, bool srgb, bool from_buffer)
{
unsigned w = img.get_width();
unsigned h = img.get_height();
PixelFormat fmt = pixelformat_from_graphics(img.get_format());
if(width==0)
{
{
unsigned w = img.get_width();
unsigned h = img.get_height();
PixelFormat fmt = pixelformat_from_graphics(img.get_format());
if(width==0)
{
- unsigned l = (is_mipmapped(min_filter) ? mipmap_levels ? mipmap_levels : 0 : 1);
+ unsigned l = (is_mipmapped(min_filter) ? lv : 1);
storage(storage_pixelformat_from_graphics(img.get_format(), srgb), w, h, l);
}
storage(storage_pixelformat_from_graphics(img.get_format(), srgb), w, h, l);
}
- else if(w!=width || h!=height)
+ else if(w!=width || h!=height || (lv && lv!=levels))
throw incompatible_data("Texture2D::image");
PixelStore pstore = PixelStore::from_image(img);
throw incompatible_data("Texture2D::image");
PixelStore pstore = PixelStore::from_image(img);
else
glGenTextures(1, &texture.id);
}
else
glGenTextures(1, &texture.id);
}
- texture.image(image, srgb_conversion, true);
+ texture.image(image, 0, srgb_conversion, true);
If srgb is true and storage is determined by this call, then an sRGB pixel
format will be used. */
If srgb is true and storage is determined by this call, then an sRGB pixel
format will be used. */
- virtual void image(const Graphics::Image &, bool srgb = false);
+ virtual void image(const Graphics::Image &, unsigned lv, bool srgb = false);
+
+ using Texture::image;
- void image(const Graphics::Image &, bool, bool);
+ void image(const Graphics::Image &, unsigned, bool, bool);
public:
unsigned get_width() const { return width; }
public:
unsigned get_width() const { return width; }
return sub_image(level, 0, 0, 0, w, h, d, fmt, type, data);
BindRestore _bind(this);
return sub_image(level, 0, 0, 0, w, h, d, fmt, type, data);
BindRestore _bind(this);
+
+ if(!allocated)
+ glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, levels-1);
glTexImage3D(target, level, ifmt, width, height, depth, 0, get_upload_format(fmt), type, data);
allocated |= 1<<level;
if(auto_gen_mipmap && level==0)
{
generate_mipmap();
glTexImage3D(target, level, ifmt, width, height, depth, 0, get_upload_format(fmt), type, data);
allocated |= 1<<level;
if(auto_gen_mipmap && level==0)
{
generate_mipmap();
- allocated |= (1<<get_n_levels())-1;
+ allocated |= (1<<levels)-1;
image(0, fmt, UNSIGNED_BYTE, img.get_data());
}
image(0, fmt, UNSIGNED_BYTE, img.get_data());
}
-void Texture3D::image(const Graphics::Image &img, bool srgb)
+void Texture3D::image(const Graphics::Image &img, unsigned lv, bool srgb)
{
unsigned w = img.get_width();
unsigned h = img.get_height();
{
unsigned w = img.get_width();
unsigned h = img.get_height();
PixelFormat fmt = pixelformat_from_graphics(img.get_format());
if(width==0)
{
PixelFormat fmt = pixelformat_from_graphics(img.get_format());
if(width==0)
{
- unsigned l = (is_mipmapped(min_filter) ? mipmap_levels ? mipmap_levels : 0 : 1);
+ unsigned l = (is_mipmapped(min_filter) ? lv : 1);
storage(storage_pixelformat_from_graphics(img.get_format(), srgb), w, h, d, l);
}
else if(w!=width || h!=height || d!=depth)
storage(storage_pixelformat_from_graphics(img.get_format(), srgb), w, h, d, l);
}
else if(w!=width || h!=height || d!=depth)
If srgb is true and storage is determined by this call, then an sRGB pixel
format will be used. */
If srgb is true and storage is determined by this call, then an sRGB pixel
format will be used. */
- virtual void image(const Graphics::Image &, bool = false);
+ virtual void image(const Graphics::Image &, unsigned, bool = false);
+
+ using Texture::image;
unsigned get_width() const { return width; }
unsigned get_height() const { return height; }
unsigned get_width() const { return width; }
unsigned get_height() const { return height; }
return sub_image(face, level, 0, 0, s, s, fmt, type, data);
BindRestore _bind(this);
return sub_image(face, level, 0, 0, s, s, fmt, type, data);
BindRestore _bind(this);
+
+ if(!allocated)
+ glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, levels-1);
glTexImage2D(face, level, ifmt, s, s, 0, get_upload_format(fmt), type, data);
// XXX Allocation should be tracked per-face, but we'll run out of bits
glTexImage2D(face, level, ifmt, s, s, 0, get_upload_format(fmt), type, data);
// XXX Allocation should be tracked per-face, but we'll run out of bits
{
// TODO Only do this once all faces are created
generate_mipmap();
{
// TODO Only do this once all faces are created
generate_mipmap();
- allocated |= (1<<get_n_levels())-1;
+ allocated |= (1<<levels)-1;
image(face, 0, fmt, UNSIGNED_BYTE, img.get_data());
}
image(face, 0, fmt, UNSIGNED_BYTE, img.get_data());
}
-void TextureCube::image(const Graphics::Image &img, bool srgb)
+void TextureCube::image(const Graphics::Image &img, unsigned lv, bool srgb)
{
unsigned w = img.get_width();
unsigned h = img.get_height();
{
unsigned w = img.get_width();
unsigned h = img.get_height();
PixelFormat fmt = pixelformat_from_graphics(img.get_format());
if(size==0)
{
PixelFormat fmt = pixelformat_from_graphics(img.get_format());
if(size==0)
{
- unsigned l = (is_mipmapped(min_filter) ? mipmap_levels ? mipmap_levels : 0 : 1);
+ unsigned l = (is_mipmapped(min_filter) ? lv : 1);
storage(storage_pixelformat_from_graphics(img.get_format(), srgb), w, l);
}
else if(w!=size || h!=size)
storage(storage_pixelformat_from_graphics(img.get_format(), srgb), w, l);
}
else if(w!=size || h!=size)
void image(TextureCubeFace, const Graphics::Image &, bool = false);
void image(TextureCubeFace, const Graphics::Image &, bool = false);
- virtual void image(const Graphics::Image &, bool = false);
+ virtual void image(const Graphics::Image &, unsigned, bool = false);
+ using Texture::image;
unsigned get_size() const { return size; }
private:
unsigned get_size() const { return size; }
private: