MipMap::MipMap(const std::vector<uint8_t> &texels, int width, int height, int ncomp, WRAP_MODE wrap_mode) : wrap_mode(wrap_mode), width(width), height(height), ncomp(ncomp) { if (weight_table[0] == -1){ init_weight_table(); } //We only support power of two textures at the moment //Determine if pow2 via http://www.graphics.stanford.edu/~seander/bithacks.html#DetermineIfPowerOf2 if (!(width && !(width & (width - 1))) || !(height && !(height & (height - 1)))){ std::cout << "MipMap Error: Only powers of two are supported at the moment\n"; assert("Non power of two texture"); } int n_levels = 1 + static_cast<int>(log_2(std::max(width, height))); pyramid.reserve(n_levels); pyramid.emplace_back(width, height, texels); for (int i = 1; i < n_levels; ++i){ int w = std::max(1, pyramid[i - 1].width / 2); int h = std::max(1, pyramid[i - 1].height / 2); pyramid.emplace_back(w, h); std::vector<uint8_t> &img = pyramid.back().texels; img.resize(w * h * ncomp); for (int t = 0; t < h; ++t){ for (int s = 0; s < w; ++s){ Colorf cf = 0.25 * (texel(i - 1, 2 * s, 2 * t) + texel(i - 1, 2 * s + 1, 2 * t) + texel(i - 1, 2 * s, 2 * t + 1) + texel(i - 1, 2 * s + 1, 2 * t + 1)); cf.normalize(); Color24 c{cf}; //Write the number of components that we have only for (int j = 0; j < ncomp; ++j){ img[t * w * ncomp + s * ncomp + j] = c[j]; } } } } }
Colorf MipMap::triangle_filter(int lvl, float s, float t) const { lvl = clamp(lvl, 0, static_cast<int>(pyramid.size() - 1)); s = s * pyramid[lvl].width - 0.5f; t = t * pyramid[lvl].height - 0.5f; int si = static_cast<int>(s); int ti = static_cast<int>(t); float ds = s - si; float dt = t - ti; return (1 - ds) * (1 - dt) * texel(lvl, si, ti) + (1 - ds) * dt * texel(lvl, si, ti + 1) + ds * (1 - dt) * texel(lvl, si + 1, ti) + ds * dt * texel(lvl, si + 1, ti + 1); }
Colorf MipMap::sample_ewa(const TextureSample &samp, std::array<float, 2> ds, std::array<float, 2> dt) const { //Compute the ellipse's major and minor axes, we pick the major axis to be (ds[0], dt[0]) so //swap if this wouldn't be the case if (ds[0] * ds[0] + dt[0] * dt[0] < ds[1] * ds[1] + dt[1] * dt[1]){ std::swap(ds[0], ds[1]); std::swap(dt[0], dt[1]); } float major_len = std::sqrt(ds[0] * ds[0] + dt[0] * dt[0]); float minor_len = std::sqrt(ds[1] * ds[1] + dt[1] * dt[1]); //Clamp the ellipse eccentricity if it's too anisotropic by increasing the minor axis static const float max_anisotropy = 8; if (minor_len > 0 && minor_len * max_anisotropy < major_len){ float s = major_len / (minor_len * max_anisotropy); ds[1] *= s; dt[1] *= s; minor_len *= s; } if (minor_len == 0){ return triangle_filter(0, samp.s, samp.t); } float level = pyramid.size() - 1 + std::log2(minor_len); if (level >= pyramid.size()){ return texel(pyramid.size() - 1, 0, 0); } int lvl = static_cast<int>(level); float d = level - lvl; return (1 - d) * ewa_filter(lvl, samp.s, samp.t, ds, dt) + d * ewa_filter(lvl + 1, samp.s, samp.t, ds, dt); }
Colorf MipMap::sample_trilinear(const TextureSample &samp, float w) const { float level = pyramid.size() - 1 + std::log2(std::max(w, 1e-8f)); if (level < 0){ return triangle_filter(0, samp.s, samp.t); } if (level >= pyramid.size() - 1){ return texel(pyramid.size() - 1, 0, 0); } //Find integer coord of the level and the percentage we're in each int lvl = static_cast<int>(level); float d = level - lvl; return (1 - d) * triangle_filter(lvl, samp.s, samp.t) + d * triangle_filter(lvl + 1, samp.s, samp.t); }
Colorf MipMap::ewa_filter(int lvl, float s, float t, std::array<float, 2> ds, std::array<float, 2> dt) const { lvl = clamp(lvl, 0, static_cast<int>(pyramid.size() - 1)); s = s * pyramid[lvl].width - 0.5f; t = t * pyramid[lvl].height - 0.5f; for (size_t i = 0; i < ds.size(); ++i){ ds[i] *= pyramid[lvl].width; dt[i] *= pyramid[lvl].height; } float a = dt[0] * dt[0] + dt[1] * dt[1] + 1; float b = -2 * (ds[0] * dt[0] + ds[1] * dt[1]); float c = ds[0] * ds[0] + ds[1] * ds[1] + 1; float inv_f = 1 / (a * c - b * b * 0.25f); a *= inv_f; b *= inv_f; c *= inv_f; //Compute the ellipse's AABB so we can find which texels to loop over and filter float det = -b * b + 4 * a * c; float inv_det = 1 / det; float u_sqrt = std::sqrt(det * c); float v_sqrt = std::sqrt(det * a); std::array<int, 2> s_bound{ static_cast<int>(s - 2 * inv_det * u_sqrt), static_cast<int>(s + 2 * inv_det * u_sqrt) }; std::array<int, 2> t_bound{ static_cast<int>(t - 2 * inv_det * v_sqrt), static_cast<int>(t + 2 * inv_det * v_sqrt) }; Colorf color; float weight_sum = 0; for (int it = t_bound[0]; it <= t_bound[1]; ++it){ float t_pos = it - t; for (int is = s_bound[0]; is <= s_bound[1]; ++is){ float s_pos = is - s; //Find the position of this texel relative to the ellipse and see if it's inside float r_sqr = a * s_pos * s_pos + b * s_pos * t_pos + c * t_pos * t_pos; if (r_sqr < 1){ float w = weight_table[std::min(static_cast<int>(r_sqr * WEIGHT_LUT_SIZE), WEIGHT_LUT_SIZE - 1)]; color += texel(lvl, is, it) * w; weight_sum += w; } } } return color / weight_sum; }
void DistanceFieldShiftedStyleTextMaterialShader::updateShift(qreal fontScale, const QPointF &shift) { QPointF texel(1.0 / fontScale * shift.x(), 1.0 / fontScale * shift.y()); program()->setUniformValue(m_shift_id, texel); }
static void renderscanline_uvi_full( mame_bitmap *bitmap, const rectangle *clip, const edge *e1, const edge *e2, int sy ) { if( e1->x > e2->x ) { SWAP(e1,e2); } { UINT32 *pDest = (UINT32 *)bitmap->line[sy]; INT32 *pZBuf = namco_zbuffer + bitmap->width*sy; int x0 = (int)e1->x; int x1 = (int)e2->x; int w = x1-x0; if( w ) { float u = e1->u; /* u/z */ float v = e1->v; /* v/z */ float i = e1->i; /* i/z */ float z = e1->z; /* 1/z */ float oow = 1.0f / w; float du = (e2->u - e1->u)*oow; float dv = (e2->v - e1->v)*oow; float dz = (e2->z - e1->z)*oow; float di = (e2->i - e1->i)*oow; int x, crop; int baseColor = mColor&0x7f00; pen_t *pens = &Machine->pens[baseColor]; crop = clip->min_x - x0; if( crop>0 ) { u += crop*du; v += crop*dv; i += crop*di; z += crop*dz; x0 = clip->min_x; } if( x1>clip->max_x ) { x1 = clip->max_x; } for( x=x0; x<x1; x++ ) { if( mZSort<pZBuf[x] ) { float ooz = 1.0f/z; UINT32 color = pens[texel(u * ooz,v * ooz)]; int shade = i * ooz; int r = color>>16; int g = (color>>8)&0xff; int b = color&0xff; r+=shade; if( r<0 ) r = 0; else if( r>0xff ) r = 0xff; g+=shade; if( g<0 ) g = 0; else if( g>0xff ) g = 0xff; b+=shade; if( b<0 ) b = 0; else if( b>0xff ) b = 0xff; pDest[x] = (r<<16)|(g<<8)|b; pZBuf[x] = mZSort; } u += du; v += dv; i += di; z += dz; } } }
Color3f Li(const Scene *scene, Sampler *sampler, const Ray3f &r) const { /* Find the surface that is visible in the requested direction */ Intersection its; Ray3f ray(r); if (!scene->rayIntersect(ray, its)) return Color3f(0.0f); Color3f radiance(0.0f); bool specularBounce = false; Color3f pathThroughput(1.0f); for ( int bounces = 0; ; ++bounces ) { const Luminaire* luminaire = its.mesh->getLuminaire(); if ((bounces == 0 || specularBounce) && luminaire != NULL) { Vector3f wo = (-ray.d).normalized(); Color3f emission = luminaire->le(its.p, its.shFrame.n, wo); radiance += pathThroughput*emission; } const Texture* texture = its.mesh->getTexture(); Color3f texel(1.0f); if ( texture ) { texel = texture->lookUp(its.uv.x(), its.uv.y()); } const BSDF* bsdf = its.mesh->getBSDF(); // sample illumination from lights, add to path contribution if (!bsdf->isSpecular()){ radiance += pathThroughput*UniformSampleAllLights(scene, ray, its, sampler, m_samplePolicy)*texel; } // sample bsdf to get new path direction BSDFQueryRecord bRec(its.toLocal((-ray.d)).normalized()); Color3f f = bsdf->sample(bRec, sampler->next2D() ); if (f.isZero() ) { // farther path no contribution break; } specularBounce = bsdf->isSpecular(); Vector3f d = its.toWorld(bRec.wo); f *= texel; pathThroughput *= f; ray = Ray3f(its.p, d ); // possibly termination if (bounces > kSampleDepth) { #if 0 float continueProbability = std::min( 0.5f, pathThroughput.y() ); if ( sampler->next1D() > continueProbability ) { break; } #else float continueProbability = std::max(f.x(), std::max(f.y(), f.z())); if ( sampler->next1D() > continueProbability ) { break; } #endif pathThroughput /= continueProbability; } if (bounces == m_maxDepth) { break; } // find next vertex of path if ( !scene->rayIntersect(ray, its) ) { break; } } return radiance; }