📄 s_texfilter.c
字号:
/* * Mesa 3-D graphics library * Version: 7.0.3 * * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */#include "glheader.h"#include "context.h"#include "colormac.h"#include "imports.h"#include "texformat.h"#include "s_context.h"#include "s_texfilter.h"/** * Constants for integer linear interpolation. */#define ILERP_SCALE 65536.0F#define ILERP_SHIFT 16/** * Linear interpolation macros */#define LERP(T, A, B) ( (A) + (T) * ((B) - (A)) )#define ILERP(IT, A, B) ( (A) + (((IT) * ((B) - (A))) >> ILERP_SHIFT) )/** * Do 2D/biliner interpolation of float values. * v00, v10, v01 and v11 are typically four texture samples in a square/box. * a and b are the horizontal and vertical interpolants. * It's important that this function is inlined when compiled with * optimization! If we find that's not true on some systems, convert * to a macro. */static INLINE GLfloatlerp_2d(GLfloat a, GLfloat b, GLfloat v00, GLfloat v10, GLfloat v01, GLfloat v11){ const GLfloat temp0 = LERP(a, v00, v10); const GLfloat temp1 = LERP(a, v01, v11); return LERP(b, temp0, temp1);}/** * Do 2D/biliner interpolation of integer values. * \sa lerp_2d */static INLINE GLintilerp_2d(GLint ia, GLint ib, GLint v00, GLint v10, GLint v01, GLint v11){ /* fixed point interpolants in [0, ILERP_SCALE] */ const GLint temp0 = ILERP(ia, v00, v10); const GLint temp1 = ILERP(ia, v01, v11); return ILERP(ib, temp0, temp1);}/** * Do 3D/trilinear interpolation of float values. * \sa lerp_2d */static INLINE GLfloatlerp_3d(GLfloat a, GLfloat b, GLfloat c, GLfloat v000, GLfloat v100, GLfloat v010, GLfloat v110, GLfloat v001, GLfloat v101, GLfloat v011, GLfloat v111){ const GLfloat temp00 = LERP(a, v000, v100); const GLfloat temp10 = LERP(a, v010, v110); const GLfloat temp01 = LERP(a, v001, v101); const GLfloat temp11 = LERP(a, v011, v111); const GLfloat temp0 = LERP(b, temp00, temp10); const GLfloat temp1 = LERP(b, temp01, temp11); return LERP(c, temp0, temp1);}/** * Do 3D/trilinear interpolation of integer values. * \sa lerp_2d */static INLINE GLintilerp_3d(GLint ia, GLint ib, GLint ic, GLint v000, GLint v100, GLint v010, GLint v110, GLint v001, GLint v101, GLint v011, GLint v111){ /* fixed point interpolants in [0, ILERP_SCALE] */ const GLint temp00 = ILERP(ia, v000, v100); const GLint temp10 = ILERP(ia, v010, v110); const GLint temp01 = ILERP(ia, v001, v101); const GLint temp11 = ILERP(ia, v011, v111); const GLint temp0 = ILERP(ib, temp00, temp10); const GLint temp1 = ILERP(ib, temp01, temp11); return ILERP(ic, temp0, temp1);}/** * Do linear interpolation of colors. */static INLINE voidlerp_rgba(GLchan result[4], GLfloat t, const GLchan a[4], const GLchan b[4]){#if CHAN_TYPE == GL_FLOAT result[0] = LERP(t, a[0], b[0]); result[1] = LERP(t, a[1], b[1]); result[2] = LERP(t, a[2], b[2]); result[3] = LERP(t, a[3], b[3]);#elif CHAN_TYPE == GL_UNSIGNED_SHORT result[0] = (GLchan) (LERP(t, a[0], b[0]) + 0.5); result[1] = (GLchan) (LERP(t, a[1], b[1]) + 0.5); result[2] = (GLchan) (LERP(t, a[2], b[2]) + 0.5); result[3] = (GLchan) (LERP(t, a[3], b[3]) + 0.5);#else /* fixed point interpolants in [0, ILERP_SCALE] */ const GLint it = IROUND_POS(t * ILERP_SCALE); ASSERT(CHAN_TYPE == GL_UNSIGNED_BYTE); result[0] = ILERP(it, a[0], b[0]); result[1] = ILERP(it, a[1], b[1]); result[2] = ILERP(it, a[2], b[2]); result[3] = ILERP(it, a[3], b[3]);#endif}/** * Do bilinear interpolation of colors. */static INLINE voidlerp_rgba_2d(GLchan result[4], GLfloat a, GLfloat b, const GLchan t00[4], const GLchan t10[4], const GLchan t01[4], const GLchan t11[4]){#if CHAN_TYPE == GL_FLOAT result[0] = lerp_2d(a, b, t00[0], t10[0], t01[0], t11[0]); result[1] = lerp_2d(a, b, t00[1], t10[1], t01[1], t11[1]); result[2] = lerp_2d(a, b, t00[2], t10[2], t01[2], t11[2]); result[3] = lerp_2d(a, b, t00[3], t10[3], t01[3], t11[3]);#elif CHAN_TYPE == GL_UNSIGNED_SHORT result[0] = (GLchan) (lerp_2d(a, b, t00[0], t10[0], t01[0], t11[0]) + 0.5); result[1] = (GLchan) (lerp_2d(a, b, t00[1], t10[1], t01[1], t11[1]) + 0.5); result[2] = (GLchan) (lerp_2d(a, b, t00[2], t10[2], t01[2], t11[2]) + 0.5); result[3] = (GLchan) (lerp_2d(a, b, t00[3], t10[3], t01[3], t11[3]) + 0.5);#else const GLint ia = IROUND_POS(a * ILERP_SCALE); const GLint ib = IROUND_POS(b * ILERP_SCALE); ASSERT(CHAN_TYPE == GL_UNSIGNED_BYTE); result[0] = ilerp_2d(ia, ib, t00[0], t10[0], t01[0], t11[0]); result[1] = ilerp_2d(ia, ib, t00[1], t10[1], t01[1], t11[1]); result[2] = ilerp_2d(ia, ib, t00[2], t10[2], t01[2], t11[2]); result[3] = ilerp_2d(ia, ib, t00[3], t10[3], t01[3], t11[3]);#endif}/** * Do trilinear interpolation of colors. */static INLINE voidlerp_rgba_3d(GLchan result[4], GLfloat a, GLfloat b, GLfloat c, const GLchan t000[4], const GLchan t100[4], const GLchan t010[4], const GLchan t110[4], const GLchan t001[4], const GLchan t101[4], const GLchan t011[4], const GLchan t111[4]){ GLuint k; /* compiler should unroll these short loops */#if CHAN_TYPE == GL_FLOAT for (k = 0; k < 4; k++) { result[k] = lerp_3d(a, b, c, t000[k], t100[k], t010[k], t110[k], t001[k], t101[k], t011[k], t111[k]); }#elif CHAN_TYPE == GL_UNSIGNED_SHORT for (k = 0; k < 4; k++) { result[k] = (GLchan)(lerp_3d(a, b, c, t000[k], t100[k], t010[k], t110[k], t001[k], t101[k], t011[k], t111[k]) + 0.5F); }#else GLint ia = IROUND_POS(a * ILERP_SCALE); GLint ib = IROUND_POS(b * ILERP_SCALE); GLint ic = IROUND_POS(c * ILERP_SCALE); for (k = 0; k < 4; k++) { result[k] = ilerp_3d(ia, ib, ic, t000[k], t100[k], t010[k], t110[k], t001[k], t101[k], t011[k], t111[k]); }#endif}/** * If A is a signed integer, A % B doesn't give the right value for A < 0 * (in terms of texture repeat). Just casting to unsigned fixes that. */#define REMAINDER(A, B) ((unsigned) (A) % (unsigned) (B))/** * Used to compute texel locations for linear sampling. * Input: * wrapMode = GL_REPEAT, GL_CLAMP, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_BORDER * S = texcoord in [0,1] * SIZE = width (or height or depth) of texture * Output: * U = texcoord in [0, width] * I0, I1 = two nearest texel indexes */#define COMPUTE_LINEAR_TEXEL_LOCATIONS(wrapMode, S, U, SIZE, I0, I1) \{ \ switch (wrapMode) { \ case GL_REPEAT: \ U = S * SIZE - 0.5F; \ if (img->_IsPowerOfTwo) { \ I0 = IFLOOR(U) & (SIZE - 1); \ I1 = (I0 + 1) & (SIZE - 1); \ } \ else { \ I0 = REMAINDER(IFLOOR(U), SIZE); \ I1 = REMAINDER(I0 + 1, SIZE); \ } \ break; \ case GL_CLAMP_TO_EDGE: \ if (S <= 0.0F) \ U = 0.0F; \ else if (S >= 1.0F) \ U = (GLfloat) SIZE; \ else \ U = S * SIZE; \ U -= 0.5F; \ I0 = IFLOOR(U); \ I1 = I0 + 1; \ if (I0 < 0) \ I0 = 0; \ if (I1 >= (GLint) SIZE) \ I1 = SIZE - 1; \ break; \ case GL_CLAMP_TO_BORDER: \ { \ const GLfloat min = -1.0F / (2.0F * SIZE); \ const GLfloat max = 1.0F - min; \ if (S <= min) \ U = min * SIZE; \ else if (S >= max) \ U = max * SIZE; \ else \ U = S * SIZE; \ U -= 0.5F; \ I0 = IFLOOR(U); \ I1 = I0 + 1; \ } \ break; \ case GL_MIRRORED_REPEAT: \ { \ const GLint flr = IFLOOR(S); \ if (flr & 1) \ U = 1.0F - (S - (GLfloat) flr); /* flr is odd */ \ else \ U = S - (GLfloat) flr; /* flr is even */ \ U = (U * SIZE) - 0.5F; \ I0 = IFLOOR(U); \ I1 = I0 + 1; \ if (I0 < 0) \ I0 = 0; \ if (I1 >= (GLint) SIZE) \ I1 = SIZE - 1; \ } \ break; \ case GL_MIRROR_CLAMP_EXT: \ U = FABSF(S); \ if (U >= 1.0F) \ U = (GLfloat) SIZE; \ else \ U *= SIZE; \ U -= 0.5F; \ I0 = IFLOOR(U); \ I1 = I0 + 1; \ break; \ case GL_MIRROR_CLAMP_TO_EDGE_EXT: \ U = FABSF(S); \ if (U >= 1.0F) \ U = (GLfloat) SIZE; \ else \ U *= SIZE; \ U -= 0.5F; \ I0 = IFLOOR(U); \ I1 = I0 + 1; \ if (I0 < 0) \ I0 = 0; \ if (I1 >= (GLint) SIZE) \ I1 = SIZE - 1; \ break; \ case GL_MIRROR_CLAMP_TO_BORDER_EXT: \ { \ const GLfloat min = -1.0F / (2.0F * SIZE); \ const GLfloat max = 1.0F - min; \ U = FABSF(S); \ if (U <= min) \ U = min * SIZE; \ else if (U >= max) \ U = max * SIZE; \ else \ U *= SIZE; \ U -= 0.5F; \ I0 = IFLOOR(U); \ I1 = I0 + 1; \ } \ break; \ case GL_CLAMP: \ if (S <= 0.0F) \ U = 0.0F; \ else if (S >= 1.0F) \ U = (GLfloat) SIZE; \ else \ U = S * SIZE; \ U -= 0.5F; \ I0 = IFLOOR(U); \ I1 = I0 + 1; \ break; \ default: \ _mesa_problem(ctx, "Bad wrap mode"); \ return; \ } \}/** * Used to compute texel location for nearest sampling. */#define COMPUTE_NEAREST_TEXEL_LOCATION(wrapMode, S, SIZE, I) \{ \ switch (wrapMode) { \ case GL_REPEAT: \ /* s limited to [0,1) */ \ /* i limited to [0,size-1] */ \ I = IFLOOR(S * SIZE); \ if (img->_IsPowerOfTwo) \ I &= (SIZE - 1); \ else \ I = REMAINDER(I, SIZE); \ break; \ case GL_CLAMP_TO_EDGE: \ { \ /* s limited to [min,max] */ \ /* i limited to [0, size-1] */ \ const GLfloat min = 1.0F / (2.0F * SIZE); \ const GLfloat max = 1.0F - min; \ if (S < min) \ I = 0; \ else if (S > max) \ I = SIZE - 1; \ else \ I = IFLOOR(S * SIZE); \ } \ break; \ case GL_CLAMP_TO_BORDER: \ { \ /* s limited to [min,max] */ \ /* i limited to [-1, size] */ \ const GLfloat min = -1.0F / (2.0F * SIZE); \ const GLfloat max = 1.0F - min; \ if (S <= min) \ I = -1; \ else if (S >= max) \ I = SIZE; \ else \ I = IFLOOR(S * SIZE); \ } \ break; \ case GL_MIRRORED_REPEAT: \ { \ const GLfloat min = 1.0F / (2.0F * SIZE); \ const GLfloat max = 1.0F - min; \ const GLint flr = IFLOOR(S); \ GLfloat u; \ if (flr & 1) \ u = 1.0F - (S - (GLfloat) flr); /* flr is odd */ \ else \ u = S - (GLfloat) flr; /* flr is even */ \ if (u < min) \ I = 0; \ else if (u > max) \ I = SIZE - 1; \ else \ I = IFLOOR(u * SIZE); \ } \ break; \ case GL_MIRROR_CLAMP_EXT: \
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -