void DumpData(Ptex::DataType dt, int nchan, PtexFaceData* dh, std::string prefix) { void* dpixel = malloc(Ptex::DataSize(dt)*nchan); float* pixel = (float*) malloc(sizeof(float)*nchan); uint8_t* cpixel = (uint8_t*) malloc(sizeof(uint8_t)*nchan); Ptex::Res res = dh->res(); printf("%sdata (%d x %d)", prefix.c_str(), res.u(), res.v()); if (dh->isTiled()) { Ptex::Res tileres = dh->tileRes(); printf(", tiled (%d x %d):\n", tileres.u(), tileres.v()); int n = res.ntiles(tileres); for (int i = 0; i < n; i++) { PtexFaceData* t = dh->getTile(i); std::cout << prefix << " tile " << i; if (!t) { std::cout << " NULL!" << std::endl; } else { DumpData(dt, nchan, t, prefix + " "); t->release(); } } } else { int ures, vres; if (dh->isConstant()) { ures = vres = 1; std::cout << ", const: "; } else { ures = res.u(); vres = res.v(); std::cout << ":\n"; } int vimax = vres;// if (vimax > 16) vimax = 16; for (int vi = 0; vi < vimax; vi++) { if (vi == 8 && vres > 16) { vi = vres-8; std::cout << prefix << " ..." << std::endl; } std::cout << prefix << " "; int uimax = ures;// if (uimax > 16) uimax = 16; for (int ui = 0; ui < uimax; ui++) { if (ui == 8 && ures > 16) { ui = ures-8; std::cout << "... "; } dh->getPixel(ui, vi, dpixel); Ptex::ConvertToFloat(pixel, dpixel, dt, nchan); Ptex::ConvertFromFloat(cpixel, pixel, Ptex::dt_uint8, nchan); for (int c=0; c < nchan; c++) { printf("%02x", cpixel[c]); } printf(" "); } if (uimax != ures) printf(" ..."); printf("\n"); } if (vimax != vres) std::cout << prefix << " ..." << std::endl; } free(cpixel); free(pixel); free(dpixel); }
void DumpData(PtexTexture* r, int faceid, bool dumpall) { int levels = 1; if (dumpall) { PtexReader* R = static_cast<PtexReader*> (r); if (R) levels = R->header().nlevels; } const Ptex::FaceInfo& f = r->getFaceInfo(faceid); int nchan = r->numChannels(); float* pixel = (float*) malloc(sizeof(float)*nchan); Ptex::Res res = f.res; while (levels && res.ulog2 >= 1 && res.vlog2 >= 1) { int ures = res.u(), vres = res.v(); std::cout << " data (" << ures << " x " << vres << ")"; if (f.isConstant()) { ures = vres = 1; } bool isconst = (ures == 1 && vres == 1); if (isconst) std::cout << ", const: "; else std::cout << ":"; for (int vi = 0; vi < vres; vi++) { for (int ui = 0; ui < ures; ui++) { if (!isconst) std::cout << "\n (" << ui << ", " << vi << "): "; r->getPixel(faceid, ui, vi, pixel, 0, nchan, res); for (int c=0; c < nchan; c++) { printf(" %.3f", pixel[c]); } } } std::cout << std::endl; res.ulog2--; res.vlog2--; levels--; } free(pixel); }
void DumpFaceInfo(const Ptex::FaceInfo& f) { Ptex::Res res = f.res; std::cout << " res: " << int(res.ulog2) << ' ' << int(res.vlog2) << " (" << res.u() << " x " << res.v() << ")" << " adjface: " << f.adjfaces[0] << ' ' << f.adjfaces[1] << ' ' << f.adjfaces[2] << ' ' << f.adjfaces[3] << " adjedge: " << f.adjedge(0) << ' ' << f.adjedge(1) << ' ' << f.adjedge(2) << ' ' << f.adjedge(3) << " flags:"; // output flag names if (f.flags == 0) std::cout << " (none)"; else { if (f.isSubface()) std::cout << " subface"; if (f.isConstant()) std::cout << " constant"; if (f.isNeighborhoodConstant()) std::cout << " nbconstant"; if (f.hasEdits()) std::cout << " hasedits"; } std::cout << std::endl; }
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 DumpTiling(PtexFaceData* dh) { std::cout << " tiling: "; if (dh->isTiled()) { Ptex::Res res = dh->tileRes(); std::cout << "ntiles = " << dh->res().ntiles(res) << ", res = " << int(res.ulog2) << ' ' << int(res.vlog2) << " (" << res.u() << " x " << res.v() << ")\n"; } else if (dh->isConstant()) { std::cout << " (constant)" << std::endl; } else { std::cout << " (untiled)" << std::endl; } }
void PtexTriangleFilter::applyIter(PtexTriangleKernelIter& k, PtexFaceData* dh) { if (dh->isConstant()) { k.applyConst(_result, (char*)dh->getData()+_firstChanOffset, _dt, _nchan); _weight += k.weight; } else if (dh->isTiled()) { Ptex::Res tileres = dh->tileRes(); PtexTriangleKernelIter kt = k; int tileresu = tileres.u(); int tileresv = tileres.v(); kt.rowlen = tileresu; int ntilesu = k.rowlen / kt.rowlen; int wOffsetBase = k.rowlen - tileresu; for (int tilev = k.v1 / tileresv, tilevEnd = (k.v2-1) / tileresv; tilev <= tilevEnd; tilev++) { int vOffset = tilev * tileresv; kt.v = k.v - (float)vOffset; kt.v1 = PtexUtils::max(0, k.v1 - vOffset); kt.v2 = PtexUtils::min(k.v2 - vOffset, tileresv); for (int tileu = k.u1 / tileresu, tileuEnd = (k.u2-1) / tileresu; tileu <= tileuEnd; tileu++) { int uOffset = tileu * tileresu; int wOffset = wOffsetBase - uOffset - vOffset; kt.u = k.u - (float)uOffset; kt.u1 = PtexUtils::max(0, k.u1 - uOffset); kt.u2 = PtexUtils::min(k.u2 - uOffset, tileresu); kt.w1 = k.w1 - wOffset; kt.w2 = k.w2 - wOffset; PtexPtr<PtexFaceData> th ( dh->getTile(tilev * ntilesu + tileu) ); if (th) { kt.weight = 0; if (th->isConstant()) kt.applyConst(_result, (char*)th->getData()+_firstChanOffset, _dt, _nchan); else kt.apply(_result, (char*)th->getData()+_firstChanOffset, _dt, _nchan, _ntxchan); _weight += kt.weight; } } } } else { k.apply(_result, (char*)dh->getData()+_firstChanOffset, _dt, _nchan, _ntxchan); _weight += k.weight; } }
void IBLWidget::loadIBL( const char* filename ) { printf( "opening %s... ", filename ); // try and load it Ptex::String error; PtexTexture* tx = PtexTexture::open(filename, error); if (!tx) { printf( "failed\n"); return; } CKGL(); Ptex::DataType dataType = tx->dataType(); int numChannels = tx->numChannels(); int numFaces=tx->numFaces(); int faceWidth=0, faceHeight=0; if( dataType != Ptex::dt_float || numChannels != 3 || numFaces != 6 ) { printf( "not the right kind\n" ); return; } for( int i = 0; i < numFaces; i++ ) { int face = i; Ptex::Res res = tx->getFaceInfo(i).res; if( i == 0 ) { faceWidth = res.u(); faceHeight = res.v(); // printf( "size: %dx%d (%dx%d)\n", faceWidth, faceHeight, faceWidth*6, faceHeight ); envTex.create( faceWidth*6, faceHeight ); } if( faceWidth != res.u() || faceHeight != res.v() ) { printf( "error loading ptex file\n" ); return; } float* faceData = (float*)malloc( faceWidth*faceHeight*numChannels*sizeof(float) ); tx->getData( i, faceData, 0 ); // copy the data into the envmap texture for( int j = 0; j < faceHeight * faceWidth; j++ ) { color3 c( faceData[j*3+0], faceData[j*3+1], faceData[j*3+2] ); envTex.setPixel( faceWidth*face + j % faceWidth, j / faceWidth, c ); } free( faceData ); } tx->release(); printf( "success\n"); // allocate texture names (if we haven't before) if( envTexID == 0 ) { glf->glGenTextures( 1, &envTexID ); glf->glGenTextures( 1, &probTexID ); glf->glGenTextures( 1, &marginalProbTexID ); } CKGL(); // now that the envmap tex is loaded, compute the sampling data computeEnvMapSamplingData(); createGLSamplingTextures(); CKGL(); glf->glGenTextures(1, &envTexID); glf->glBindTexture( GL_TEXTURE_CUBE_MAP, envTexID ); glf->glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST); BitmapContainer<color3> flip; flip.create(envTex.w, envTex.h);//get face flipped to match GL thinking! for (int y=0; y < envTex.h; y++){ color3* in = &envTex.data[y*envTex.w]; color3* out = &flip.data[(envTex.h-y-1)*envTex.w]; for (int x=0; x < envTex.w; x++) out[x] = in[x]; } BitmapContainer<color3> tmp; tmp.create(envTex.h, envTex.h); CKGL(); for (int y=0; y < tmp.h; y++) for (int x=0; x < tmp.w; x++) tmp.setPixel(x, y,flip.getPixel(x+tmp.w*0, y)); glf->glTexImage2D( GL_TEXTURE_CUBE_MAP_POSITIVE_X , 0,GL_R11F_G11F_B10F, tmp.w, tmp.h, 0, GL_RGB, GL_FLOAT, tmp.getPtr() ); for (int y=0; y < tmp.h; y++) for (int x=0; x < tmp.w; x++) tmp.setPixel(x, y,flip.getPixel(x+tmp.w*1, y)); glf->glTexImage2D( GL_TEXTURE_CUBE_MAP_NEGATIVE_X , 0,GL_R11F_G11F_B10F, tmp.w, tmp.h, 0, GL_RGB, GL_FLOAT, tmp.getPtr() ); for (int y=0; y < tmp.h; y++) for (int x=0; x < tmp.w; x++) tmp.setPixel(x, y,flip.getPixel(x+tmp.w*2, y)); glf->glTexImage2D( GL_TEXTURE_CUBE_MAP_POSITIVE_Y , 0,GL_R11F_G11F_B10F, tmp.w, tmp.h, 0, GL_RGB, GL_FLOAT, tmp.getPtr() ); for (int y=0; y < tmp.h; y++) for (int x=0; x < tmp.w; x++) tmp.setPixel(x, y,flip.getPixel(x+tmp.w*3, y)); glf->glTexImage2D( GL_TEXTURE_CUBE_MAP_NEGATIVE_Y , 0,GL_R11F_G11F_B10F, tmp.w, tmp.h, 0, GL_RGB, GL_FLOAT, tmp.getPtr() ); for (int y=0; y < tmp.h; y++) for (int x=0; x < tmp.w; x++) tmp.setPixel(x, y,flip.getPixel(x+tmp.w*4, y)); glf->glTexImage2D( GL_TEXTURE_CUBE_MAP_POSITIVE_Z , 0,GL_R11F_G11F_B10F, tmp.w, tmp.h, 0, GL_RGB, GL_FLOAT, tmp.getPtr() ); CKGL(); for (int y=0; y < tmp.h; y++) for (int x=0; x < tmp.w; x++) tmp.setPixel(x, y,flip.getPixel(x+tmp.w*5, y)); glf->glTexImage2D( GL_TEXTURE_CUBE_MAP_NEGATIVE_Z , 0,GL_R11F_G11F_B10F, tmp.w, tmp.h, 0, GL_RGB, GL_FLOAT, tmp.getPtr() ); CKGL(); glf->glGenerateMipmap(GL_TEXTURE_CUBE_MAP); glf->glBindTexture( GL_TEXTURE_CUBE_MAP, 0 ); CKGL(); }
OBJScene::Texture *loadPtexTexture(const FileName& filename) { #if defined(USE_PTEX) std::string fn = filename.str(); Ptex::String error; std::cout << "opening " << fn << " ... " << std::flush; PtexTexture* tex = PtexTexture::open(fn.c_str(),error); if (!tex) { std::cout << "[FAILED]" << std::endl; THROW_RUNTIME_ERROR("cannot open ptex file: "+fn); } PtexMetaData *metadata = tex->getMetaData(); const int32_t *vertices_per_face = nullptr; int geom_faces = 0; metadata->getValue("PtexFaceVertCounts", vertices_per_face, geom_faces); OBJScene::Texture **face_textures = new OBJScene::Texture *[geom_faces]; for (size_t i=0;i<geom_faces;i++) face_textures[i] = nullptr; OBJScene::Texture *texture = new OBJScene::Texture(); texture->width = 0; texture->height = 0; texture->format = OBJScene::Texture::PTEX_RGBA8; texture->faceTextures = geom_faces; texture->data = face_textures; texture->width_mask = 0; texture->height_mask = 0; int nchan = tex->numChannels(); if (nchan != 3 && nchan != 1) { std::cout << "[FAILED]" << std::endl; THROW_RUNTIME_ERROR(fn+": ptex file with other than 1 or 3 channels found!"); } if (nchan == 1) texture->format = OBJScene::Texture::PTEX_FLOAT32; float px[3]; int ptex_face_id = 0; for (size_t geom_face_id=0;geom_face_id<geom_faces;geom_face_id++) { face_textures[geom_face_id] = nullptr; const Ptex::FaceInfo &fi = tex->getFaceInfo(ptex_face_id); int n = vertices_per_face[geom_face_id]; if (n == 4) /* ptex data only for quads */ { Ptex::Res res = fi.res; OBJScene::Texture *face_txt = new OBJScene::Texture(); face_txt->width = res.u(); face_txt->height = res.v(); face_txt->width_mask = 0; face_txt->height_mask = 0; face_txt->data = nullptr; face_textures[geom_face_id] = face_txt; if (nchan == 3) /* rgb color data */ { face_txt->format = OBJScene::Texture::RGBA8; face_txt->bytesPerTexel = 4; unsigned char *data = new unsigned char[face_txt->bytesPerTexel*face_txt->width*face_txt->height]; face_txt->data = data; for (int vi = 0; vi < face_txt->height; vi++) { for (int ui = 0; ui < face_txt->width; ui++) { tex->getPixel(ptex_face_id, ui, vi, px, 0, nchan, res); data[(vi*face_txt->width+ui)*4+0] = (unsigned char)(px[0]*255.0f); data[(vi*face_txt->width+ui)*4+1] = (unsigned char)(px[1]*255.0f); data[(vi*face_txt->width+ui)*4+2] = (unsigned char)(px[2]*255.0f); } } } else if (nchan == 1) /* displacement data */ { face_txt->format = OBJScene::Texture::FLOAT32; face_txt->bytesPerTexel = 4; float*data = new float[face_txt->width*face_txt->height]; face_txt->data = data; for (int vi = 0; vi < face_txt->height; vi++) { for (int ui = 0; ui < face_txt->width; ui++) { tex->getPixel(ptex_face_id, ui, vi, px, 0, nchan, res); if (!isfinite(px[0])) px[0] = 0.0f; data[vi*face_txt->width+ui] = px[0]; } } } ptex_face_id++; } else ptex_face_id += 3; } std::cout << "done" << std::endl << std::flush; return texture; #else return nullptr; #endif }
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]; } }