glm::vec4 ImageTexture:: evaluate_bilinear(int level, glm::vec2 const& uv) const { cg_assert(level >= 0 && level < static_cast<int>(mip_levels.size())); cg_assert(mip_levels[level]); int const width = mip_levels[level]->getWidth(); int const height = mip_levels[level]->getHeight(); float fs = uv[0]*width+0.5f; float ft = uv[1]*height+0.5f; float const ffs = std::floor(fs); float const fft = std::floor(ft); float const ws = fs - ffs; float const wt = ft - fft; return (1.f-ws) * (1.f-wt) * get_texel(level, ffs-1, fft-1) + (1.f-ws) * ( wt) * get_texel(level, ffs-1, fft) + ( ws) * (1.f-wt) * get_texel(level, ffs, fft-1) + ( ws) * ( wt) * get_texel(level, ffs, fft); }
glm::vec4 ImageTexture:: evaluate_nearest(int level, glm::vec2 const& uv) const { cg_assert(level >= 0 && level < static_cast<int>(mip_levels.size())); cg_assert(mip_levels[level]); int const width = mip_levels[level]->getWidth(); int const height = mip_levels[level]->getHeight(); int const s = (int)std::floor(uv[0]*width); int const t = (int)std::floor(uv[1]*height); return get_texel(level, s, t); }
/* * Evaluates a texture for the given uv-coordinate without filtering. * * This method transformes the uv-coordinate into a st-coordinate and * rounds down to integer pixel values. * * The parameter level in [0, mip_levels.size()-1] is the miplevel of * the texture that is to be evaluated. */ glm::vec4 ImageTexture:: evaluate_nearest(int level, glm::vec2 const& uv) const { cg_assert(level >= 0 && level < static_cast<int>(mip_levels.size())); cg_assert(mip_levels[level]); // TODO: compute the st-coordinates for the given uv-coordinates and mipmap level int s = floor(mip_levels[level]->getWidth() * uv[0]); int t = floor(mip_levels[level]->getHeight() * uv[1]); // get the value of pixel (s, t) of miplevel level return get_texel(level, s, t); }
Color4f TextureSource::sample_texture( TextureCache& texture_cache, const Vector2d& uv) const { // Start with the transformed input texture coordinates. Vector2d p = apply_transform(uv); p.y = 1.0 - p.y; // Apply the texture addressing mode. apply_addressing_mode(m_texture_instance.get_addressing_mode(), p); switch (m_texture_instance.get_filtering_mode()) { case TextureFilteringNearest: { p.x = clamp(p.x * m_scalar_canvas_width, 0.0, m_max_x); p.y = clamp(p.y * m_scalar_canvas_height, 0.0, m_max_y); const size_t ix = truncate<size_t>(p.x); const size_t iy = truncate<size_t>(p.y); return get_texel(texture_cache, ix, iy); } case TextureFilteringBilinear: { p.x *= m_max_x; p.y *= m_max_y; const int ix = truncate<int>(p.x); const int iy = truncate<int>(p.y); // Retrieve the four surrounding texels. Color4f t00, t10, t01, t11; get_texels_2x2( texture_cache, ix, iy, t00, t10, t01, t11); // Compute weights. const float wx1 = static_cast<float>(p.x - ix); const float wy1 = static_cast<float>(p.y - iy); const float wx0 = 1.0f - wx1; const float wy0 = 1.0f - wy1; // Apply weights. t00 *= wx0 * wy0; t10 *= wx1 * wy0; t01 *= wx0 * wy1; t11 *= wx1 * wy1; // Accumulate. t00 += t10; t00 += t01; t00 += t11; return t00; } default: assert(!"Wrong texture filtering mode."); return Color4f(0.0f); } }
glm::vec4 ImageTexture:: evaluate_bilinear(int level, glm::vec2 const& uv) const { cg_assert(level >= 0 && level < static_cast<int>(mip_levels.size())); cg_assert(mip_levels[level]); const int width = mip_levels[level]->getWidth(), height = mip_levels[level]->getHeight(); float intpart = 0.f; const glm::vec2 st{ uv[0] * width, uv[1] * height }; //texel coordinates // (x1, y1) (x2, y1) // // (x1, y2) (x2, y2) //y coords of neighbouring texels, weight b float mod_t = std::modf(st[1], &intpart); mod_t += (mod_t < 0.f) ? 1.f : 0.f; //fractional part should be positive float w2 = mod_t; //weight b int y1 = floor(st[1]); int y2 = ceil(st[1]); if (y1 == y2) //mod_t == 0 { --y1; w2 = 0.5f; } else if (mod_t < 0.5f) { --y1; --y2; w2 += 0.5f; } else if (mod_t == 0.5f) { --y1; --y2; w2 = 1.0f; } else //mod_t > 0.5f w2 -= 0.5f; //calculate x coords of neighbouring texels, weight a float mod_s = std::modf(st[0], &intpart); mod_s += (mod_s < 0.f) ? 1.f : 0.f; //fractional part should be positive float w1 = mod_s; //weight 1 int x1 = floor(st[0]); int x2 = ceil(st[0]); if (x1 == x2) //mod_s == 0 { --x1; w1 = 0.5f; } else if (mod_s < 0.5f) { --x1; --x2; w1 += 0.5f; } else if (mod_s == 0.5f) { --x1; --x2; w1 = 1.0f; } else //mod_s > 0.5f w1 -= 0.5f; // linear interpolations glm::vec4 t34 = (1.f - w1) * get_texel(level, x1, y2) + w1 * get_texel(level, x2, y2); glm::vec4 t12 = (1.f - w1) * get_texel(level, x1, y1) + w1 * get_texel(level, x2, y1); //linear interpolation vertically return (1.f - w2) * t12 + w2 * t34; }
static INLINE void sp_get_samples_3d(const struct tgsi_sampler *tgsi_sampler, const float s[QUAD_SIZE], const float t[QUAD_SIZE], const float p[QUAD_SIZE], boolean computeLambda, float lodbias, float rgba[NUM_CHANNELS][QUAD_SIZE]) { const struct sp_shader_sampler *samp = sp_shader_sampler(tgsi_sampler); const struct softpipe_context *sp = samp->sp; const uint unit = samp->unit; const struct pipe_texture *texture = sp->texture[unit]; const struct pipe_sampler_state *sampler = sp->sampler[unit]; /* get/map pipe_surfaces corresponding to 3D tex slices */ unsigned level0, level1, j, imgFilter; int width, height, depth; float levelBlend; const uint face = 0; choose_mipmap_levels(texture, sampler, s, t, p, computeLambda, lodbias, &level0, &level1, &levelBlend, &imgFilter); assert(sampler->normalized_coords); width = texture->width[level0]; height = texture->height[level0]; depth = texture->depth[level0]; assert(width > 0); assert(height > 0); assert(depth > 0); switch (imgFilter) { case PIPE_TEX_FILTER_NEAREST: { int x[4], y[4], z[4]; nearest_texcoord_4(sampler->wrap_s, s, width, x); nearest_texcoord_4(sampler->wrap_t, t, height, y); nearest_texcoord_4(sampler->wrap_r, p, depth, z); for (j = 0; j < QUAD_SIZE; j++) { get_texel(tgsi_sampler, face, level0, x[j], y[j], z[j], rgba, j); if (level0 != level1) { /* get texels from second mipmap level and blend */ float rgba2[4][4]; unsigned c; x[j] /= 2; y[j] /= 2; z[j] /= 2; get_texel(tgsi_sampler, face, level1, x[j], y[j], z[j], rgba2, j); for (c = 0; c < NUM_CHANNELS; c++) { rgba[c][j] = lerp(levelBlend, rgba2[c][j], rgba[c][j]); } } } } break; case PIPE_TEX_FILTER_LINEAR: case PIPE_TEX_FILTER_ANISO: { int x0[4], x1[4], y0[4], y1[4], z0[4], z1[4]; float xw[4], yw[4], zw[4]; /* interpolation weights */ linear_texcoord_4(sampler->wrap_s, s, width, x0, x1, xw); linear_texcoord_4(sampler->wrap_t, t, height, y0, y1, yw); linear_texcoord_4(sampler->wrap_r, p, depth, z0, z1, zw); for (j = 0; j < QUAD_SIZE; j++) { int c; float tx0[4][4], tx1[4][4]; get_texel(tgsi_sampler, face, level0, x0[j], y0[j], z0[j], tx0, 0); get_texel(tgsi_sampler, face, level0, x1[j], y0[j], z0[j], tx0, 1); get_texel(tgsi_sampler, face, level0, x0[j], y1[j], z0[j], tx0, 2); get_texel(tgsi_sampler, face, level0, x1[j], y1[j], z0[j], tx0, 3); get_texel(tgsi_sampler, face, level0, x0[j], y0[j], z1[j], tx1, 0); get_texel(tgsi_sampler, face, level0, x1[j], y0[j], z1[j], tx1, 1); get_texel(tgsi_sampler, face, level0, x0[j], y1[j], z1[j], tx1, 2); get_texel(tgsi_sampler, face, level0, x1[j], y1[j], z1[j], tx1, 3); /* interpolate R, G, B, A */ for (c = 0; c < 4; c++) { rgba[c][j] = lerp_3d(xw[j], yw[j], zw[j], tx0[c][0], tx0[c][1], tx0[c][2], tx0[c][3], tx1[c][0], tx1[c][1], tx1[c][2], tx1[c][3]); } if (level0 != level1) { /* get texels from second mipmap level and blend */ float rgba2[4][4]; x0[j] /= 2; y0[j] /= 2; z0[j] /= 2; x1[j] /= 2; y1[j] /= 2; z1[j] /= 2; get_texel(tgsi_sampler, face, level1, x0[j], y0[j], z0[j], tx0, 0); get_texel(tgsi_sampler, face, level1, x1[j], y0[j], z0[j], tx0, 1); get_texel(tgsi_sampler, face, level1, x0[j], y1[j], z0[j], tx0, 2); get_texel(tgsi_sampler, face, level1, x1[j], y1[j], z0[j], tx0, 3); get_texel(tgsi_sampler, face, level1, x0[j], y0[j], z1[j], tx1, 0); get_texel(tgsi_sampler, face, level1, x1[j], y0[j], z1[j], tx1, 1); get_texel(tgsi_sampler, face, level1, x0[j], y1[j], z1[j], tx1, 2); get_texel(tgsi_sampler, face, level1, x1[j], y1[j], z1[j], tx1, 3); /* interpolate R, G, B, A */ for (c = 0; c < 4; c++) { rgba2[c][j] = lerp_3d(xw[j], yw[j], zw[j], tx0[c][0], tx0[c][1], tx0[c][2], tx0[c][3], tx1[c][0], tx1[c][1], tx1[c][2], tx1[c][3]); } /* blend mipmap levels */ for (c = 0; c < NUM_CHANNELS; c++) { rgba[c][j] = lerp(levelBlend, rgba[c][j], rgba2[c][j]); } } } } break; default: assert(0); } }
/** * Common code for sampling 1D/2D/cube textures. * Could probably extend for 3D... */ static void sp_get_samples_2d_common(const struct tgsi_sampler *tgsi_sampler, const float s[QUAD_SIZE], const float t[QUAD_SIZE], const float p[QUAD_SIZE], boolean computeLambda, float lodbias, float rgba[NUM_CHANNELS][QUAD_SIZE], const unsigned faces[4]) { const struct sp_shader_sampler *samp = sp_shader_sampler(tgsi_sampler); const struct softpipe_context *sp = samp->sp; const uint unit = samp->unit; const struct pipe_texture *texture = sp->texture[unit]; const struct pipe_sampler_state *sampler = sp->sampler[unit]; const uint compare_func = sampler->compare_func; unsigned level0, level1, j, imgFilter; int width, height; float levelBlend; choose_mipmap_levels(texture, sampler, s, t, p, computeLambda, lodbias, &level0, &level1, &levelBlend, &imgFilter); assert(sampler->normalized_coords); width = texture->width[level0]; height = texture->height[level0]; assert(width > 0); switch (imgFilter) { case PIPE_TEX_FILTER_NEAREST: { int x[4], y[4]; nearest_texcoord_4(sampler->wrap_s, s, width, x); nearest_texcoord_4(sampler->wrap_t, t, height, y); for (j = 0; j < QUAD_SIZE; j++) { get_texel(tgsi_sampler, faces[j], level0, x[j], y[j], 0, rgba, j); if (sampler->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) { shadow_compare(compare_func, rgba, p, j); } if (level0 != level1) { /* get texels from second mipmap level and blend */ float rgba2[4][4]; unsigned c; x[j] /= 2; y[j] /= 2; get_texel(tgsi_sampler, faces[j], level1, x[j], y[j], 0, rgba2, j); if (sampler->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE){ shadow_compare(compare_func, rgba2, p, j); } for (c = 0; c < NUM_CHANNELS; c++) { rgba[c][j] = lerp(levelBlend, rgba[c][j], rgba2[c][j]); } } } } break; case PIPE_TEX_FILTER_LINEAR: case PIPE_TEX_FILTER_ANISO: { int x0[4], y0[4], x1[4], y1[4]; float xw[4], yw[4]; /* weights */ linear_texcoord_4(sampler->wrap_s, s, width, x0, x1, xw); linear_texcoord_4(sampler->wrap_t, t, height, y0, y1, yw); for (j = 0; j < QUAD_SIZE; j++) { float tx[4][4]; /* texels */ int c; get_texel(tgsi_sampler, faces[j], level0, x0[j], y0[j], 0, tx, 0); get_texel(tgsi_sampler, faces[j], level0, x1[j], y0[j], 0, tx, 1); get_texel(tgsi_sampler, faces[j], level0, x0[j], y1[j], 0, tx, 2); get_texel(tgsi_sampler, faces[j], level0, x1[j], y1[j], 0, tx, 3); if (sampler->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE) { shadow_compare(compare_func, tx, p, 0); shadow_compare(compare_func, tx, p, 1); shadow_compare(compare_func, tx, p, 2); shadow_compare(compare_func, tx, p, 3); } /* interpolate R, G, B, A */ for (c = 0; c < 4; c++) { rgba[c][j] = lerp_2d(xw[j], yw[j], tx[c][0], tx[c][1], tx[c][2], tx[c][3]); } if (level0 != level1) { /* get texels from second mipmap level and blend */ float rgba2[4][4]; x0[j] /= 2; y0[j] /= 2; x1[j] /= 2; y1[j] /= 2; get_texel(tgsi_sampler, faces[j], level1, x0[j], y0[j], 0, tx, 0); get_texel(tgsi_sampler, faces[j], level1, x1[j], y0[j], 0, tx, 1); get_texel(tgsi_sampler, faces[j], level1, x0[j], y1[j], 0, tx, 2); get_texel(tgsi_sampler, faces[j], level1, x1[j], y1[j], 0, tx, 3); if (sampler->compare_mode == PIPE_TEX_COMPARE_R_TO_TEXTURE){ shadow_compare(compare_func, tx, p, 0); shadow_compare(compare_func, tx, p, 1); shadow_compare(compare_func, tx, p, 2); shadow_compare(compare_func, tx, p, 3); } /* interpolate R, G, B, A */ for (c = 0; c < 4; c++) { rgba2[c][j] = lerp_2d(xw[j], yw[j], tx[c][0], tx[c][1], tx[c][2], tx[c][3]); } for (c = 0; c < NUM_CHANNELS; c++) { rgba[c][j] = lerp(levelBlend, rgba[c][j], rgba2[c][j]); } } } } break; default: assert(0); } }