// Shave and a Haircut // (c) 2019 Epic Games // US Patent 6720962 /********************************************************************** *< FILE: hairAPIImp.cpp -- iplementation file DESCRIPTION: Implementation of C++ Intefraces for SHAVE2 functions CREATED BY: Vladimir Dubovoy HISTORY: created 20-08-2008 *> **********************************************************************/ #include "hairAPIimp.h" #include "assert.h" #include "shaveVrayPlugin.h" #include #include #ifdef _WIN32 #define fileno _fileno #define fstat _fstat typedef struct _stat StatType; #else #include typedef struct stat StatType; #endif extern "C" { #include "shaveSDKFUNCS2.h" // // Some shave stuff need to implement // extern VERT SHAVE2apply_GI(VERT vv, CURVEINFO *ci) { VERT retValue; retValue.x = 0.0f; retValue.y = 0.0f; retValue.z = 0.0f; return retValue; } extern void SHAVE2draw_tile_callback(VERT *a,VERT *b) { } } //end "C" /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/ | Creates an instace of hairStack | /~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ static bool doNeedYZswap = false; HAIRAPI IHairStack* LoadHair(char* dra_file, bool needYZswap) { return new HairStack(dra_file,needYZswap); } HAIRAPI IHairStack* LoadHair(void* dra_data, long data_size, bool needYZswap) { return new HairStack(dra_data,data_size,needYZswap); } /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/ | HairStack wrapper | /~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ char* IHairStack::GetVersion() { return SHAVE2query_version(); } void init_threads( void ); HAIRAPI HairStack::HairStack(char* fname, bool needYZswap) { #ifdef WIN32 InitializeCriticalSection(&csect); #else pthread_mutex_init( &mutex, NULL ); #endif //its called in shaveVrayPlugin::renderBegin //SHAVE2init(); // uncommented joe - oct 10 LOGMSG("SHAVE","SHAVE2clear_stack"); SHAVE2clear_stack(); // uncommented joe - oct 10 //init_threads(); // uncommented joe - oct 10 _needyzswap() = needYZswap; _draname() = NULL; if(fname) { Init(fname); } } HAIRAPI HairStack::HairStack(void* bdata, long size, bool needYZswap) { #ifdef WIN32 InitializeCriticalSection(&csect); #else pthread_mutex_init( &mutex, NULL ); #endif //its called in shaveVrayPlugin::renderBegin //SHAVE2init(); // uncommented joe - oct 10 LOGMSG("SHAVE","SHAVE2clear_stack"); SHAVE2clear_stack(); // uncommented joe - oct 10 //init_threads(); // uncommented joe - oct 10 _needyzswap() = needYZswap; _draname() = NULL; if(bdata && size > 0) { Init(bdata,size); } } HAIRAPI HairStack::~HairStack() { Clear(); if(draname()) free(draname()); LOGMSG("SHAVE","SHAVE2clear_stack"); SHAVE2clear_stack(); //added //called in shaveVrayPlugin::renderEnd //SHAVE2cleanup(); // uncommented joe - oct 10 #ifdef WIN32 DeleteCriticalSection(&csect); #else pthread_mutex_destroy( &mutex ); #endif } /* | from IHairStack */ HAIRAPI bool HairStack::Init(char* filename) { LOGMSG("SHAVE", "HairStack::Init"); size_t len = strlen(filename) + 5; _draname() = (char*)malloc(len); memset(draname(),0,len); sprintf(draname(),"%s",filename); LOGMSGS("SHAVE", "HairStack: dra file ",draname()); #ifdef USE_MEMFILE init_MEMFILE2(&_mem(),0); FILE* draFile = fopen(draname(), "r+b"); if(!draFile) { LOGMSGS("SHAVE","HairStack: can not open dra file ",draname()); return false; } //Get the size of the DRA file. StatType fileInfo; fstat(fileno(draFile), &fileInfo); if(fileInfo.st_size == 0) { LOGMSGS("SHAVE", "HairStack: can not read dra file ",draname()); return false; } _mem().size = fileInfo.st_size; _mem().data = (char*)malloc(mem().size); //size_t nread = fread(&_mem().data,1,mem().size,draFile); int sum = 0; int c; int p = 0; while ((c = fgetc(draFile)) != EOF) { _mem().data[p] = c; p++; sum+=c; } fclose(draFile); if(p != mem().size) { char buf[100]; sprintf(buf,"(bytes read: %i expected: %li)",p,mem().size); LOGMSGS("SHAVE", "HairStack: error reading DRA file ",buf); free_MEMFILE2(&_mem()); return false; } LOGMSGI("SHAVE", "HairStack: bytes read ",p); //printf("SHAVE> MEMFILE ID:%i data:%p, pos:%i size:%i\n",mem().ID, mem().data, mem().pos, mem().size ); LOGMSGI("SHAVE", "shaveVrayInstance: (debug) checksum ", (int)sum); Lock(); try { LOGMSG("SHAVE", "SHAVE2init_hairstack_from_mem_archive"); _voxres() = SHAVE2init_hairstack_from_mem_archive(&_mem()); // SHAVEprint_engine2(); } catch (...) { LOGMSG("SHAVE", "exception occured in SHAVE2init_hairstack_from_mem_archive"); _voxres() = -1; } UnLock(); #else Lock(); try { LOGMSG("SHAVE", "SHAVE2init_hairstack_from_archive"); _voxres() = SHAVE2init_hairstack_from_archive(draname()); } catch (...) { LOGMSG("SHAVE", "exception occured in SHAVE2init_hairstack_from_archive"); _voxres() = -1; } UnLock(); #endif if(voxres() == -1) { return false; } if(voxres() != 0) { _voxels().resize(voxres()*voxres()*voxres()); for(unsigned int i = 0; i < (unsigned int)voxels().size(); i++) { _voxel(i) = NULL; } } LOGMSG("SHAVE", "HairStack::Init - OK"); return true; } /* | from IHairStack */ HAIRAPI bool HairStack::Init(void* bdata, long size) { LOGMSG("SHAVE", "HairStack::Init"); LOGMSGI("SHAVE", "HairStack: data size ",(int)size); init_MEMFILE2(&_mem(),0); _mem().size = size; _mem().data = (char*)bdata; Lock(); try { LOGMSG("SHAVE", "SHAVE2init_hairstack_from_mem_archive"); _voxres() = SHAVE2init_hairstack_from_mem_archive(&_mem()); } catch (...) { LOGMSG("SHAVE", "exception occured in SHAVE2init_hairstack_from_mem_archive"); _voxres() = -1; } UnLock(); if(voxres() == -1) { return false; } if(voxres() != 0) { _voxels().resize(voxres()*voxres()*voxres()); for(unsigned int i = 0; i < (unsigned int)voxels().size(); i++) { _voxel(i) = NULL; } } LOGMSG("SHAVE", "HairStack::Init - OK"); return true; } /* | from IHairStack */ HAIRAPI void HairStack::Clear() { LOGMSG("SHAVE", "HairStack::Clear"); for(unsigned int i = 0; i < (unsigned int)voxels().size(); i++) { if(voxel(i)) { delete voxel(i); _voxel(i) = NULL; } } _voxels().clear(); _voxres() = 0; for(unsigned int i = 0; i < (unsigned int)nodes().size(); i++) { if(node(i)) { delete node(i); _node(i) = NULL; } } _nodes().clear(); LOGMSG("SHAVE", "SHAVE2clear_stack"); Lock(); SHAVE2clear_stack(); UnLock(); LOGMSG("SHAVE", "HairStack::Clear - OK"); } /* | from IHairStack */ HAIRAPI char* HairStack::GetDRAname() const { return draname(); } /* | from IHairStack */ HAIRAPI int HairStack::GetNumVoxels() const { return (int)voxels().size(); } /* | from IHairStack */ HAIRAPI int HairStack::GetVoxelRes() const { return voxres(); } /* | from IHairStack */ HAIRAPI IHairVoxel* HairStack::GetHairVoxel(int x, int y, int z) { int idx = 0; int nvoxels = (int)voxels().size(); if(nvoxels == 0) return NULL; if(voxelIDXformXYZ(idx,x,y,z) && idx < nvoxels) { if(!voxel(idx)) { VERT ppMax; VERT ppMin; VERT pMax; VERT pMin; Lock(); #ifdef USE_MEMFILE LOGMSG("SHAVE", "SHAVE2import_mem_archive_voxel_bbox"); if(SHAVE2import_mem_archive_voxel_bbox( &_mem(), x, y, z, &ppMin, &ppMax )) #else LOGMSG("SHAVE", "SHAVE2import_archive_voxel_bbox"); if(SHAVE2import_archive_voxel_bbox( draname(), x, y, z, &ppMin, &ppMax )) #endif { if(needyzswap()) { pMin.x = ppMin.x; pMin.y = -ppMax.z; pMin.z = ppMin.y; pMax.x = ppMax.x; pMax.y = -ppMin.z; pMax.z = ppMax.y; } else { pMin = ppMin; pMax = ppMax; } _voxel(idx) = new HairVoxel(this, pMin, pMax, x, y, z, false); } else { //no hair in voxel _voxel(idx) = new HairVoxel(); } UnLock(); } return voxel(idx); } return NULL; } /* | from IHairStack */ HAIRAPI IHairVoxel* HairStack::GetHairVoxel(int idx) { int nvoxels = (int)voxels().size(); if(nvoxels == 0) return NULL; if(idx < nvoxels) { if(!voxel(idx) ) { VERT ppMax; VERT ppMin; VERT pMax; VERT pMin; int x, y, z; if(voxelXYZformIDX(idx,x,y,z)) { Lock(); #ifdef USE_MEMFILE LOGMSG("SHAVE", "SHAVE2import_mem_archive_voxel_bbox"); if(SHAVE2import_mem_archive_voxel_bbox( &_mem(), x, y, z, &ppMin, &ppMax)) #else LOGMSG("SHAVE", "SHAVE2import_archive_voxel_bbox"); if(SHAVE2import_archive_voxel_bbox( draname(), x, y, z, &ppMin, &ppMax)) #endif { if(needyzswap()) { pMin.x = ppMin.x; pMin.y = -ppMax.z; pMin.z = ppMin.y; pMax.x = ppMax.x; pMax.y = -ppMin.z; pMax.z = ppMax.y; } else { pMin = ppMin; pMax = ppMax; } _voxel(idx) = new HairVoxel(this, pMin, pMax, x, y, z, false); } else { //no hair in voxel _voxel(idx) = new HairVoxel(); } UnLock(); } } return voxel(idx); } return NULL; } /* | from IHairStack */ HAIRAPI IHairNode* HairStack::GetHairNodeByID (int node_index, bool squirrel) { for(unsigned int i = 0; i < nodes().size(); i++) if(node(i) && node(i)->GetStackID() == node_index) return node(i); HairNode* hnode = new HairNode(this, node_index,squirrel); if(hnode->GetNumVoxels() == 0) { delete hnode; return NULL; } _nodes().push_back(hnode); return hnode; } /* | from IHairStack */ void HairStack::Lock() { #ifdef WIN32 EnterCriticalSection(&csect); #else pthread_mutex_lock( &mutex ); #endif } /* | from IHairStack */ void HairStack::UnLock() { #ifdef WIN32 LeaveCriticalSection(&csect); #else pthread_mutex_unlock( &mutex ); #endif } bool HairStack::voxelXYZformIDX(int index, int& x, int& y, int& z) { if(voxres() == 0) { x = y = z = 0; return false; } int voxresSq = voxres()*voxres(); z = index / (voxresSq); y = (index - z*voxresSq)/voxres(); x = index - z*voxresSq - y*voxres(); return true; } bool HairStack::voxelIDXformXYZ(int& index, int x, int y, int z) { if(voxres() == 0) { index = -1; return false; } index = z*(voxres()*voxres()) + y*voxres() + x; return true; } /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/ | HairHode wrapper | /~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ char* IHairNode::GetVersion() { return SHAVE2query_version(); } HAIRAPI HairNode::HairNode(HairStack* hstack, int stack_id, bool sqrl) { LOGMSG("SHAVE", "HairNode ctor"); assert(hstack); _stack() = hstack; _stackid() = stack_id; _squirrel()= sqrl; _bboxMin().x = FLT_MAX; _bboxMin().y = FLT_MAX; _bboxMin().z = FLT_MAX; _bboxMax().x = -FLT_MAX; _bboxMax().y = -FLT_MAX; _bboxMax().z = -FLT_MAX; float x1 = FLT_MAX; float y1 = FLT_MAX; float z1 = FLT_MAX; float x2 = -FLT_MAX; float y2 = -FLT_MAX; float z2 = -FLT_MAX; if(!stack()) return; int voxres = hstack->GetVoxelRes(); LOGMSGI("SHAVE", "voxres",voxres); for(int ix = 0; ix < voxres; ix++) { for(int iy = 0; iy < voxres; iy++) { for(int iz = 0; iz < voxres; iz++) { VERT pMin; VERT pMax; VERT ppMin; VERT ppMax; bool hasHair; _stack()->Lock(); try { #ifdef USE_MEMFILE LOGMSG("SHAVE", "SHAVE2import_mem_archive_voxel_bbox"); hasHair = SHAVE2import_mem_archive_voxel_bbox( stack()->GetMemFile(), ix, iy, iz, &ppMin, &ppMax ) != 0; #else LOGMSG("SHAVE", "SHAVE2import_archive_voxel_bbox"); hasHair = SHAVE2import_archive_voxel_bbox( stack()->GetDRAname(), ix, iy, iz, &ppMin, &ppMax ) != 0; #endif } catch (...) { LOGMSG("SHAVE", "an exception occured in SHAVE2import(_mem_)archive_voxel_bbox"); hasHair = false; } _stack()->UnLock(); if(!hasHair) { continue; } if(hstack->GetNeedYZswap()) { pMin.x = ppMin.x; pMin.y = -ppMax.z; pMin.z = ppMin.y; pMax.x = ppMax.x; pMax.y = -ppMin.z; pMax.z = ppMax.y; } else { pMin = ppMin; pMax = ppMax; } HairVoxel* vox = new HairVoxel(stack(),pMin,pMax, stackid(),ix,iy,iz,squirrel()); if(!vox->HasHair()) { delete vox; continue; } //init lookup tables int vox_idx = (int)voxels().size(); int num_vox_verts = vox->GetNumVerts(); for(int i = 0; i < num_vox_verts; i++) { _vtovoxs().push_back(vox_idx); _vtovoxVs().push_back(i); } int num_vox_strands = vox->GetNumStrands(); for(int i = 0; i < num_vox_strands; i++) { _stovoxs().push_back(vox_idx); _stovoxSs().push_back(i); } //add voxel to list _voxels().push_back(vox); //expand bounding box _bboxMin().x = bboxMin().x > pMin.x ? pMin.x : bboxMin().x; _bboxMin().y = bboxMin().y > pMin.y ? pMin.y : bboxMin().y; _bboxMin().z = bboxMin().z > pMin.z ? pMin.z : bboxMin().z; _bboxMax().x = bboxMax().x < pMax.x ? pMax.x : bboxMax().x; _bboxMax().y = bboxMax().y < pMax.y ? pMax.y : bboxMax().y; _bboxMax().z = bboxMax().z < pMax.z ? pMax.z : bboxMax().z; } } } LOGMSG("SHAVE", "HairNode ctor - OK"); } HAIRAPI HairNode::~HairNode() { LOGMSG("SHAVE", "HairNode dtor"); for(unsigned int i = 0; i < (unsigned int)voxels().size(); i++) { if(voxel(i)) { delete voxel(i); _voxel(i) = NULL; } } _voxels().clear(); _vtovoxs().clear(); _vtovoxVs().clear(); _stovoxs().clear(); _stovoxSs().clear(); LOGMSG("SHAVE", "HairNode dtor - OK"); } /* | from IHairNode */ HAIRAPI bool HairNode::GetBbox(VERT& pmin, VERT& pmax) const { pmin = bboxMin(); pmax = bboxMax(); return (voxels().size() > 0); } /* | from IHairNode */ HAIRAPI int HairNode::GetStackID() const { return stackid(); } /* | from IHairNode */ HAIRAPI int HairNode::GetNumVoxels()const { return (int)voxels().size(); } /* | from IHairNode */ HAIRAPI IHairVoxel* HairNode::GetVoxel(int i) const { if(i < (int)voxels().size()) return voxel(i); return NULL; } /* | from IHairNode */ int HairNode::GetNumVerts () const { return (int)vtovoxs().size(); } /* | from IHairNode */ int HairNode::GetNumStrands() const { return (int)stovoxs().size(); } /* | from IHairNode */ int HairNode::GetNumFaces() const { return (int)stovoxs().size(); } /* | from IHairNode */ void HairNode::GetVert(int i, float& x, float& y, float& z) const { int vox_idx; int vert_idx; vertIndexToVoxVertIndex(i,vox_idx,vert_idx); voxel(vox_idx)->GetVert(vert_idx,x,y,z); } /* | from IHairNode */ void HairNode::GetVelocity(int i, float& x, float& y, float& z) const { int vox_idx; int vert_idx; vertIndexToVoxVertIndex(i,vox_idx,vert_idx); voxel(vox_idx)->GetVelocity(vert_idx,x,y,z); } /* | from IHairNode */ void HairNode::GetStrand(int i, int& v_start, int& v_end) const { int vox_idx; int str_idx; strandIndexToVoxStrandIndex(i,vox_idx,str_idx); voxel(vox_idx)->GetStrand(str_idx,v_start,v_end); } /* | from IHairNode */ void HairNode::GetFace(int i, int& v_start, int& v_end) const { int vox_idx; int str_idx; strandIndexToVoxStrandIndex(i,vox_idx,str_idx); voxel(vox_idx)->GetFace(str_idx,v_start,v_end); } /* | from IHairNode */ bool HairNode::IsColorConst (int i) const { int vox_idx; int str_idx; strandIndexToVoxStrandIndex(i,vox_idx,str_idx); return voxel(vox_idx)->IsColorConst(str_idx); } /* | from IHairNode */ void HairNode::GetRootColor (int i, float& r, float& g, float& b) const { int vox_idx; int str_idx; strandIndexToVoxStrandIndex(i,vox_idx,str_idx); voxel(vox_idx)->GetRootColor(str_idx,r,g,b); } /* | from IHairNode */ void HairNode::GetTipColor(int i, float& r, float& g, float& b) const { int vox_idx; int str_idx; strandIndexToVoxStrandIndex(i,vox_idx,str_idx); voxel(vox_idx)->GetTipColor(str_idx,r,g,b); } /* | from IHairNode */ void HairNode::GetVertColor(int i, int knot_idx, float& r, float& g, float& b) const { int vox_idx; int str_idx; strandIndexToVoxStrandIndex(i,vox_idx,str_idx); voxel(vox_idx)->GetVertColor(str_idx,knot_idx,r,g,b); } /* | from IHairNode */ void HairNode::GetColor(int i, float t, float& r, float& g, float& b) const { int vox_idx; int str_idx; strandIndexToVoxStrandIndex(i,vox_idx,str_idx); voxel(vox_idx)->GetColor(str_idx,t,r,g,b); } /* | from IHairNode */ void HairNode::GetSurfNormal(int i, float& x, float& y, float& z) const { int vox_idx; int str_idx; strandIndexToVoxStrandIndex(i,vox_idx,str_idx); voxel(vox_idx)->GetSurfNormal(str_idx,x,y,z); } /* | from IHairNode */ float HairNode::GetStrandGlossiness(int i) const { int vox_idx; int str_idx; strandIndexToVoxStrandIndex(i,vox_idx,str_idx); return voxel(vox_idx)->GetStrandGlossiness(str_idx); } /* | from IHairNode */ float HairNode::GetStrandSpecLevel(int i) const { int vox_idx; int str_idx; strandIndexToVoxStrandIndex(i,vox_idx,str_idx); return voxel(vox_idx)->GetStrandSpecLevel(str_idx); } /* | from IHairNode */ float HairNode::GetStrandOpacity(int i) const { int vox_idx; int str_idx; strandIndexToVoxStrandIndex(i,vox_idx,str_idx); return voxel(vox_idx)->GetStrandOpacity(str_idx); } /* | from IHairNode */ float HairNode::GetStrandAmbDiff(int i) const { int vox_idx; int str_idx; strandIndexToVoxStrandIndex(i,vox_idx,str_idx); return voxel(vox_idx)->GetStrandAmbDiff(str_idx); } /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/ | HairVoxel wrapper | /~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ HAIRAPI HairVoxel::HairVoxel() { _stack() = NULL; _hashair() = false; _nodevoxel()= false; _nodeindex()= -1; _squirrel() = false; _bboxMin().x = FLT_MAX; _bboxMin().y = FLT_MAX; _bboxMin().z = FLT_MAX; _bboxMax().x = -FLT_MAX; _bboxMax().y = -FLT_MAX; _bboxMax().z = -FLT_MAX; _hairtype().owner = NULL; } HAIRAPI HairVoxel::HairVoxel(HairStack* hstack, const VERT& pmin, const VERT& pmax, int ix, int iy, int iz, bool squirr) { LOGMSGI3("SHAVE","HairVoxel ctor",ix, iy, iz); _stack() = hstack; _hashair() = false; _nodevoxel()= false; _nodeindex()= -1; _squirrel() = squirr; _bboxMin() = pmin; _bboxMax() = pmax; assert(hstack); if(!hstack) return; _stack()->Lock(); #ifdef USE_MEMFILE LOGMSG("SHAVE","SHAVE2import_mem_archive_voxel"); SHAVE2import_mem_archive_voxel( stack()->GetMemFile(), ix, iy, iz, &_hairtype(), 0); #else LOGMSG("SHAVE","SHAVE2import_archive_voxel"); SHAVE2import_archive_voxel( hstack->GetDRAname(), ix, iy, iz, &_hairtype(), 0); #endif _stack()->UnLock(); LOGMSGI("SHAVE","numfaces",hairtype().totalfaces); _hashair() = hairtype().totalfaces != 0; _hairtype().owner = hstack; _hairtype().squirrel = squirrel(); LOGMSG("SHAVE","HairVoxel ctor - OK"); } HAIRAPI HairVoxel::HairVoxel(HairStack* hstack, const VERT& pmin, const VERT& pmax, int stack_id, int ix, int iy, int iz, bool squirr) { LOGMSGI3("SHAVE","HairVoxel ctor2",ix, iy, iz); _stack() = hstack; _hashair() = false; _nodevoxel()= true; _nodeindex()= stack_id; _squirrel() = squirr; _bboxMin() = pmin; _bboxMax() = pmax; assert(hstack); if(!hstack) return; _stack()->Lock(); #ifdef USE_MEMFILE LOGMSG("SHAVE","SHAVE2import_mem_archive_voxel_by_node"); SHAVE2import_mem_archive_voxel_by_node(stack()->GetMemFile(),ix,iy,iz, &_hairtype(), &_hairuvs(), 0, stack_id); #else LOGMSG("SHAVE","SHAVE2import_archive_voxel_by_node"); SHAVE2import_archive_voxel_by_node(hstack->GetDRAname(),ix,iy,iz, &_hairtype(), &_hairuvs(), 0, stack_id); #endif LOGMSGI("SHAVE","numfaces",hairtype().totalfaces); _stack()->UnLock(); _hashair() = hairtype().totalfaces != 0; _hairtype().owner = hstack; _hairtype().squirrel = squirrel(); ////////////// debug //////////// //int nv = hairtype().GetNumVerts(); //for(int i = 0; i < nv; i++) //{ // float u,v,w; // hairtype().GetUV(i,u,v,w); // printf("uvw %f %f %f\n", u,v,w); //} //fflush(stdout); ///////////////////////////////// LOGMSG("SHAVE","HairVoxel ctor2 - OK"); } HAIRAPI HairVoxel::~HairVoxel() { LOGMSG("SHAVE","HairVoxel dtor"); LOGMSG("SHAVE","HairVoxel dtor - OK"); } /* | from IHairVoxel */ HAIRAPI bool HairVoxel::HasHair() const { return hashair(); } /* | from IHairVoxel */ HAIRAPI bool HairVoxel::IsNodeVoxel() const { return nodevoxel(); } /* | from IHairVoxel */ HAIRAPI int HairVoxel::GetNodeID(void) const { return nodeindex(); } /* | from IHairVoxel */ HAIRAPI bool HairVoxel::GetBbox(VERT& pmin, VERT& pmax) const { pmin = bboxMin(); pmax = bboxMax(); return hashair(); } /* | from IHairVoxel */ HAIRAPI const HairType& HairVoxel::GetHair(/*bool isShadow*/) { return hairtype(); } /* | from IHairVoxel */ HAIRAPI const HairUVs& HairVoxel::GetUVs (/*bool isShadow*/) { return hairuvs(); } /* | from IHairVoxel */ int HairVoxel::GetNumVerts () const { return hairtype().GetNumVerts(); } /* | from IHairVoxel */ int HairVoxel::GetNumStrands() const { return hairtype().GetNumStrands(); } /* | from IHairVoxel */ int HairVoxel::GetNumFaces() const { return hairtype().GetNumFaces(); } /* | from IHairVoxel */ void HairVoxel::GetVert(int vertidx, float& x, float& y, float& z) const { hairtype().GetVert(vertidx,x,y,z); } /* | from IHairVoxel */ void HairVoxel::GetVelocity(int vertidx, float& x, float& y, float& z) const { hairtype().GetVelocity(vertidx,x,y,z); } /* | from IHairVoxel */ void HairVoxel::GetStrand(int strandidx, int& v_start, int& v_end) const { hairtype().GetStrand(strandidx,v_start,v_end); } /* | from IHairVoxel */ void HairVoxel::GetFace(int faceidx, int& v_start, int& v_end) const { hairtype().GetFace(faceidx,v_start,v_end); } /* | from IHairVoxel */ bool HairVoxel::IsColorConst(int strandidx) const { return hairtype().IsColorConst(strandidx); } /* | from IHairVoxel */ void HairVoxel::GetRootColor(int strandidx, float& r, float& g, float& b) const { hairtype().GetRootColor(strandidx,r,g,b); } /* | from IHairVoxel */ void HairVoxel::GetTipColor(int strandidx, float& r, float& g, float& b) const { hairtype().GetTipColor(strandidx,r,g,b); } /* | from IHairVoxel */ void HairVoxel::GetVertColor(int strandidx, int knot_idx, float& r, float& g, float& b) const { hairtype().GetVertColor(strandidx,knot_idx,r,g,b); } /* | from IHairVoxel */ void HairVoxel::GetColor(int strandidx, float t, float& r, float& g, float& b) const { hairtype().GetColor(strandidx,t,r,g,b); } /* | from IHairVoxel */ void HairVoxel::GetSurfNormal(int strandidx, float& x, float& y, float& z) const { hairtype().GetSurfNormal(strandidx,x,y,z); } /* | from IHairVoxel */ float HairVoxel::GetStrandGlossiness(int i) const { return hairtype().gloss[i]; } /* | from IHairVoxel */ float HairVoxel::GetStrandSpecLevel(int i) const { return hairtype().spec[i]; } /* | from IHairVoxel */ float HairVoxel::GetStrandOpacity(int i) const { return hairtype().opacity[i]; } /* | from IHairVoxel */ float HairVoxel::GetStrandAmbDiff(int i) const { return hairtype().ambdiff[i]; } /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/ | HairType wrapper | /~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ HAIRAPI HairType::HairType(bool init) { if(init) { LOGMSG("SHAVE","SHAVE2init_hairtype"); SHAVE2init_hairtype(this); } squirrel = false; } HAIRAPI HairType::~HairType() { LOGMSG("SHAVE","SHAVE2free_hairtype"); SHAVE2free_hairtype(this); } int HairType::GetNumStrands() const { return totalfaces; } int HairType::GetNumFaces() const { return totalfaces; } int HairType::GetNumVerts() const { return totalverts; } int HairType::GetFaceVert(int face_list_idx ) const { return facelist[face_list_idx]; } void HairType::GetVert(int i, float &x, float &y, float &z) const { bool doswap = owner ? ((HairStack*)owner)->GetNeedYZswap() : false; if(doswap) { x = v[i].x; y = -v[i].z; z = v[i].y; } else { x = v[i].x; y = v[i].y; z = v[i].z; } } void HairType::GetUV (int i, float& u, float& v, float& w) const { u = uvw[i].x; v = uvw[i].y; w = uvw[i].z; } void HairType::GetVelocity(int i, float& x, float& y, float& z) const { bool doswap = owner ? ((HairStack*)owner)->GetNeedYZswap() : false; if(doswap) { x = velocity[i].x; y = -velocity[i].z; z = velocity[i].y; } else { x = velocity[i].x; y = velocity[i].y; z = velocity[i].z; } //x = 0.0f; //y = 0.0f; //z = 0.0f; } void HairType::GetStrand(int i, int& v_start, int& v_end) const { v_start = face_start[i]; v_end = face_end[i]; } void HairType::GetFace(int i, int& v_start, int& v_end) const { v_start = face_start[i]; v_end = face_end[i]; } bool HairType::IsColorConst(int i) const { return (colorroot[i].x == colortip[i].x) && (colorroot[i].y == colortip[i].y) && (colorroot[i].z == colortip[i].z); } void HairType::GetRootColor(int i, float& r, float& g, float& b) const { r = colorroot[i].x; g = colorroot[i].y; b = colorroot[i].z; } void HairType::GetTipColor (int i, float& r, float& g, float& b) const { r = colortip[i].x; g = colortip[i].y; b = colortip[i].z; } void HairType::GetVertColor(int i, int v, float& r, float& g, float& b) const { if((colorroot[i].x == colortip[i].x) && (colorroot[i].y == colortip[i].y) && (colorroot[i].z == colortip[i].z)) { r = colorroot[i].x; g = colorroot[i].y; b = colorroot[i].z; return; } int nknots = face_end[i] - face_start[i]; float t = (float)v/(float)nknots; float T = 1.0f - t; if (!squirrel) { r = colorroot[i].x*T + colortip[i].x*t; g = colorroot[i].y*T + colortip[i].y*t; b = colorroot[i].z*T + colortip[i].z*t; } else { if (t<.7) { r=colorroot[i].x; g=colorroot[i].y; b=colorroot[i].z; } else { r=colortip[i].x; g=colortip[i].y; b=colortip[i].z; } } } void HairType::GetColor (int i, float t, float& r, float& g, float& b) const { if((colorroot[i].x == colortip[i].x) && (colorroot[i].y == colortip[i].y) && (colorroot[i].z == colortip[i].z)) { r = colorroot[i].x; g = colorroot[i].y; b = colorroot[i].z; return; } if (!squirrel) { float T = 1.0f - t; r = colorroot[i].x*T + colortip[i].x*t; g = colorroot[i].y*T + colortip[i].y*t; b = colorroot[i].z*T + colortip[i].z*t; } else { if (t<.7) { r=colorroot[i].x; g=colorroot[i].y; b=colorroot[i].z; } else { r=colortip[i].x; g=colortip[i].y; b=colortip[i].z; } } } void HairType::GetSurfNormal(int i, float& x, float& y, float& z) const { bool doswap = owner ? ((HairStack*)owner)->GetNeedYZswap() : false; if(doswap) { x = surfNorm[i].x; y = -surfNorm[i].z; z = surfNorm[i].y; } else { x = surfNorm[i].x; y = surfNorm[i].y; z = surfNorm[i].z; } } float HairType::GetStrandGlossiness(int i) const { return gloss[i]; } float HairType::GetStrandSpecLevel(int i) const { return spec[i]; } float HairType::GetStrandOpacity(int i) const { return opacity[i]; } float HairType::GetStrandAmbDiff(int i) const { return ambdiff[i]; } /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~/ | HairUVs wrapper | /~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/ HAIRAPI HairUVs::HairUVs(bool init) { if(init) { LOGMSG("SHAVE", "SHAVE2init_UV"); SHAVE2init_UV(this); } } HAIRAPI HairUVs::~HairUVs() { LOGMSG("SHAVE", "SHAVE2free_UV"); //comment for text SHAVE2free_UV(this); }