void PtexSeparableFilter::applyToCornerFace(PtexSeparableKernel& k, const Ptex::FaceInfo& f, int eid,
					    int cfid, const Ptex::FaceInfo& cf, int ceid)
{
    // adjust uv coord and res for face/subface boundary
    bool fIsSubface = f.isSubface(), cfIsSubface = cf.isSubface();
    if (fIsSubface != cfIsSubface) {
	if (cfIsSubface) k.adjustMainToSubface(eid + 3);
	else k.adjustSubfaceToMain(eid + 3);
    }
    
    // rotate and apply (resplit if going to a subface)
    k.rotate(eid - ceid + 2);
    if (cfIsSubface) splitAndApply(k, cfid, cf);
    else apply(k, cfid, cf);
}
void PtexSeparableFilter::applyAcrossEdge(PtexSeparableKernel& k, 
					  int faceid, const Ptex::FaceInfo& f, int eid)
{
    int afid = f.adjface(eid), aeid = f.adjedge(eid);
    const Ptex::FaceInfo* af = &_tx->getFaceInfo(afid);
    int rot = eid - aeid + 2;

    // adjust uv coord and res for face/subface boundary
    bool fIsSubface = f.isSubface(), afIsSubface = af->isSubface();
    if (fIsSubface != afIsSubface) {
	if (afIsSubface) {
	    // main face to subface transition
	    // adjust res and offset uv coord for primary subface
	    bool primary = k.adjustMainToSubface(eid);
	    if (!primary) {
		// advance ajacent face and edge id to secondary subface
		int neid = (aeid + 3) % 4;
		afid = af->adjface(neid);
		aeid = af->adjedge(neid);
		af = &_tx->getFaceInfo(afid);
		rot += neid - aeid + 2;
	    }
	}
	else {
	    // subface to main face transition
	    // Note: the transform depends on which subface the kernel is
	    // coming from.  The "primary" subface is the one the main
	    // face is pointing at.  The secondary subface adjustment
	    // happens to be the same as for the primary subface for the
	    // next edge, so the cases can be combined.
	    bool primary = (af->adjface(aeid) == faceid);
	    k.adjustSubfaceToMain(eid - primary);
	}
    }

    // rotate and apply (resplit if going to a subface)
    k.rotate(rot);
    if (afIsSubface) splitAndApply(k, afid, *af);
    else apply(k, afid, *af);
}
void PtexSeparableFilter::apply(PtexSeparableKernel& k, int faceid, const Ptex::FaceInfo& f)
{
    assert(k.u >= 0 && k.u + k.uw <= k.res.u());
    assert(k.v >= 0 && k.v + k.vw <= k.res.v());

    if (k.uw <= 0 || k.vw <= 0) return;

    // downres kernel if needed
    while (k.res.u() > f.res.u()) k.downresU();
    while (k.res.v() > f.res.v()) k.downresV();

    // get face data, and apply
    PtexPtr<PtexFaceData> dh ( _tx->getData(faceid, k.res) );
    if (!dh) return;

    if (dh->isConstant()) {
	k.applyConst(_result, (char*)dh->getData()+_firstChanOffset, _dt, _nchan);
    }
    else if (dh->isTiled()) {
	Ptex::Res tileres = dh->tileRes();
	PtexSeparableKernel kt;
	kt.res = tileres;
	int tileresu = tileres.u();
	int tileresv = tileres.v();
	int ntilesu = k.res.u() / tileresu;
	for (int v = k.v, vw = k.vw; vw > 0; vw -= kt.vw, v += kt.vw) {
	    int tilev = v / tileresv;
	    kt.v = v % tileresv;
	    kt.vw = PtexUtils::min(vw, tileresv - kt.v);
	    kt.kv = k.kv + v - k.v;
	    for (int u = k.u, uw = k.uw; uw > 0; uw -= kt.uw, u += kt.uw) {
		int tileu = u / tileresu;
		kt.u = u % tileresu;
		kt.uw = PtexUtils::min(uw, tileresu - kt.u);
		kt.ku = k.ku + u - k.u;
		PtexPtr<PtexFaceData> th ( dh->getTile(tilev * ntilesu + tileu) );
		if (th) {
		    if (th->isConstant())
			kt.applyConst(_result, (char*)th->getData()+_firstChanOffset, _dt, _nchan);
		    else
			kt.apply(_result, (char*)th->getData()+_firstChanOffset, _dt, _nchan, _ntxchan);
		}
	    }
	}
    }
    else {
	k.apply(_result, (char*)dh->getData()+_firstChanOffset, _dt, _nchan, _ntxchan);
    }
}
void PtexSeparableFilter::eval(float* result, int firstChan, int nChannels,
			       int faceid, float u, float v, 
			       float uw1, float vw1, float uw2, float vw2,
			       float width, float blur)
{
    // init
    if (!_tx || nChannels <= 0) return;
    if (faceid < 0 || faceid >= _tx->numFaces()) return;
    _ntxchan = _tx->numChannels();
    _dt = _tx->dataType();
    _firstChanOffset = firstChan*DataSize(_dt);
    _nchan = PtexUtils::min(nChannels, _ntxchan-firstChan);

    // get face info
    const FaceInfo& f = _tx->getFaceInfo(faceid);

    // if neighborhood is constant, just return constant value of face
    if (f.isNeighborhoodConstant()) {
	PtexPtr<PtexFaceData> data ( _tx->getData(faceid, 0) );
	if (data) {
	    char* d = (char*) data->getData() + _firstChanOffset;
	    Ptex::ConvertToFloat(result, d, _dt, _nchan);
	}
	return;
    }

    // find filter width as bounding box of vectors w1 and w2
    float uw = fabs(uw1) + fabs(uw2), vw = fabs(vw1) + fabs(vw2);

    // handle border modes
    switch (_uMode) {
    case m_clamp: u = PtexUtils::clamp(u, 0.0f, 1.0f); break;
    case m_periodic: u = u-floor(u); break;
    case m_black: break; // do nothing
    }

    switch (_vMode) {
    case m_clamp: v = PtexUtils::clamp(v, 0.0f, 1.0f); break;
    case m_periodic: v = v-floor(v);
    case m_black: break; // do nothing
    }

    // build kernel
    PtexSeparableKernel k;
    if (f.isSubface()) {
	// for a subface, build the kernel as if it were on a main face and then downres
	uw = uw * width + blur * 2;
	vw = vw * width + blur * 2;
	buildKernel(k, u*.5, v*.5, uw*.5, vw*.5, f.res);
	if (k.res.ulog2 == 0) k.upresU();
	if (k.res.vlog2 == 0) k.upresV();
	k.res.ulog2--; k.res.vlog2--;
    }
    else {
	uw = uw * width + blur;
	vw = vw * width + blur;
	buildKernel(k, u, v, uw, vw, f.res);
    }
    k.stripZeros();

    // check kernel (debug only)
    assert(k.uw > 0 && k.vw > 0);
    assert(k.uw <= PtexSeparableKernel::kmax && k.vw <= PtexSeparableKernel::kmax);
    _weight = k.weight();

    // allocate temporary double-precision result
    _result = (double*) alloca(sizeof(double)*_nchan);
    memset(_result, 0, sizeof(double)*_nchan);

    // apply to faces
    splitAndApply(k, faceid, f);

    // normalize (both for data type and cumulative kernel weight applied)
    // and output result
    double scale = 1.0 / (_weight * OneValue(_dt));
    for (int i = 0; i < _nchan; i++) result[i] = float(_result[i] * scale);

    // clear temp result
    _result = 0;
}
void PtexSeparableFilter::applyToCorner(PtexSeparableKernel& k, int faceid, 
					const Ptex::FaceInfo& f, int eid)
{
    // traverse clockwise around corner vertex and gather corner faces
    int afid = faceid, aeid = eid;
    const FaceInfo* af = &f;
    bool prevIsSubface = af->isSubface();

    const int MaxValence = 10;
    int cfaceId[MaxValence];
    int cedgeId[MaxValence];
    const FaceInfo* cface[MaxValence];

    int numCorners = 0;
    for (int i = 0; i < MaxValence; i++) {
	// advance to next face
	int prevFace = afid;
	afid = af->adjface(aeid);
	aeid = (af->adjedge(aeid) + 1) % 4;

	// we hit a boundary or reached starting face
	// note: we need to check edge id too because we might have
	// a periodic texture (w/ toroidal topology) where all 4 corners
	// are from the same face
	if (afid < 0 || (afid == faceid && aeid == eid)) {
	    numCorners = i - 2;
	    break;
	}

	// record face info
	af = &_tx->getFaceInfo(afid);
	cfaceId[i] = afid;
	cedgeId[i] = aeid;
	cface[i] = af;

	// check to see if corner is a subface "tee"
	bool isSubface = af->isSubface();
	if (prevIsSubface && !isSubface && af->adjface((aeid+3)%4) == prevFace) 
	{
	    // adjust the eid depending on whether we started from
	    // the primary or secondary subface.
	    bool primary = (i==1);
	    k.adjustSubfaceToMain(eid + primary * 2);
	    k.rotate(eid - aeid + 3 - primary);
	    splitAndApply(k, afid, *af);
	    return;
	}
	prevIsSubface = isSubface;
    }

    if (numCorners == 1) {
	// regular case (valence 4)
	applyToCornerFace(k, f, eid, cfaceId[1], *cface[1], cedgeId[1]);
    }
    else if (numCorners > 1) {
	// valence 5+, make kernel symmetric and apply equally to each face
	// first, rotate to standard orientation, u=v=0
	k.rotate(eid + 2);
        double initialWeight = k.weight();
        double newWeight = k.makeSymmetric(initialWeight);
	for (int i = 1; i <= numCorners; i++) {
	    PtexSeparableKernel kc = k;
	    applyToCornerFace(kc, f, 2, cfaceId[i], *cface[i], cedgeId[i]);
	}
        // adjust weight for symmetrification and for additional corners
        _weight += newWeight * numCorners - initialWeight;
    }
    else {
	// valence 2 or 3, ignore corner face (just adjust weight)
	_weight -= k.weight();
    }
}
void PtexSeparableFilter::splitAndApply(PtexSeparableKernel& k, int faceid, const Ptex::FaceInfo& f)
{
    // do we need to split? (i.e. does kernel span an edge?)
    bool splitR = (k.u+k.uw > k.res.u()), splitL = (k.u < 0);
    bool splitT = (k.v+k.vw > k.res.v()), splitB = (k.v < 0);

#ifdef NOEDGEBLEND
    // for debugging only
    if (splitR) k.mergeR(_uMode);
    if (splitL) k.mergeL(_uMode);
    if (splitT) k.mergeT(_vMode);
    if (splitB) k.mergeB(_vMode);
#else
    if (splitR || splitL || splitT || splitB) { 
	PtexSeparableKernel ka, kc;
	if (splitR) {
	    if (f.adjface(e_right) >= 0) {
		k.splitR(ka);
		if (splitT) {
		    if (f.adjface(e_top) >= 0) {
			ka.splitT(kc);
			applyToCorner(kc, faceid, f, e_top);
		    }
		    else ka.mergeT(_vMode);
		}
		if (splitB) {
		    if (f.adjface(e_bottom) >= 0) {
			ka.splitB(kc);
			applyToCorner(kc, faceid, f, e_right);
		    }
		    else ka.mergeB(_vMode);
		}
		applyAcrossEdge(ka, faceid, f, e_right);
	    }
	    else k.mergeR(_uMode);
	}
	if (splitL) {
	    if (f.adjface(e_left) >= 0) {
		k.splitL(ka);
		if (splitT) {
		    if (f.adjface(e_top) >= 0) {
			ka.splitT(kc);
			applyToCorner(kc, faceid, f, e_left);
		    }
		    else ka.mergeT(_vMode);
		}
		if (splitB) {
		    if (f.adjface(e_bottom) >= 0) {
			ka.splitB(kc);
			applyToCorner(kc, faceid, f, e_bottom);
		    }
		    else ka.mergeB(_vMode);
		}
		applyAcrossEdge(ka, faceid, f, e_left);
	    }
	    else k.mergeL(_uMode);
	}
	if (splitT) {
	    if (f.adjface(e_top) >= 0) {
		k.splitT(ka);
		applyAcrossEdge(ka, faceid, f, e_top);
	    }
	    else k.mergeT(_vMode);
	}
	if (splitB) {
	    if (f.adjface(e_bottom) >= 0) {
		k.splitB(ka);
		applyAcrossEdge(ka, faceid, f, e_bottom);
	    }
	    else k.mergeB(_vMode);
	}
    }
#endif

    // do local face
    apply(k, faceid, f); 
}
Пример #7
0
void PtexSeparableFilter::apply(PtexSeparableKernel& k, int faceid, const Ptex::FaceInfo& f)
{
    assert(k.u >= 0 && k.u + k.uw <= k.res.u());
    assert(k.v >= 0 && k.v + k.vw <= k.res.v());

    if (k.uw <= 0 || k.vw <= 0) return;

    // downres kernel if needed
    while (k.res.u() > f.res.u()) k.downresU();
    while (k.res.v() > f.res.v()) k.downresV();

    // get face data, and apply
    PtexPtr<PtexFaceData> dh ( _tx->getData(faceid, k.res) );
    if (!dh) return;

    if (dh->isConstant()) {
        k.applyConst(_result, (char*)dh->getData()+_firstChanOffset, _dt, _nchan);
        return;
    }

    // allocate temporary result for tanvec mode (if needed)
    bool tanvecMode = (_efm == efm_tanvec) && (_nchan >= 2) && (k.rot > 0);
    float* result = tanvecMode ? (float*) alloca(sizeof(float)*_nchan) : _result;
    if (tanvecMode) memset(result, 0, sizeof(float)*_nchan);

    if (dh->isTiled()) {
        Ptex::Res tileres = dh->tileRes();
        PtexSeparableKernel kt;
        kt.res = tileres;
        int tileresu = tileres.u();
        int tileresv = tileres.v();
        int ntilesu = k.res.u() / tileresu;
        for (int v = k.v, vw = k.vw; vw > 0; vw -= kt.vw, v += kt.vw) {
            int tilev = v / tileresv;
            kt.v = v % tileresv;
            kt.vw = PtexUtils::min(vw, tileresv - kt.v);
            kt.kv = k.kv + v - k.v;
            for (int u = k.u, uw = k.uw; uw > 0; uw -= kt.uw, u += kt.uw) {
                int tileu = u / tileresu;
                kt.u = u % tileresu;
                kt.uw = PtexUtils::min(uw, tileresu - kt.u);
                kt.ku = k.ku + u - k.u;
                PtexPtr<PtexFaceData> th ( dh->getTile(tilev * ntilesu + tileu) );
                if (th) {
                    if (th->isConstant())
                        kt.applyConst(result, (char*)th->getData()+_firstChanOffset, _dt, _nchan);
                    else
                        kt.apply(result, (char*)th->getData()+_firstChanOffset, _dt, _nchan, _ntxchan);
                }
            }
        }
    }
    else {
        k.apply(result, (char*)dh->getData()+_firstChanOffset, _dt, _nchan, _ntxchan);
    }

    if (tanvecMode) {
        // rotate tangent-space vector data and update main result
        switch (k.rot) {
            case 0: // rot==0 included for completeness, but tanvecMode should be false in this case
                _result[0] += result[0];
                _result[1] += result[1];
                break;
            case 1:
                _result[0] -= result[1];
                _result[1] += result[0];
                break;
            case 2:
                _result[0] -= result[0];
                _result[1] -= result[1];
                break;
            case 3:
                _result[0] += result[1];
                _result[1] -= result[0];
                break;
        }
        for (int i = 2; i < _nchan; i++) _result[i] += result[i];
    }
}