📄 s_texture.c
字号:
/*
* Compute nearest mipmap level for given lambda.
*/
#define COMPUTE_NEAREST_MIPMAP_LEVEL(tObj, lambda, level) \
{ \
GLfloat l; \
if (lambda <= 0.5F) \
l = 0.0F; \
else if (lambda > tObj->_MaxLambda + 0.4999F) \
l = tObj->_MaxLambda + 0.4999F; \
else \
l = lambda; \
level = (GLint) (tObj->BaseLevel + l + 0.5F); \
if (level > tObj->_MaxLevel) \
level = tObj->_MaxLevel; \
}
/*
* Note, the FRAC macro has to work perfectly. Otherwise you'll sometimes
* see 1-pixel bands of improperly weighted linear-sampled texels. The
* tests/texwrap.c demo is a good test.
* Also note, FRAC(x) doesn't truly return the fractional part of x for x < 0.
* Instead, if x < 0 then FRAC(x) = 1 - true_frac(x).
*/
#define FRAC(f) ((f) - IFLOOR(f))
/*
* Bitflags for texture border color sampling.
*/
#define I0BIT 1
#define I1BIT 2
#define J0BIT 4
#define J1BIT 8
#define K0BIT 16
#define K1BIT 32
/*
* The lambda[] array values are always monotonic. Either the whole span
* will be minified, magnified, or split between the two. This function
* determines the subranges in [0, n-1] that are to be minified or magnified.
*/
static INLINE void
compute_min_mag_ranges( GLfloat minMagThresh, GLuint n, const GLfloat lambda[],
GLuint *minStart, GLuint *minEnd,
GLuint *magStart, GLuint *magEnd )
{
ASSERT(lambda != NULL);
#if 0
/* Verify that lambda[] is monotonous.
* We can't really use this because the inaccuracy in the LOG2 function
* causes this test to fail, yet the resulting texturing is correct.
*/
if (n > 1) {
GLuint i;
printf("lambda delta = %g\n", lambda[0] - lambda[n-1]);
if (lambda[0] >= lambda[n-1]) { /* decreasing */
for (i = 0; i < n - 1; i++) {
ASSERT((GLint) (lambda[i] * 10) >= (GLint) (lambda[i+1] * 10));
}
}
else { /* increasing */
for (i = 0; i < n - 1; i++) {
ASSERT((GLint) (lambda[i] * 10) <= (GLint) (lambda[i+1] * 10));
}
}
}
#endif /* DEBUG */
/* since lambda is monotonous-array use this check first */
if (lambda[0] <= minMagThresh && lambda[n-1] <= minMagThresh) {
/* magnification for whole span */
*magStart = 0;
*magEnd = n;
*minStart = *minEnd = 0;
}
else if (lambda[0] > minMagThresh && lambda[n-1] > minMagThresh) {
/* minification for whole span */
*minStart = 0;
*minEnd = n;
*magStart = *magEnd = 0;
}
else {
/* a mix of minification and magnification */
GLuint i;
if (lambda[0] > minMagThresh) {
/* start with minification */
for (i = 1; i < n; i++) {
if (lambda[i] <= minMagThresh)
break;
}
*minStart = 0;
*minEnd = i;
*magStart = i;
*magEnd = n;
}
else {
/* start with magnification */
for (i = 1; i < n; i++) {
if (lambda[i] > minMagThresh)
break;
}
*magStart = 0;
*magEnd = i;
*minStart = i;
*minEnd = n;
}
}
#if 0
/* Verify the min/mag Start/End values
* We don't use this either (see above)
*/
{
GLint i;
for (i = 0; i < n; i++) {
if (lambda[i] > minMagThresh) {
/* minification */
ASSERT(i >= *minStart);
ASSERT(i < *minEnd);
}
else {
/* magnification */
ASSERT(i >= *magStart);
ASSERT(i < *magEnd);
}
}
}
#endif
}
/**********************************************************************/
/* 1-D Texture Sampling Functions */
/**********************************************************************/
/*
* Return the texture sample for coordinate (s) using GL_NEAREST filter.
*/
static void
sample_1d_nearest(GLcontext *ctx,
const struct gl_texture_object *tObj,
const struct gl_texture_image *img,
const GLfloat texcoord[4], GLchan rgba[4])
{
const GLint width = img->Width2; /* without border, power of two */
GLint i;
(void) ctx;
COMPUTE_NEAREST_TEXEL_LOCATION(tObj->WrapS, texcoord[0], width, i);
/* skip over the border, if any */
i += img->Border;
if (i < 0 || i >= (GLint) img->Width) {
/* Need this test for GL_CLAMP_TO_BORDER mode */
COPY_CHAN4(rgba, tObj->_BorderChan);
}
else {
img->FetchTexelc(img, i, 0, 0, rgba);
}
}
/*
* Return the texture sample for coordinate (s) using GL_LINEAR filter.
*/
static void
sample_1d_linear(GLcontext *ctx,
const struct gl_texture_object *tObj,
const struct gl_texture_image *img,
const GLfloat texcoord[4], GLchan rgba[4])
{
const GLint width = img->Width2;
GLint i0, i1;
GLfloat u;
GLuint useBorderColor;
(void) ctx;
COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj->WrapS, texcoord[0], u, width, i0, i1);
useBorderColor = 0;
if (img->Border) {
i0 += img->Border;
i1 += img->Border;
}
else {
if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT;
if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT;
}
{
const GLfloat a = FRAC(u);
GLchan t0[4], t1[4]; /* texels */
/* fetch texel colors */
if (useBorderColor & I0BIT) {
COPY_CHAN4(t0, tObj->_BorderChan);
}
else {
img->FetchTexelc(img, i0, 0, 0, t0);
}
if (useBorderColor & I1BIT) {
COPY_CHAN4(t1, tObj->_BorderChan);
}
else {
img->FetchTexelc(img, i1, 0, 0, t1);
}
/* do linear interpolation of texel colors */
#if CHAN_TYPE == GL_FLOAT
rgba[0] = LERP(a, t0[0], t1[0]);
rgba[1] = LERP(a, t0[1], t1[1]);
rgba[2] = LERP(a, t0[2], t1[2]);
rgba[3] = LERP(a, t0[3], t1[3]);
#elif CHAN_TYPE == GL_UNSIGNED_SHORT
rgba[0] = (GLchan) (LERP(a, t0[0], t1[0]) + 0.5);
rgba[1] = (GLchan) (LERP(a, t0[1], t1[1]) + 0.5);
rgba[2] = (GLchan) (LERP(a, t0[2], t1[2]) + 0.5);
rgba[3] = (GLchan) (LERP(a, t0[3], t1[3]) + 0.5);
#else
ASSERT(CHAN_TYPE == GL_UNSIGNED_BYTE);
{
/* fixed point interpolants in [0, ILERP_SCALE] */
const GLint ia = IROUND_POS(a * ILERP_SCALE);
rgba[0] = ILERP(ia, t0[0], t1[0]);
rgba[1] = ILERP(ia, t0[1], t1[1]);
rgba[2] = ILERP(ia, t0[2], t1[2]);
rgba[3] = ILERP(ia, t0[3], t1[3]);
}
#endif
}
}
static void
sample_1d_nearest_mipmap_nearest(GLcontext *ctx,
const struct gl_texture_object *tObj,
GLuint n, const GLfloat texcoord[][4],
const GLfloat lambda[], GLchan rgba[][4])
{
GLuint i;
ASSERT(lambda != NULL);
for (i = 0; i < n; i++) {
GLint level;
COMPUTE_NEAREST_MIPMAP_LEVEL(tObj, lambda[i], level);
sample_1d_nearest(ctx, tObj, tObj->Image[0][level], texcoord[i], rgba[i]);
}
}
static void
sample_1d_linear_mipmap_nearest(GLcontext *ctx,
const struct gl_texture_object *tObj,
GLuint n, const GLfloat texcoord[][4],
const GLfloat lambda[], GLchan rgba[][4])
{
GLuint i;
ASSERT(lambda != NULL);
for (i = 0; i < n; i++) {
GLint level;
COMPUTE_NEAREST_MIPMAP_LEVEL(tObj, lambda[i], level);
sample_1d_linear(ctx, tObj, tObj->Image[0][level], texcoord[i], rgba[i]);
}
}
/*
* This is really just needed in order to prevent warnings with some compilers.
*/
#if CHAN_TYPE == GL_FLOAT
#define CHAN_CAST
#else
#define CHAN_CAST (GLchan) (GLint)
#endif
static void
sample_1d_nearest_mipmap_linear(GLcontext *ctx,
const struct gl_texture_object *tObj,
GLuint n, const GLfloat texcoord[][4],
const GLfloat lambda[], GLchan rgba[][4])
{
GLuint i;
ASSERT(lambda != NULL);
for (i = 0; i < n; i++) {
GLint level;
COMPUTE_LINEAR_MIPMAP_LEVEL(tObj, lambda[i], level);
if (level >= tObj->_MaxLevel) {
sample_1d_nearest(ctx, tObj, tObj->Image[0][tObj->_MaxLevel],
texcoord[i], rgba[i]);
}
else {
GLchan t0[4], t1[4];
const GLfloat f = FRAC(lambda[i]);
sample_1d_nearest(ctx, tObj, tObj->Image[0][level ], texcoord[i], t0);
sample_1d_nearest(ctx, tObj, tObj->Image[0][level+1], texcoord[i], t1);
rgba[i][RCOMP] = CHAN_CAST ((1.0F-f) * t0[RCOMP] + f * t1[RCOMP]);
rgba[i][GCOMP] = CHAN_CAST ((1.0F-f) * t0[GCOMP] + f * t1[GCOMP]);
rgba[i][BCOMP] = CHAN_CAST ((1.0F-f) * t0[BCOMP] + f * t1[BCOMP]);
rgba[i][ACOMP] = CHAN_CAST ((1.0F-f) * t0[ACOMP] + f * t1[ACOMP]);
}
}
}
static void
sample_1d_linear_mipmap_linear(GLcontext *ctx,
const struct gl_texture_object *tObj,
GLuint n, const GLfloat texcoord[][4],
const GLfloat lambda[], GLchan rgba[][4])
{
GLuint i;
ASSERT(lambda != NULL);
for (i = 0; i < n; i++) {
GLint level;
COMPUTE_LINEAR_MIPMAP_LEVEL(tObj, lambda[i], level);
if (level >= tObj->_MaxLevel) {
sample_1d_linear(ctx, tObj, tObj->Image[0][tObj->_MaxLevel],
texcoord[i], rgba[i]);
}
else {
GLchan t0[4], t1[4];
const GLfloat f = FRAC(lambda[i]);
sample_1d_linear(ctx, tObj, tObj->Image[0][level ], texcoord[i], t0);
sample_1d_linear(ctx, tObj, tObj->Image[0][level+1], texcoord[i], t1);
rgba[i][RCOMP] = CHAN_CAST ((1.0F-f) * t0[RCOMP] + f * t1[RCOMP]);
rgba[i][GCOMP] = CHAN_CAST ((1.0F-f) * t0[GCOMP] + f * t1[GCOMP]);
rgba[i][BCOMP] = CHAN_CAST ((1.0F-f) * t0[BCOMP] + f * t1[BCOMP]);
rgba[i][ACOMP] = CHAN_CAST ((1.0F-f) * t0[ACOMP] + f * t1[ACOMP]);
}
}
}
static void
sample_nearest_1d( GLcontext *ctx, GLuint texUnit,
const struct gl_texture_object *tObj, GLuint n,
const GLfloat texcoords[][4], const GLfloat lambda[],
GLchan rgba[][4] )
{
GLuint i;
struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel];
(void) texUnit;
(void) lambda;
for (i=0;i<n;i++) {
sample_1d_nearest(ctx, tObj, image, texcoords[i], rgba[i]);
}
}
static void
sample_linear_1d( GLcontext *ctx, GLuint texUnit,
const struct gl_texture_object *tObj, GLuint n,
const GLfloat texcoords[][4], const GLfloat lambda[],
GLchan rgba[][4] )
{
GLuint i;
struct gl_texture_image *image = tObj->Image[0][tObj->BaseLevel];
(void) texUnit;
(void) lambda;
for (i=0;i<n;i++) {
sample_1d_linear(ctx, tObj, image, texcoords[i], rgba[i]);
}
}
/*
* Given an (s) texture coordinate and lambda (level of detail) value,
* return a texture sample.
*
*/
static void
sample_lambda_1d( GLcontext *ctx, GLuint texUnit,
const struct gl_texture_object *tObj, GLuint n,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -