diff options
Diffstat (limited to 'source/blender/gpu/intern/gpu_texture.c')
-rw-r--r-- | source/blender/gpu/intern/gpu_texture.c | 769 |
1 files changed, 769 insertions, 0 deletions
diff --git a/source/blender/gpu/intern/gpu_texture.c b/source/blender/gpu/intern/gpu_texture.c new file mode 100644 index 00000000000..294b08f155a --- /dev/null +++ b/source/blender/gpu/intern/gpu_texture.c @@ -0,0 +1,769 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2005 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Brecht Van Lommel. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_image_types.h" + +#include "BLI_blenlib.h" +#include "BLI_utildefines.h" +#include "BLI_math_base.h" +#include "BLI_math_vector.h" + +#include "BKE_global.h" + +#include "GPU_debug.h" +#include "GPU_draw.h" +#include "GPU_extensions.h" +#include "GPU_framebuffer.h" +#include "GPU_glew.h" +#include "GPU_texture.h" + +static struct GPUTextureGlobal { + GPUTexture *invalid_tex_1D; /* texture used in place of invalid textures (not loaded correctly, missing) */ + GPUTexture *invalid_tex_2D; + GPUTexture *invalid_tex_3D; +} GG = {NULL, NULL, NULL}; + +/* GPUTexture */ + +struct GPUTexture { + int w, h; /* width/height */ + int number; /* number for multitexture binding */ + int refcount; /* reference count */ + GLenum target; /* GL_TEXTURE_* */ + GLenum target_base; /* same as target, (but no multisample) */ + GLuint bindcode; /* opengl identifier for texture */ + int fromblender; /* we got the texture from Blender */ + + GPUFrameBuffer *fb; /* GPUFramebuffer this texture is attached to */ + int fb_attachment; /* slot the texture is attached to */ + int depth; /* is a depth texture? if 3D how deep? */ +}; + +static unsigned char *GPU_texture_convert_pixels(int length, const float *fpixels) +{ + unsigned char *pixels, *p; + const float *fp = fpixels; + const int len = 4 * length; + + p = pixels = MEM_callocN(sizeof(unsigned char) * len, "GPUTexturePixels"); + + for (int a = 0; a < len; a++, p++, fp++) + *p = FTOCHAR((*fp)); + + return pixels; +} + +static void GPU_glTexSubImageEmpty(GLenum target, GLenum format, int x, int y, int w, int h) +{ + void *pixels = MEM_callocN(sizeof(char) * 4 * w * h, "GPUTextureEmptyPixels"); + + if (target == GL_TEXTURE_1D) + glTexSubImage1D(target, 0, x, w, format, GL_UNSIGNED_BYTE, pixels); + else + glTexSubImage2D(target, 0, x, y, w, h, format, GL_UNSIGNED_BYTE, pixels); + + MEM_freeN(pixels); +} + +static GPUTexture *GPU_texture_create_nD( + int w, int h, int n, const float *fpixels, int depth, + GPUHDRType hdr_type, int components, int samples, + char err_out[256]) +{ + GLenum type, format, internalformat; + void *pixels = NULL; + + if (samples) { + CLAMP_MAX(samples, GPU_max_color_texture_samples()); + } + + GPUTexture *tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture"); + tex->w = w; + tex->h = h; + tex->number = -1; + tex->refcount = 1; + tex->target = (n == 1) ? GL_TEXTURE_1D : (samples ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D); + tex->target_base = (n == 1) ? GL_TEXTURE_1D : GL_TEXTURE_2D; + tex->depth = depth; + tex->fb_attachment = -1; + + glGenTextures(1, &tex->bindcode); + + if (!tex->bindcode) { + if (err_out) { + BLI_snprintf(err_out, 256, "GPUTexture: texture create failed: %d", + (int)glGetError()); + } + else { + fprintf(stderr, "GPUTexture: texture create failed: %d\n", + (int)glGetError()); + } + GPU_texture_free(tex); + return NULL; + } + + if (!GPU_full_non_power_of_two_support()) { + tex->w = power_of_2_max_i(tex->w); + tex->h = power_of_2_max_i(tex->h); + } + + tex->number = 0; + glBindTexture(tex->target, tex->bindcode); + + if (depth) { + type = GL_UNSIGNED_BYTE; + format = GL_DEPTH_COMPONENT; + internalformat = GL_DEPTH_COMPONENT; + } + else { + type = GL_FLOAT; + + if (components == 4) { + format = GL_RGBA; + switch (hdr_type) { + case GPU_HDR_NONE: + internalformat = GL_RGBA8; + break; + /* the following formats rely on ARB_texture_float or OpenGL 3.0 */ + case GPU_HDR_HALF_FLOAT: + internalformat = GL_RGBA16F_ARB; + break; + case GPU_HDR_FULL_FLOAT: + internalformat = GL_RGBA32F_ARB; + break; + default: + break; + } + } + else if (components == 2) { + /* these formats rely on ARB_texture_rg or OpenGL 3.0 */ + format = GL_RG; + switch (hdr_type) { + case GPU_HDR_NONE: + internalformat = GL_RG8; + break; + case GPU_HDR_HALF_FLOAT: + internalformat = GL_RG16F; + break; + case GPU_HDR_FULL_FLOAT: + internalformat = GL_RG32F; + break; + default: + break; + } + } + + if (fpixels && hdr_type == GPU_HDR_NONE) { + type = GL_UNSIGNED_BYTE; + pixels = GPU_texture_convert_pixels(w * h, fpixels); + } + } + + if (tex->target == GL_TEXTURE_1D) { + glTexImage1D(tex->target, 0, internalformat, tex->w, 0, format, type, NULL); + + if (fpixels) { + glTexSubImage1D(tex->target, 0, 0, w, format, type, + pixels ? pixels : fpixels); + + if (tex->w > w) { + GPU_glTexSubImageEmpty(tex->target, format, w, 0, tex->w - w, 1); + } + } + } + else { + if (samples) { + glTexImage2DMultisample(tex->target, samples, internalformat, tex->w, tex->h, true); + } + else { + glTexImage2D(tex->target, 0, internalformat, tex->w, tex->h, 0, + format, type, NULL); + } + + if (fpixels) { + glTexSubImage2D(tex->target, 0, 0, 0, w, h, + format, type, pixels ? pixels : fpixels); + + if (tex->w > w) + GPU_glTexSubImageEmpty(tex->target, format, w, 0, tex->w - w, tex->h); + if (tex->h > h) + GPU_glTexSubImageEmpty(tex->target, format, 0, h, w, tex->h - h); + } + } + + if (pixels) + MEM_freeN(pixels); + + if (depth) { + glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE); + glTexParameteri(tex->target_base, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); + glTexParameteri(tex->target_base, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY); + } + else { + glTexParameteri(tex->target_base, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(tex->target_base, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + } + + if (tex->target_base != GL_TEXTURE_1D) { + glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + } + else + glTexParameteri(tex->target_base, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + + return tex; +} + + +GPUTexture *GPU_texture_create_3D(int w, int h, int depth, int channels, const float *fpixels) +{ + GLenum type, format, internalformat; + void *pixels = NULL; + + GPUTexture *tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture"); + tex->w = w; + tex->h = h; + tex->depth = depth; + tex->number = -1; + tex->refcount = 1; + tex->target = GL_TEXTURE_3D; + tex->target_base = GL_TEXTURE_3D; + + glGenTextures(1, &tex->bindcode); + + if (!tex->bindcode) { + fprintf(stderr, "GPUTexture: texture create failed: %d\n", + (int)glGetError()); + GPU_texture_free(tex); + return NULL; + } + + tex->number = 0; + glBindTexture(tex->target, tex->bindcode); + + GPU_ASSERT_NO_GL_ERRORS("3D glBindTexture"); + + type = GL_FLOAT; + if (channels == 4) { + format = GL_RGBA; + internalformat = GL_RGBA8; + } + else { + format = GL_RED; + internalformat = GL_INTENSITY8; + } + + /* 3D textures are quite heavy, test if it's possible to create them first */ + glTexImage3D(GL_PROXY_TEXTURE_3D, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, NULL); + + bool rescale = false; + int r_width; + + glGetTexLevelParameteriv(GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_WIDTH, &r_width); + + while (r_width == 0) { + rescale = true; + tex->w /= 2; + tex->h /= 2; + tex->depth /= 2; + glTexImage3D(GL_PROXY_TEXTURE_3D, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, NULL); + glGetTexLevelParameteriv(GL_PROXY_TEXTURE_3D, 0, GL_TEXTURE_WIDTH, &r_width); + } + + /* really unlikely to happen but keep this just in case */ + tex->w = max_ii(tex->w, 1); + tex->h = max_ii(tex->h, 1); + tex->depth = max_ii(tex->depth, 1); + +#if 0 + if (fpixels) + pixels = GPU_texture_convert_pixels(w*h*depth, fpixels); +#endif + + GPU_ASSERT_NO_GL_ERRORS("3D glTexImage3D"); + + /* hardcore stuff, 3D texture rescaling - warning, this is gonna hurt your performance a lot, but we need it + * for gooseberry */ + if (rescale && fpixels) { + /* FIXME: should these be floating point? */ + const unsigned int xf = w / tex->w, yf = h / tex->h, zf = depth / tex->depth; + float *tex3d = MEM_mallocN(channels * sizeof(float) * tex->w * tex->h * tex->depth, "tex3d"); + + GPU_print_error_debug("You need to scale a 3D texture, feel the pain!"); + + for (unsigned k = 0; k < tex->depth; k++) { + for (unsigned j = 0; j < tex->h; j++) { + for (unsigned i = 0; i < tex->w; i++) { + /* obviously doing nearest filtering here, + * it's going to be slow in any case, let's not make it worse */ + float xb = i * xf; + float yb = j * yf; + float zb = k * zf; + unsigned int offset = k * (tex->w * tex->h) + i * tex->h + j; + unsigned int offset_orig = (zb) * (w * h) + (xb) * h + (yb); + + if (channels == 4) { + tex3d[offset * 4] = fpixels[offset_orig * 4]; + tex3d[offset * 4 + 1] = fpixels[offset_orig * 4 + 1]; + tex3d[offset * 4 + 2] = fpixels[offset_orig * 4 + 2]; + tex3d[offset * 4 + 3] = fpixels[offset_orig * 4 + 3]; + } + else + tex3d[offset] = fpixels[offset_orig]; + } + } + } + + glTexImage3D(tex->target, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, tex3d); + + MEM_freeN(tex3d); + } + else { + if (fpixels) { + glTexImage3D(tex->target, 0, internalformat, tex->w, tex->h, tex->depth, 0, format, type, fpixels); + GPU_ASSERT_NO_GL_ERRORS("3D glTexSubImage3D"); + } + } + + + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); + + if (pixels) + MEM_freeN(pixels); + + GPU_texture_unbind(tex); + + return tex; +} + +GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, int textarget, bool is_data, double time, int mipmap) +{ + int gputt; + /* this binds a texture, so that's why to restore it to 0 */ + GLint bindcode = GPU_verify_image(ima, iuser, textarget, 0, 0, mipmap, is_data); + GPU_update_image_time(ima, time); + + if (textarget == GL_TEXTURE_2D) + gputt = TEXTARGET_TEXTURE_2D; + else + gputt = TEXTARGET_TEXTURE_CUBE_MAP; + + if (ima->gputexture[gputt]) { + ima->gputexture[gputt]->bindcode = bindcode; + glBindTexture(textarget, 0); + return ima->gputexture[gputt]; + } + + GPUTexture *tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture"); + tex->bindcode = bindcode; + tex->number = -1; + tex->refcount = 1; + tex->target = textarget; + tex->target_base = GL_TEXTURE_2D; + tex->fromblender = 1; + + ima->gputexture[gputt] = tex; + + if (!glIsTexture(tex->bindcode)) { + GPU_ASSERT_NO_GL_ERRORS("Blender Texture Not Loaded"); + } + else { + GLint w, h, border; + + GLenum gettarget; + + if (textarget == GL_TEXTURE_2D) + gettarget = GL_TEXTURE_2D; + else + gettarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X; + + glBindTexture(textarget, tex->bindcode); + glGetTexLevelParameteriv(gettarget, 0, GL_TEXTURE_WIDTH, &w); + glGetTexLevelParameteriv(gettarget, 0, GL_TEXTURE_HEIGHT, &h); + glGetTexLevelParameteriv(gettarget, 0, GL_TEXTURE_BORDER, &border); + + tex->w = w - border; + tex->h = h - border; + } + + glBindTexture(textarget, 0); + + return tex; +} + +GPUTexture *GPU_texture_from_preview(PreviewImage *prv, int mipmap) +{ + GPUTexture *tex = prv->gputexture[0]; + GLuint bindcode = 0; + + if (tex) + bindcode = tex->bindcode; + + /* this binds a texture, so that's why we restore it to 0 */ + if (bindcode == 0) { + GPU_create_gl_tex(&bindcode, prv->rect[0], NULL, prv->w[0], prv->h[0], GL_TEXTURE_2D, mipmap, 0, NULL); + } + if (tex) { + tex->bindcode = bindcode; + glBindTexture(GL_TEXTURE_2D, 0); + return tex; + } + + tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture"); + tex->bindcode = bindcode; + tex->number = -1; + tex->refcount = 1; + tex->target = GL_TEXTURE_2D; + tex->target_base = GL_TEXTURE_2D; + + prv->gputexture[0] = tex; + + if (!glIsTexture(tex->bindcode)) { + GPU_ASSERT_NO_GL_ERRORS("Blender Texture Not Loaded"); + } + else { + GLint w, h; + + glBindTexture(GL_TEXTURE_2D, tex->bindcode); + glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &w); + glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &h); + + tex->w = w; + tex->h = h; + } + + glBindTexture(GL_TEXTURE_2D, 0); + + return tex; + +} + +GPUTexture *GPU_texture_create_1D(int w, const float *fpixels, char err_out[256]) +{ + GPUTexture *tex = GPU_texture_create_nD(w, 1, 1, fpixels, 0, GPU_HDR_NONE, 4, 0, err_out); + + if (tex) + GPU_texture_unbind(tex); + + return tex; +} + +GPUTexture *GPU_texture_create_2D(int w, int h, const float *fpixels, GPUHDRType hdr, char err_out[256]) +{ + GPUTexture *tex = GPU_texture_create_nD(w, h, 2, fpixels, 0, hdr, 4, 0, err_out); + + if (tex) + GPU_texture_unbind(tex); + + return tex; +} +GPUTexture *GPU_texture_create_2D_multisample( + int w, int h, const float *fpixels, GPUHDRType hdr, int samples, char err_out[256]) +{ + GPUTexture *tex = GPU_texture_create_nD(w, h, 2, fpixels, 0, hdr, 4, samples, err_out); + + if (tex) + GPU_texture_unbind(tex); + + return tex; +} + +GPUTexture *GPU_texture_create_depth(int w, int h, char err_out[256]) +{ + GPUTexture *tex = GPU_texture_create_nD(w, h, 2, NULL, 1, GPU_HDR_NONE, 1, 0, err_out); + + if (tex) + GPU_texture_unbind(tex); + + return tex; +} +GPUTexture *GPU_texture_create_depth_multisample(int w, int h, int samples, char err_out[256]) +{ + GPUTexture *tex = GPU_texture_create_nD(w, h, 2, NULL, 1, GPU_HDR_NONE, 1, samples, err_out); + + if (tex) + GPU_texture_unbind(tex); + + return tex; +} + +/** + * A shadow map for VSM needs two components (depth and depth^2) + */ +GPUTexture *GPU_texture_create_vsm_shadow_map(int size, char err_out[256]) +{ + GPUTexture *tex = GPU_texture_create_nD(size, size, 2, NULL, 0, GPU_HDR_FULL_FLOAT, 2, 0, err_out); + + if (tex) { + /* Now we tweak some of the settings */ + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + GPU_texture_unbind(tex); + } + + return tex; +} + +GPUTexture *GPU_texture_create_2D_procedural(int w, int h, const float *pixels, bool repeat, char err_out[256]) +{ + GPUTexture *tex = GPU_texture_create_nD(w, h, 2, pixels, 0, GPU_HDR_HALF_FLOAT, 2, 0, err_out); + + if (tex) { + /* Now we tweak some of the settings */ + if (repeat) { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + } + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + + GPU_texture_unbind(tex); + } + + return tex; +} + +GPUTexture *GPU_texture_create_1D_procedural(int w, const float *pixels, char err_out[256]) +{ + GPUTexture *tex = GPU_texture_create_nD(w, 0, 1, pixels, 0, GPU_HDR_HALF_FLOAT, 2, 0, err_out); + + if (tex) { + /* Now we tweak some of the settings */ + glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + + GPU_texture_unbind(tex); + } + + return tex; +} + +void GPU_invalid_tex_init(void) +{ + const float color[4] = {1.0f, 0.0f, 1.0f, 1.0f}; + GG.invalid_tex_1D = GPU_texture_create_1D(1, color, NULL); + GG.invalid_tex_2D = GPU_texture_create_2D(1, 1, color, GPU_HDR_NONE, NULL); + GG.invalid_tex_3D = GPU_texture_create_3D(1, 1, 1, 4, color); +} + +void GPU_invalid_tex_bind(int mode) +{ + switch (mode) { + case GL_TEXTURE_1D: + glBindTexture(GL_TEXTURE_1D, GG.invalid_tex_1D->bindcode); + break; + case GL_TEXTURE_2D: + glBindTexture(GL_TEXTURE_2D, GG.invalid_tex_2D->bindcode); + break; + case GL_TEXTURE_3D: + glBindTexture(GL_TEXTURE_3D, GG.invalid_tex_3D->bindcode); + break; + } +} + +void GPU_invalid_tex_free(void) +{ + if (GG.invalid_tex_1D) + GPU_texture_free(GG.invalid_tex_1D); + if (GG.invalid_tex_2D) + GPU_texture_free(GG.invalid_tex_2D); + if (GG.invalid_tex_3D) + GPU_texture_free(GG.invalid_tex_3D); +} + + +void GPU_texture_bind(GPUTexture *tex, int number) +{ + if (number >= GPU_max_textures()) { + fprintf(stderr, "Not enough texture slots.\n"); + return; + } + + if ((G.debug & G_DEBUG)) { + if (tex->fb && GPU_framebuffer_bound(tex->fb)) { + fprintf(stderr, "Feedback loop warning!: Attempting to bind texture attached to current framebuffer!\n"); + } + } + + if (number < 0) + return; + + GPU_ASSERT_NO_GL_ERRORS("Pre Texture Bind"); + + GLenum arbnumber = (GLenum)((GLuint)GL_TEXTURE0 + number); + if (number != 0) glActiveTexture(arbnumber); + if (tex->bindcode != 0) { + glBindTexture(tex->target, tex->bindcode); + } + else + GPU_invalid_tex_bind(tex->target); + glEnable(tex->target); + if (number != 0) glActiveTexture(GL_TEXTURE0); + + tex->number = number; + + GPU_ASSERT_NO_GL_ERRORS("Post Texture Bind"); +} + +void GPU_texture_unbind(GPUTexture *tex) +{ + if (tex->number >= GPU_max_textures()) { + fprintf(stderr, "Not enough texture slots.\n"); + return; + } + + if (tex->number == -1) + return; + + GPU_ASSERT_NO_GL_ERRORS("Pre Texture Unbind"); + + GLenum arbnumber = (GLenum)((GLuint)GL_TEXTURE0 + tex->number); + if (tex->number != 0) glActiveTexture(arbnumber); + glBindTexture(tex->target, 0); + glDisable(tex->target); + glBindTexture(tex->target_base, 0); + glDisable(tex->target_base); + if (tex->number != 0) glActiveTexture(GL_TEXTURE0); + + tex->number = -1; + + GPU_ASSERT_NO_GL_ERRORS("Post Texture Unbind"); +} + +int GPU_texture_bound_number(GPUTexture *tex) +{ + return tex->number; +} + +void GPU_texture_filter_mode(GPUTexture *tex, bool compare, bool use_filter) +{ + if (tex->number >= GPU_max_textures()) { + fprintf(stderr, "Not enough texture slots.\n"); + return; + } + + if (tex->number == -1) + return; + + GPU_ASSERT_NO_GL_ERRORS("Pre Texture Unbind"); + + GLenum arbnumber = (GLenum)((GLuint)GL_TEXTURE0 + tex->number); + if (tex->number != 0) glActiveTexture(arbnumber); + + if (tex->depth) { + if (compare) + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE); + else + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE); + } + + if (use_filter) { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + } + else { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + } + if (tex->number != 0) glActiveTexture(GL_TEXTURE0); + + GPU_ASSERT_NO_GL_ERRORS("Post Texture Unbind"); +} + +void GPU_texture_free(GPUTexture *tex) +{ + tex->refcount--; + + if (tex->refcount < 0) + fprintf(stderr, "GPUTexture: negative refcount\n"); + + if (tex->refcount == 0) { + if (tex->fb) + GPU_framebuffer_texture_detach(tex); + if (tex->bindcode && !tex->fromblender) + glDeleteTextures(1, &tex->bindcode); + + MEM_freeN(tex); + } +} + +void GPU_texture_ref(GPUTexture *tex) +{ + tex->refcount++; +} + +int GPU_texture_target(const GPUTexture *tex) +{ + return tex->target; +} + +int GPU_texture_width(const GPUTexture *tex) +{ + return tex->w; +} + +int GPU_texture_height(const GPUTexture *tex) +{ + return tex->h; +} + +int GPU_texture_depth(const GPUTexture *tex) +{ + return tex->depth; +} + +int GPU_texture_opengl_bindcode(const GPUTexture *tex) +{ + return tex->bindcode; +} + +GPUFrameBuffer *GPU_texture_framebuffer(GPUTexture *tex) +{ + return tex->fb; +} + +int GPU_texture_framebuffer_attachment(GPUTexture *tex) +{ + return tex->fb_attachment; +} + +void GPU_texture_framebuffer_set(GPUTexture *tex, GPUFrameBuffer *fb, int attachment) +{ + tex->fb = fb; + tex->fb_attachment = attachment; +} + |