Beispiel #1
0
bool
TextureSystemImpl::accum3d_sample_bilinear (const Imath::V3f &P, int miplevel,
                                 TextureFile &texturefile,
                                 PerThreadInfo *thread_info,
                                 TextureOpt &options,
                                 float weight, float *accum, float *daccumds,
                                 float *daccumdt, float *daccumdr)
{
    const ImageSpec &spec (texturefile.spec (options.subimage, miplevel));
    const ImageCacheFile::LevelInfo &levelinfo (texturefile.levelinfo(options.subimage,miplevel));
    // As passed in, (s,t) map the texture to (0,1).  Remap to texel coords
    // and subtract 0.5 because samples are at texel centers.
    float s = P[0] * spec.full_width  + spec.full_x - 0.5f;
    float t = P[1] * spec.full_height + spec.full_y - 0.5f;
    float r = P[2] * spec.full_depth  + spec.full_z - 0.5f;
    int sint, tint, rint;
    float sfrac = floorfrac (s, &sint);
    float tfrac = floorfrac (t, &tint);
    float rfrac = floorfrac (r, &rint);
    // Now (sint,tint,rint) are the integer coordinates of the texel to the
    // immediate "upper left" of the lookup point, and (sfrac,tfrac,rfrac) are
    // the amount that the lookup point is actually offset from the
    // texel center (with (1,1) being all the way to the next texel down
    // and to the right).

    // Wrap
    DASSERT (options.swrap_func != NULL && options.twrap_func != NULL &&
             options.rwrap_func != NULL);
    int stex[2], ttex[2], rtex[2];       // Texel coords
    stex[0] = sint;  stex[1] = sint+1;
    ttex[0] = tint;  ttex[1] = tint+1;
    rtex[0] = rint;  rtex[1] = rint+1;
//    bool svalid[2], tvalid[2], rvalid[2];  // Valid texels?  false means black border
    union { bool bvalid[6]; unsigned long long ivalid; } valid_storage;
    valid_storage.ivalid = 0;
    DASSERT (sizeof(valid_storage) >= 6*sizeof(bool));
    const unsigned long long none_valid = 0;
    const unsigned long long all_valid = 0x010101010101LL;
    DASSERT (__LITTLE_ENDIAN__ && "this trick won't work with big endian");
    bool *svalid = valid_storage.bvalid;
    bool *tvalid = valid_storage.bvalid + 2;
    bool *rvalid = valid_storage.bvalid + 4;

    svalid[0] = options.swrap_func (stex[0], spec.x, spec.width);
    svalid[1] = options.swrap_func (stex[1], spec.x, spec.width);
    tvalid[0] = options.twrap_func (ttex[0], spec.y, spec.height);
    tvalid[1] = options.twrap_func (ttex[1], spec.y, spec.height);
    rvalid[0] = options.rwrap_func (rtex[0], spec.z, spec.depth);
    rvalid[1] = options.rwrap_func (rtex[1], spec.z, spec.depth);
    // Account for crop windows
    if (! levelinfo.full_pixel_range) {
        svalid[0] &= (stex[0] >= spec.x && stex[0] < spec.x+spec.width);
        svalid[1] &= (stex[1] >= spec.x && stex[1] < spec.x+spec.width);
        tvalid[0] &= (ttex[0] >= spec.y && ttex[0] < spec.y+spec.height);
        tvalid[1] &= (ttex[1] >= spec.y && ttex[1] < spec.y+spec.height);
        rvalid[0] &= (rtex[0] >= spec.z && rtex[0] < spec.z+spec.depth);
        rvalid[1] &= (rtex[1] >= spec.z && rtex[1] < spec.z+spec.depth);
    }
//    if (! (svalid[0] | svalid[1] | tvalid[0] | tvalid[1] | rvalid[0] | rvalid[1]))
    if (valid_storage.ivalid == none_valid)
        return true; // All texels we need were out of range and using 'black' wrap

    int tilewidthmask  = spec.tile_width  - 1;  // e.g. 63
    int tileheightmask = spec.tile_height - 1;
    int tiledepthmask = spec.tile_depth - 1;
    const unsigned char *texel[2][2][2];
    TileRef savetile[2][2][2];
    static float black[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
    int tile_s = (stex[0] - spec.x) % spec.tile_width;
    int tile_t = (ttex[0] - spec.y) % spec.tile_height;
    int tile_r = (rtex[0] - spec.z) % spec.tile_depth;
    bool s_onetile = (tile_s != tilewidthmask) & (stex[0]+1 == stex[1]);
    bool t_onetile = (tile_t != tileheightmask) & (ttex[0]+1 == ttex[1]);
    bool r_onetile = (tile_r != tiledepthmask) & (rtex[0]+1 == rtex[1]);
    bool onetile = (s_onetile & t_onetile & r_onetile);
    size_t channelsize = texturefile.channelsize();
    size_t pixelsize = texturefile.pixelsize();
    if (onetile &&
        valid_storage.ivalid == all_valid) {
        // Shortcut if all the texels we need are on the same tile
        TileID id (texturefile, options.subimage, miplevel,
                   stex[0] - tile_s, ttex[0] - tile_t, rtex[0] - tile_r);
        bool ok = find_tile (id, thread_info);
        if (! ok)
            error ("%s", m_imagecache->geterror().c_str());
        TileRef &tile (thread_info->tile);
        if (! tile->valid())
            return false;
        size_t tilepel = (tile_r * spec.tile_height + tile_t) * spec.tile_width + tile_s;
        size_t offset = (spec.nchannels * tilepel + options.firstchannel) * channelsize;
        DASSERT ((size_t)offset < spec.tile_width*spec.tile_height*spec.tile_depth*pixelsize);

        const unsigned char *b = tile->bytedata() + offset;
        texel[0][0][0] = b;
        texel[0][0][1] = b + pixelsize;
        texel[0][1][0] = b + pixelsize * spec.tile_width;
        texel[0][1][1] = b + pixelsize * spec.tile_width + pixelsize;
        b += pixelsize * spec.tile_width * spec.tile_height;
        texel[1][0][0] = b;
        texel[1][0][1] = b + pixelsize;
        texel[1][1][0] = b + pixelsize * spec.tile_width;
        texel[1][1][1] = b + pixelsize * spec.tile_width + pixelsize;
    } else {
        for (int k = 0;  k < 2;  ++k) {
            for (int j = 0;  j < 2;  ++j) {
                for (int i = 0;  i < 2;  ++i) {
                    if (! (svalid[i] && tvalid[j] && rvalid[k])) {
                        texel[k][j][i] = (unsigned char *)black;
                        continue;
                    }
                    tile_s = (stex[i] - spec.x) % spec.tile_width;
                    tile_t = (ttex[j] - spec.y) % spec.tile_height;
                    tile_r = (rtex[k] - spec.z) % spec.tile_depth;
                    TileID id (texturefile, options.subimage, miplevel,
                               stex[i] - tile_s, ttex[j] - tile_t,
                               rtex[k] - tile_r);
                    bool ok = find_tile (id, thread_info);
                    if (! ok)
                        error ("%s", m_imagecache->geterror().c_str());
                    TileRef &tile (thread_info->tile);
                    if (! tile->valid())
                        return false;
                    savetile[k][j][i] = tile;
                    size_t tilepel = (tile_r * spec.tile_height + tile_t) * spec.tile_width + tile_s;
                    size_t offset = (spec.nchannels * tilepel + options.firstchannel) * channelsize;
#if DEBUG
                    if ((size_t)offset >= spec.tile_width*spec.tile_height*spec.tile_depth*pixelsize)
                        std::cerr << "offset=" << offset << ", whd " << spec.tile_width << ' ' << spec.tile_height << ' ' << spec.tile_depth << " pixsize " << pixelsize << "\n";
#endif
                    DASSERT ((size_t)offset < spec.tile_width*spec.tile_height*spec.tile_depth*pixelsize);
                    texel[k][j][i] = tile->bytedata() + offset;
                    DASSERT (tile->id() == id);
                }
            }
        }
    }
    // FIXME -- optimize the above loop by unrolling

    if (channelsize == 1) {
        // special case for 8-bit tiles
        int c;
        for (c = 0;  c < options.actualchannels;  ++c)
            accum[c] += weight * trilerp (uchar2float(texel[0][0][0][c]), uchar2float(texel[0][0][1][c]),
                                          uchar2float(texel[0][1][0][c]), uchar2float(texel[0][1][1][c]),
                                          uchar2float(texel[1][0][0][c]), uchar2float(texel[1][0][1][c]),
                                          uchar2float(texel[1][1][0][c]), uchar2float(texel[1][1][1][c]),
                                          sfrac, tfrac, rfrac);
        if (daccumds) {
            float scalex = weight * spec.full_width;
            float scaley = weight * spec.full_height;
            float scalez = weight * spec.full_depth;
            for (c = 0;  c < options.actualchannels;  ++c) {
                daccumds[c] += scalex * bilerp(
                    uchar2float(texel[0][0][1][c]) - uchar2float(texel[0][0][0][c]),
                    uchar2float(texel[0][1][1][c]) - uchar2float(texel[0][1][0][c]),

                    uchar2float(texel[1][0][1][c]) - uchar2float(texel[1][0][0][c]),
                    uchar2float(texel[1][1][1][c]) - uchar2float(texel[1][1][0][c]),
                    tfrac, rfrac
                );
                daccumdt[c] += scaley * bilerp(
                    uchar2float(texel[0][1][0][c]) - uchar2float(texel[0][0][0][c]),
                    uchar2float(texel[0][1][1][c]) - uchar2float(texel[0][0][1][c]),
                    uchar2float(texel[1][1][0][c]) - uchar2float(texel[1][0][0][c]),
                    uchar2float(texel[1][1][1][c]) - uchar2float(texel[1][0][1][c]),
                    sfrac, rfrac
                );
                daccumdr[c] += scalez * bilerp(
                    uchar2float(texel[0][1][0][c]) - uchar2float(texel[1][1][0][c]),
                    uchar2float(texel[0][1][1][c]) - uchar2float(texel[1][1][1][c]),
                    uchar2float(texel[0][0][1][c]) - uchar2float(texel[1][0][0][c]),
                    uchar2float(texel[0][1][1][c]) - uchar2float(texel[1][1][1][c]),
                    sfrac, tfrac
                );
            }
        }
    } else {
        // General case for float tiles
        trilerp_mad ((const float *)texel[0][0][0], (const float *)texel[0][0][1],
                     (const float *)texel[0][1][0], (const float *)texel[0][1][1],
                     (const float *)texel[1][0][0], (const float *)texel[1][0][1],
                     (const float *)texel[1][1][0], (const float *)texel[1][1][1],
                     sfrac, tfrac, rfrac, weight, options.actualchannels, accum);
        if (daccumds) {
            float scalex = weight * spec.full_width;
            float scaley = weight * spec.full_height;
            float scalez = weight * spec.full_depth;
            for (int c = 0;  c < options.actualchannels;  ++c) {
                daccumds[c] += scalex * bilerp(
                    ((const float *) texel[0][0][1])[c] - ((const float *) texel[0][0][0])[c],
                    ((const float *) texel[0][1][1])[c] - ((const float *) texel[0][1][0])[c],
                    ((const float *) texel[1][0][1])[c] - ((const float *) texel[1][0][0])[c],
                    ((const float *) texel[1][1][1])[c] - ((const float *) texel[1][1][0])[c],
                    tfrac, rfrac
                );
                daccumdt[c] += scaley * bilerp(
                    ((const float *) texel[0][1][0])[c] - ((const float *) texel[0][0][0])[c],
                    ((const float *) texel[0][1][1])[c] - ((const float *) texel[0][0][1])[c],
                    ((const float *) texel[1][1][0])[c] - ((const float *) texel[1][0][0])[c],
                    ((const float *) texel[1][1][1])[c] - ((const float *) texel[1][0][1])[c],
                    sfrac, rfrac
                );
                daccumdr[c] += scalez * bilerp(
                    ((const float *) texel[0][1][0])[c] - ((const float *) texel[1][1][0])[c],
                    ((const float *) texel[0][1][1])[c] - ((const float *) texel[1][1][1])[c],
                    ((const float *) texel[0][0][1])[c] - ((const float *) texel[1][0][0])[c],
                    ((const float *) texel[0][1][1])[c] - ((const float *) texel[1][1][1])[c],
                    sfrac, tfrac
                );
            }
        }
    }

    return true;
}
Beispiel #2
0
bool
TextureSystemImpl::accum3d_sample_closest (const Imath::V3f &P, int miplevel,
                                 TextureFile &texturefile,
                                 PerThreadInfo *thread_info,
                                 TextureOpt &options,
                                 float weight, float *accum, float *daccumds,
                                 float *daccumdt, float *daccumdr)
{
    const ImageSpec &spec (texturefile.spec (options.subimage, miplevel));
    const ImageCacheFile::LevelInfo &levelinfo (texturefile.levelinfo(options.subimage,miplevel));
    // As passed in, (s,t) map the texture to (0,1).  Remap to texel coords.
    float s = P[0] * spec.full_width  + spec.full_x;
    float t = P[1] * spec.full_height + spec.full_y;
    float r = P[2] * spec.full_depth + spec.full_z;
    int stex, ttex, rtex;    // Texel coordintes
    (void) floorfrac (s, &stex);   // don't need fractional result
    (void) floorfrac (t, &ttex);
    (void) floorfrac (r, &rtex);

    // Wrap
    DASSERT (options.swrap_func != NULL && options.twrap_func != NULL &&
             options.rwrap_func != NULL);
    bool svalid, tvalid, rvalid;  // Valid texels?  false means black border
    svalid = options.swrap_func (stex, spec.x, spec.width);
    tvalid = options.twrap_func (ttex, spec.y, spec.height);
    rvalid = options.rwrap_func (rtex, spec.z, spec.depth);
    if (! levelinfo.full_pixel_range) {
        svalid &= (stex >= spec.x && stex < (spec.x+spec.width)); // data window
        tvalid &= (ttex >= spec.y && ttex < (spec.y+spec.height));
        rvalid &= (rtex >= spec.z && rtex < (spec.z+spec.depth));
    }
    if (! (svalid & tvalid & rvalid)) {
        // All texels we need were out of range and using 'black' wrap.
        return true;
    }

    int tile_s = (stex - spec.x) % spec.tile_width;
    int tile_t = (ttex - spec.y) % spec.tile_height;
    int tile_r = (rtex - spec.z) % spec.tile_depth;
    TileID id (texturefile, options.subimage, miplevel,
               stex - tile_s, ttex - tile_t, rtex - tile_r);
    bool ok = find_tile (id, thread_info);
    if (! ok)
        error ("%s", m_imagecache->geterror().c_str());
    TileRef &tile (thread_info->tile);
    if (! tile  ||  ! ok)
        return false;
    size_t channelsize = texturefile.channelsize();
    int tilepel = (tile_r * spec.tile_height + tile_t) * spec.tile_width + tile_s;
    int offset = spec.nchannels * tilepel + options.firstchannel;
    DASSERT ((size_t)offset < spec.nchannels*spec.tile_pixels());
    if (channelsize == 1) {
        // special case for 8-bit tiles
        const unsigned char *texel = tile->bytedata() + offset;
        for (int c = 0;  c < options.actualchannels;  ++c)
            accum[c] += weight * uchar2float(texel[c]);
    } else {
        // General case for float tiles
        const float *texel = tile->data() + offset;
        for (int c = 0;  c < options.actualchannels;  ++c)
            accum[c] += weight * texel[c];
    }
    return true;
}