void GL1TextureProvider::copy_image_from(
    int x,
    int y,
    int width,
    int height,
    int level,
    TextureFormat texture_format,
    GraphicContextProvider *gc)
{
    throw_if_disposed();
    OpenGL::set_active(static_cast<GL1GraphicContextProvider*>(gc));
    GL1TextureStateTracker state_tracker(texture_type, handle);

    GLint gl_internal_format;
    GLenum gl_pixel_format;
    to_opengl_textureformat(texture_format, gl_internal_format, gl_pixel_format);

    glCopyTexImage2D(
        GL_TEXTURE_2D,
        level,
        gl_internal_format,
        x, y,
        width, height,
        0);
}
void GL1TextureProvider::set_wrap_mode(
    TextureWrapMode wrap_s)
{
    throw_if_disposed();
    GL1TextureStateTracker state_tracker(texture_type, handle);
    glTexParameteri(texture_type, GL_TEXTURE_WRAP_S, OpenGL::to_enum(wrap_s));
}
PixelBuffer GL1TextureProvider::get_pixeldata(GraphicContext &gc, TextureFormat texture_format, int level) const
{
    throw_if_disposed();

    OpenGL::set_active(gc);
    GL1TextureStateTracker state_tracker(texture_type, handle);

    GLenum gl_format = 0, gl_type = 0;
    bool supported = to_opengl_pixelformat(texture_format, gl_format, gl_type);
    if (supported)
    {
        PixelBuffer buffer(pot_width, pot_height, texture_format);
        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
#ifndef __ANDROID__
        glPixelStorei(GL_UNPACK_ROW_LENGTH, buffer.get_pitch() / buffer.get_bytes_per_pixel());
        glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
        glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
#endif
        glGetTexImage(texture_type, level, gl_format, gl_type, buffer.get_data());
        return buffer.copy(Rect(0,0, width, height));
    }
    else
    {
        PixelBuffer buffer(pot_width, pot_height, tf_rgba8);
        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
#ifndef __ANDROID__
        glPixelStorei(GL_UNPACK_ROW_LENGTH, buffer.get_pitch() / buffer.get_bytes_per_pixel());
        glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
        glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
#endif
        glGetTexImage(texture_type, level, GL_RGBA, GL_UNSIGNED_BYTE, buffer.get_data());
        return buffer.copy(Rect(0,0, width, height)).to_format(texture_format);
    }
}
void GL1TextureProvider::set_texture_compare(TextureCompareMode mode, CompareFunction func)
{
    throw_if_disposed();
    GL1TextureStateTracker state_tracker(texture_type, handle);
    glTexParameteri(texture_type, GL_TEXTURE_COMPARE_MODE, OpenGL::to_enum(mode));
    glTexParameteri(texture_type, GL_TEXTURE_COMPARE_FUNC, OpenGL::to_enum(func));
}
void CL_OpenGLProgramObjectProvider::set_uniform1i(const CL_StringRef &name, int p1)
{
    throw_if_disposed();
    CL_ProgramObjectStateTracker state_tracker(handle);
    int loc = get_uniform_location(name);
    if (loc == -1)
        return;
    glUniform1i(loc, p1);
}
void GL3ProgramObjectProvider::set_uniform4f(int location, float v1, float v2, float v3, float v4)
{
	throw_if_disposed();
	if (location >= 0)
	{
		ProgramObjectStateTracker state_tracker(handle);
		glUniform4f(location, v1, v2, v3, v4);	
	}
}
void GL3ProgramObjectProvider::set_uniform3i(int location, int v1, int v2, int v3)
{
	throw_if_disposed();
	if (location >= 0)
	{
		ProgramObjectStateTracker state_tracker(handle);
		glUniform3i(location, v1, v2, v3);	
	}
}
void GL3ProgramObjectProvider::set_uniform_matrix(int location, int size, int count, bool transpose, const float *data)
{
	throw_if_disposed();
	if (location >= 0)
	{
		ProgramObjectStateTracker state_tracker(handle);
		if( size == 2 ) glUniformMatrix2fv(location, count, transpose, data);	
		else if( size == 3 ) glUniformMatrix3fv(location, count, transpose, data);	
		else if( size == 4 ) glUniformMatrix4fv(location, count, transpose, data);
	}
}
void GL3ProgramObjectProvider::set_uniformfv(int location, int size, int count, const float *data)
{
	throw_if_disposed();
	if (location >= 0)
	{
		ProgramObjectStateTracker state_tracker(handle);
		if( size == 1 ) glUniform1fv(location, count, data);	
		else if( size == 2 ) glUniform2fv(location, count, data);	
		else if( size == 3 ) glUniform3fv(location, count, data);	
		else if( size == 4 ) glUniform4fv(location, count, data);	
	}
}
void CL_OpenGLProgramObjectProvider::set_uniform_matrix(const CL_StringRef &name, int size, int count, bool transpose, float *data)
{
    throw_if_disposed();

    CL_ProgramObjectStateTracker state_tracker(handle);
    int loc = get_uniform_location(name);
    if (loc == -1)
        return;

    if( size == 2 ) glUniformMatrix2fv(loc, count, transpose, data);
    else if( size == 3 ) glUniformMatrix3fv(loc, count, transpose, data);
    else if( size == 4 ) glUniformMatrix4fv(loc, count, transpose, data);
    else throw CL_Exception(cl_format("Unsupported size given to uniform '%1'.", name));
}
示例#11
0
GL1TextureProvider::GL1TextureProvider(TextureDimensions texture_dimensions)
    : width(0), height(0), depth(0), handle(0), texture_type(0)
{
    SharedGCData::add_disposable(this);
    switch (texture_dimensions)
    {
    case texture_1d:
#ifdef __ANDROID__
        throw Exception("GL_TEXTURE_1D is not supported");
#else
        texture_type = GL_TEXTURE_1D;
#endif
        break;
    case texture_2d:
    default:
        texture_type = GL_TEXTURE_2D;
        break;
    case texture_3d:
        texture_type = GL_TEXTURE_3D;
        break;
    case texture_cube:
#ifdef __ANDROID__
        throw Exception("GL_TEXTURE_CUBE_MAP is not supported");
#else
        texture_type = GL_TEXTURE_CUBE_MAP;
#endif
        break;
    }

    OpenGL::set_active();
    glGenTextures(1, &handle);
    GL1TextureStateTracker state_tracker(texture_type, 0);
    glBindTexture(texture_type, handle);
    glTexParameteri(texture_type, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(texture_type, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(texture_type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
#ifndef __ANDROID__
    if (texture_type != GL_TEXTURE_1D)
#endif
    {
        glTexParameteri(texture_type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    }
    if (texture_type == GL_TEXTURE_3D)
        glTexParameteri(texture_type, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
}
示例#12
0
void GL1TextureProvider::copy_subimage_from(
    int offset_x,
    int offset_y,
    int x,
    int y,
    int width,
    int height,
    int level,
    GraphicContextProvider *gc)
{
    throw_if_disposed();
    OpenGL::set_active(static_cast<GL1GraphicContextProvider*>(gc));
    GL1TextureStateTracker state_tracker(texture_type, handle);

    glCopyTexSubImage2D(
        GL_TEXTURE_2D,
        level,
        offset_x,
        offset_y,
        x, y,
        width, height );
}
示例#13
0
void GL1TextureProvider::set_max_lod(double max_lod)
{
    throw_if_disposed();
    GL1TextureStateTracker state_tracker(texture_type, handle);
    glTexParameterf(texture_type, GL_TEXTURE_MAX_LOD, (GLfloat)max_lod);
}
示例#14
0
void GL1TextureProvider::create(int new_width, int new_height, int new_depth, int array_size, TextureFormat texture_format, int levels)
{
    throw_if_disposed();

    GLint gl_internal_format;
    GLenum gl_pixel_format;
    to_opengl_textureformat(texture_format, gl_internal_format, gl_pixel_format);

    if ( (new_width > 32768) || (new_width < 1) )
    {
        throw Exception("Invalid texture width in the GL1 target");
    }

    if ( (texture_type == GL_TEXTURE_2D) || (texture_type == GL_TEXTURE_3D) )
    {
        if ( (new_height > 32768) || (new_height < 1) )
        {
            throw Exception("Invalid texture height in the GL1 target");
        }
    }

    if ( texture_type == GL_TEXTURE_3D )
    {
        if ( (new_depth > 32768) || (new_depth < 1) )
        {
            throw Exception("Invalid texture depth in the GL1 target");
        }
    }

    width = new_width;
    height = new_height;
    depth = new_depth;
    GL1TextureStateTracker state_tracker(texture_type, handle);

#ifndef __ANDROID__
    if (texture_type == GL_TEXTURE_1D)
    {
        pot_width = get_next_power_of_two(new_width);
        if (pot_width == new_width)
        {
            power_of_two_texture=true;
        }
        else
        {
            power_of_two_texture=false;
        }

        pot_ratio_width = (float) width / pot_width;
        glTexImage1D(
            GL_TEXTURE_1D,			// target
            0,						// level
            gl_internal_format,		// internalformat
            pot_width,				// width
            0,						// border
            gl_pixel_format,		// format
            GL_UNSIGNED_BYTE,		// type (it really doesn't matter since nothing is uploaded)
            nullptr);						// texels (0 to avoid uploading)
    }
#endif
    if (texture_type == GL_TEXTURE_2D)
    {
        pot_width = get_next_power_of_two(new_width);
        pot_height = get_next_power_of_two(new_height);
        if ( (pot_width == new_width) && (pot_height == new_height))
        {
            power_of_two_texture=true;
        }
        else
        {
            power_of_two_texture=false;
        }
        pot_ratio_width = (float) width / pot_width;
        pot_ratio_height = (float) height / pot_height;

        glTexImage2D(
            GL_TEXTURE_2D,			// target
            0,						// level
            gl_internal_format,		// internalformat
            pot_width,				// width
            pot_height,				// height
            0,						// border
            gl_pixel_format,		// format
            GL_UNSIGNED_BYTE,		// type (it really doesn't matter since nothing is uploaded)
            nullptr);						// texels (0 to avoid uploading)

        // Clear the whole texture if it is npot
        if (!power_of_two_texture)
        {
            PixelBuffer image = PixelBuffer(pot_width, pot_height, tf_rgba8);
            void *data = image.get_data();
            memset(data, 0, pot_width * pot_height * 4);

            GLenum format;
            GLenum type;
            to_opengl_pixelformat(image, format, type);

            glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
            const int bytesPerPixel = image.get_bytes_per_pixel();
#ifndef __ANDROID__
            glPixelStorei(GL_UNPACK_ROW_LENGTH, image.get_pitch() / bytesPerPixel);
            glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
            glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
#endif
            glTexImage2D(
                GL_TEXTURE_2D,		// target
                0,					// level
                gl_internal_format,	// internalformat
                pot_width,			// width
                pot_height,			// height
                0,					// border
                format,				// format
                type,				// type
                data);				// texels

        }
    }
    else
    {
        pot_width = get_next_power_of_two(new_width);
        pot_height = get_next_power_of_two(new_height);
        pot_depth = get_next_power_of_two(new_depth);
        pot_ratio_width = (float) width / pot_width;
        pot_ratio_height = (float) height / pot_height;
        pot_ratio_depth = (float) depth / pot_depth;
        if ( (pot_width == new_width) && (pot_height == new_height) && (pot_depth == new_depth))
        {
            power_of_two_texture=true;
        }
        else
        {
            power_of_two_texture=false;
        }

        glTexImage3D(
            GL_TEXTURE_3D,			// target
            0,						// level
            gl_internal_format,		// internalformat
            pot_width,				// width
            pot_height,				// height
            pot_depth,				// depth
            0,						// border
            gl_pixel_format,		// format
            GL_UNSIGNED_BYTE,		// type (it really doesn't matter since nothing is uploaded)
            nullptr);						// texels (0 to avoid uploading)
    }
}
示例#15
0
void GL1TextureProvider::set_texture_image3d(
    GLuint target,
    PixelBuffer &image,
    int image_depth,
    int level)
{
    throw_if_disposed();
    GL1TextureStateTracker state_tracker(texture_type, handle);

    GLint gl_internal_format;
    GLenum gl_pixel_format;
    to_opengl_textureformat(image.get_format(), gl_internal_format, gl_pixel_format);

    // check out if the original texture needs or doesn't need an alpha channel
    bool needs_alpha = image.has_transparency();

    GLenum format;
    GLenum type;
    bool conv_needed = !to_opengl_pixelformat(image, format, type);

    // also check for the pitch (GL1 can only skip pixels, not bytes)
    if (!conv_needed)
    {
        const int bytesPerPixel = image.get_bytes_per_pixel();
        if (image.get_pitch() % bytesPerPixel != 0)
            conv_needed = true;
    }

    // no conversion needed
    if (!conv_needed)
    {
        // Upload to GL1:

        // change alignment
        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
        const int bytesPerPixel = image.get_bytes_per_pixel();
#ifndef __ANDROID__
        glPixelStorei(GL_UNPACK_ROW_LENGTH, image.get_pitch() / bytesPerPixel);
        glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
        glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
#endif

        char *data = (char *) image.get_data();
        int image_width = image.get_width();
        int image_height = image.get_height() / image_depth;

        glTexImage3D(
            target,                   // target
            level,                    // level
            gl_internal_format,           // internalformat
            image_width,              // width
            image_height,             // height
            image_depth,             // depth
            0,						 // border
            format,                   // format
            type,                     // type
            data);                    // texels
    }
    // conversion needed
    else
    {
        bool big_endian = Endian::is_system_big();

        PixelBuffer buffer(
            image.get_width(), image.get_height(),
            needs_alpha ? tf_rgba8 : tf_rgb8);

        buffer.set_image(image);

        format = needs_alpha ? GL_RGBA : GL_RGB;

        // Upload to OpenGL:

        // change alignment
        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
        const int bytesPerPixel = buffer.get_bytes_per_pixel();
#ifndef __ANDROID__
        glPixelStorei(GL_UNPACK_ROW_LENGTH, buffer.get_pitch() / bytesPerPixel);
        glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
        glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
#endif
        int image_width = image.get_width();
        int image_height = image.get_height() / image_depth;

        // upload
        glTexImage3D(
            target,                   // target
            level,                    // level
            gl_internal_format,           // internalformat
            image_width,        // width
            image_height,       // height
            image_depth,       // depth
            0,                        // border
            format,                   // format
            GL_UNSIGNED_BYTE,         // type
            buffer.get_data());       // texels

    }
}
示例#16
0
void GL1TextureProvider::set_texture_image2d(
    GLuint target,
    PixelBuffer &image,
    int level)
{
    throw_if_disposed();
    GL1TextureStateTracker state_tracker(texture_type, handle);

    GLint gl_internal_format;
    GLenum gl_pixel_format;
    to_opengl_textureformat(image.get_format(), gl_internal_format, gl_pixel_format);


    /*
    	GL_UNPACK_SWAP_BYTES
    	GL_UNPACK_LSB_FIRST
    	GL_UNPACK_SKIP_ROWS
    	GL_UNPACK_SKIP_PIXELS

    	GL_UNPACK_ROW_LENGTH
    	GL_UNPACK_ALIGNMENT
    	GL_UNPACK_IMAGE_HEIGHT
    	GL_UNPACK_SKIP_IMAGES
    */

    // check out if the original texture needs or doesn't need an alpha channel
    bool needs_alpha = image.has_transparency();

    GLenum format;
    GLenum type;
    bool conv_needed = !to_opengl_pixelformat(image, format, type);

    // also check for the pitch (GL1 can only skip pixels, not bytes)
    if (!conv_needed)
    {
        const int bytesPerPixel = image.get_bytes_per_pixel();
        if (image.get_pitch() % bytesPerPixel != 0)
            conv_needed = true;
    }

    // no conversion needed
    if (!conv_needed)
    {
        // Upload to GL1:

        // change alignment
        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
        const int bytesPerPixel = image.get_bytes_per_pixel();
#ifndef __ANDROID__
        glPixelStorei(GL_UNPACK_ROW_LENGTH, image.get_pitch() / bytesPerPixel);
        glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
        glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
#endif
        char *data = (char *) image.get_data();
        int image_width = image.get_width();
        int image_height = image.get_height();
        /*
        		int image_width = 1;
        		int image_height = 1;
        		while (image_width < image.get_width()) image_width *= 2;
        		while (image_height < image.get_height()) image_height *= 2;
        */
        glTexImage2D(
            target,                   // target
            level,                    // level
            gl_internal_format,           // internalformat
            image_width,              // width
            image_height,             // height
            0,						 // border
            format,                   // format
            type,                     // type
            data);                    // texels
    }
    // conversion needed
    else
    {
        bool big_endian = Endian::is_system_big();

        PixelBuffer buffer(
            image.get_width(), image.get_height(),
            needs_alpha ? tf_rgba8 : tf_rgb8);

        buffer.set_image(image);

        format = needs_alpha ? GL_RGBA : GL_RGB;

        // Upload to OpenGL:

        // change alignment
        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
        const int bytesPerPixel = buffer.get_bytes_per_pixel();
#ifndef __ANDROID__
        glPixelStorei(GL_UNPACK_ROW_LENGTH, buffer.get_pitch() / bytesPerPixel);
        glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
        glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
#endif
        // upload
        glTexImage2D(
            target,                   // target
            level,                    // level
            gl_internal_format,           // internalformat
            image.get_width(),        // width
            image.get_height(),       // height
            0,                        // border
            format,                   // format
            GL_UNSIGNED_BYTE,         // type
            buffer.get_data());       // texels

        /*
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        */
    }
}
示例#17
0
void GL1TextureProvider::copy_from(GraphicContext &gc, int x, int y, int slice, int level, const PixelBuffer &ximage, const Rect &src_rect)
{
    OpenGL::set_active(gc);

    PixelBuffer image = ximage;

    if (src_rect.left < 0 || src_rect.top < 0 || src_rect.right > image.get_width() || src_rect.bottom > image.get_height())
        throw Exception("Rectangle out of bounds");

    throw_if_disposed();
    GL1TextureStateTracker state_tracker(texture_type, handle);

    // check out if the original texture needs or doesn't need an alpha channel
    bool needs_alpha = image.has_transparency();

    GLenum format;
    GLenum type;
    bool conv_needed = !to_opengl_pixelformat(image, format, type);

    // also check for the pitch (GL1 can only skip pixels, not bytes)
    if (!conv_needed)
    {
        const int bytesPerPixel = image.get_bytes_per_pixel();
        if (image.get_pitch() % bytesPerPixel != 0)
            conv_needed = true;
    }

    // no conversion needed
    if (!conv_needed)
    {
        // change alignment
        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
        const int bytesPerPixel = image.get_bytes_per_pixel();
#ifndef __ANDROID__
        glPixelStorei(GL_UNPACK_ROW_LENGTH, image.get_pitch() / bytesPerPixel);
        glPixelStorei(GL_UNPACK_SKIP_PIXELS, src_rect.left);
        glPixelStorei(GL_UNPACK_SKIP_ROWS, src_rect.top);
#endif

    }
    // conversion needed
    else
    {
        bool big_endian = Endian::is_system_big();

        PixelBuffer buffer(
            src_rect.get_width(), src_rect.get_height(),
            needs_alpha ? tf_rgba8 : tf_rgb8);

        buffer.set_subimage(image, Point(0, 0), src_rect);

        format = needs_alpha ? GL_RGBA : GL_RGB;

        // Upload to GL1:
        glBindTexture(GL_TEXTURE_2D, handle);

        // change alignment
        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
        const int bytesPerPixel = buffer.get_bytes_per_pixel();
#ifndef __ANDROID__
        glPixelStorei(GL_UNPACK_ROW_LENGTH, buffer.get_pitch() / bytesPerPixel);
        glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
        glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
#endif

        type = GL_UNSIGNED_BYTE;
        image = buffer;
    }

    // upload
    glTexSubImage2D(
        GL_TEXTURE_2D,            // target
        level,                    // level
        x, y,                     // xoffset, yoffset
        src_rect.get_width(),        // width
        src_rect.get_height(),       // height
        format,					  // format
        type,					  // type
        image.get_data());        // texels

    if (!power_of_two_texture)
    {
        // TODO: This needs corrected.It should be optimised and currently it does not write to the lower right quadrant

        // Check extend the right edge
        int right_edge = x + image.get_width();
        if ( right_edge >= width )
        {
            char *edge_data = (char *) image.get_data();
            edge_data += image.get_bytes_per_pixel() * (width-1);

            for(int edge_cnt = right_edge; edge_cnt < pot_width; edge_cnt++)
            {
                glTexSubImage2D(
                    GL_TEXTURE_2D,		// target
                    level,				// level
                    edge_cnt, y,		// xoffset, yoffset
                    1,					// width
                    src_rect.get_height(),	// height
                    format,				// format
                    type,				// type
                    edge_data);				// texels
            }
        }
        // Check extend the bottom edge
        int bottom_edge = y + image.get_height();
        if ( bottom_edge >= height )
        {
            char *edge_data = (char *) image.get_data();
            edge_data += image.get_pitch() * (height-1);

            for(int edge_cnt = bottom_edge; edge_cnt < pot_height; edge_cnt++)
            {
                glTexSubImage2D(
                    GL_TEXTURE_2D,		// target
                    level,				// level
                    x, edge_cnt,		// xoffset, yoffset
                    src_rect.get_width(),		// width
                    1,	// height
                    format,				// format
                    type,				// type
                    edge_data);				// texels
            }
        }
    }
    // Restore these unpack values to the default
#ifndef __ANDROID__
    glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
    glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
#endif
}
示例#18
0
void GL1TextureProvider::set_mag_filter(TextureFilter filter)
{
    throw_if_disposed();
    GL1TextureStateTracker state_tracker(texture_type, handle);
    glTexParameteri(texture_type, GL_TEXTURE_MAG_FILTER, OpenGL::to_enum(filter));
}
示例#19
0
void GL1TextureProvider::set_max_level(int max_level)
{
    throw_if_disposed();
    GL1TextureStateTracker state_tracker(texture_type, handle);
    glTexParameteri(texture_type, GL_TEXTURE_MAX_LEVEL, max_level);
}
示例#20
0
void GL1TextureProvider::set_lod_bias(double lod_bias)
{
    throw_if_disposed();
    GL1TextureStateTracker state_tracker(texture_type, handle);
    glTexParameterf(texture_type, GL_TEXTURE_LOD_BIAS, (GLfloat)lod_bias);
}