// Shave and a Haircut // (c) 2019 Epic Games // US Patent 6720962 #include #include "shaveSDKFUNCS.h" #include "mini_kernal_structs.h" extern void SHAVEallocate_kernal(MINIKERNAL *in,SHAVEPARMS *shavep, int haircount,int hairsegs); void SHAVEfree_kernal(MINIKERNAL *in); void SHAVEinit_kernal(MINIKERNAL *in); void MTmake_a_bunchROOT( int list_total, int *list, MINIKERNAL *m, int threadID ); typedef int errcode; // //approx size helpers for memory allocation // static size_t get_newguides_size(NEWGUIDES* n, size_t segs, size_t size) { size_t hv = sizeof(VERT) * segs * size; size_t resthv = sizeof(VERT) * segs * size; size_t velocity = sizeof(VERT) * segs * size; size_t noisev = sizeof(VERT) * segs * size; return sizeof(NEWGUIDES) * size + hv + resthv + velocity + noisev; } static size_t get_rootpts_size(ROOTPT* r, size_t size) { int tex_link = sizeof(unsigned char) * r->total_tex * size; // was UCHAR int baked_tex = sizeof(float) * r->total_tex * size; return sizeof(ROOTPT)*size + tex_link + baked_tex; } static size_t get_minikernal_size(MINIKERNAL* k) { size_t hairlist_size = k->hairlist_size * sizeof(int); size_t guides = get_newguides_size(k->guides, k->guide_segs, k->total_guides); size_t hair_roots = get_rootpts_size(k->hair_roots, k->total_roots); size_t clump_roots = get_rootpts_size(k->clump_roots, k->total_clumps); size_t return_hair = get_newguides_size(k->return_hair, k->guide_segs, k->hairlist_size); // size_t multiplier_offsets = sizeof(VERT) * k->multiplier; // size_t multiplier_root_colors = sizeof(VERT) * k->multiplier; // size_t multiplier_tip_colors = sizeof(VERT) * k->multiplier; return sizeof(MINIKERNAL) + hairlist_size + guides + hair_roots + clump_roots; // return_hair ; // multiplier_offsets + // multiplier_root_colors + // multiplier_tip_colors; } // // save // static void save_uchar(unsigned char i, char** buf) { unsigned char* p = (unsigned char*)(*buf); (*p) = i; (*buf) += sizeof(unsigned char); } static void save_int(int i, char** buf) { int* p = (int*)(*buf); (*p) = i; (*buf) += sizeof(int); } static void save_float(float i, char** buf) { float* p = (float*)(*buf); (*p) = i; (*buf) += sizeof(float); } static void save_vert(VERT i, char** buf) { VERT* p = (VERT*)(*buf); (*p) = i; (*buf) += sizeof(VERT); } static void save_uchars(unsigned char* uchars, int count, char** buf) { int i; save_int(count, buf); for (i = 0; i < count; ++i) { save_uchar(uchars[i], buf); } } static void save_ints(int* ints, int count, char** buf) { int i; save_int(count, buf); for (i = 0; i < count; ++i) { save_int(ints[i], buf); } } static void save_floats(float* floats, int count, char** buf) { int i; save_int(count, buf); for (i = 0; i < count; ++i) { save_float(floats[i], buf); } } static void save_verts(VERT* verts, int count, char** buf) { int i; save_int(count, buf); for (i = 0; i < count; ++i) { save_vert(verts[i], buf); } } static void save_newguidess(NEWGUIDES* n, int segs, int count, char** buf) { int i; save_int(count, buf); for (i = 0; i < count; ++i) { save_verts(n[i].hv, segs, buf); save_verts(n[i].resthv, segs, buf); save_verts(n[i].velocity, segs, buf); save_verts(n[i].noisev, segs, buf); save_vert(n[i].rest_handle, buf); save_vert(n[i].rest_normal, buf); save_vert(n[i].handle, buf); save_vert(n[i].normal, buf); save_float(n[i].uu, buf); save_float(n[i].vv, buf); } } static void save_rootpts(ROOTPT* r, int count, char** buf) { int i; save_int(count, buf); for (i = 0; i < count; ++i) { save_int(r[i].id, buf); save_int(r[i].killme, buf); save_vert(r[i].resthv, buf); save_vert(r[i].bary, buf); save_int(r[i].pntid1, buf); save_int(r[i].pntid2, buf); save_int(r[i].pntid3, buf); save_int(r[i].closest_clump, buf); save_float(r[i].distance, buf); save_int(r[i].total_tex, buf); save_uchars(r[i].tex_link, r[i].total_tex, buf); save_floats(r[i].baked_tex, r[i].total_tex, buf); save_float(r[i].flip, buf); } } static void save_minikernal(MINIKERNAL* k, char* buf) { int i, j, k_; char** b = &buf; save_int(k->multiplier, b); save_int(k->segs, b); save_int(k->interpolation_type, b); save_int(k->total_guides, b); save_int(k->total_clumps, b); save_int(k->total_roots, b); save_int(k->guide_segs, b); save_int(k->enable_interpolation, b); save_int(k->hairlist_size, b); save_ints(k->hairlist, k->hairlist_size, b); save_int(k->dirty, b); save_int(k->instancing_status, b); save_int(k->tipfade, b); save_int(k->rand_seed_offset, b); save_int(k->squirrel, b); for (i = 0; i < SHAVE_NUM_PARAMS; ++i) { save_float(k->slider_val[i], b); } save_float(k->geom_shadow, b); save_float(k->multrot, b); save_float(k->multrot_phase, b); save_float(k->multrot_offset, b); save_float(k->flyaway_percent, b); save_vert(k->spec_tint, b); save_vert(k->spec_tint2, b); save_newguidess(k->guides, k->guide_segs, k->total_guides, b); save_rootpts(k->hair_roots, k->total_roots, b); save_rootpts(k->clump_roots, k->total_clumps, b); // save_newguidess(k->return_hair, k->guide_segs, k->hairlist_size, b); +question return_hairs don't belong in file // save_verts(k->multiplier_offsets, k->multiplier, b); // save_verts(k->multiplier_root_colors, k->multiplier, b); // save_verts(k->multiplier_tip_colors, k->multiplier, b); for (i = 0; i < 20; ++i) { for (j = 0; j < 20; ++j) { for (k_ = 0; k_ < 20; ++k_) { save_float(k->noise[i][j][k_], b); } } } save_float(k->RESTBOUND, b); } // // load // static void load_uchar(unsigned char* i, char** buf) { unsigned char* p = (unsigned char*)(*buf); (*i) = (*p); (*buf) += sizeof(unsigned char); } static void load_int(int* i, char** buf) { int* p = (int*)(*buf); (*i) = (*p); (*buf) += sizeof(int); } static void load_float(float* i, char** buf) { float* p = (float*)(*buf); (*i) = (*p); (*buf) += sizeof(float); } static void load_vert(VERT* i, char** buf) { VERT* p = (VERT*)(*buf); (*i) = (*p); (*buf) += sizeof(VERT); } static void load_uchars(unsigned char** chars, char** buf) { int i; int size; load_int(&size, buf); if (size == 0) { return; } (*chars) = (unsigned char*)malloc(sizeof(unsigned char) * size); for (i = 0; i < size; ++i) { load_uchar(&(*chars)[i], buf); } } static void load_ints(int** ints, char** buf) { int i; int size; load_int(&size, buf); if (size == 0) { return; } (*ints) = (int*)malloc(sizeof(int) * size); for (i = 0; i < size; ++i) { load_int(&(*ints)[i], buf); } } static void load_floats(float** floats, char** buf) { int i; int size; load_int(&size, buf); if (size == 0) { return; } (*floats) = (float*)malloc(sizeof(float) * size); for (i = 0; i < size; ++i) { load_float(&(*floats)[i], buf); } } static void load_verts(VERT** verts, char** buf) { static int z = 0; int i; int size; load_int(&size, buf); if (size == 0) { return; } (*verts) = (VERT*)malloc(sizeof(VERT) * size); for (i = 0; i < size; ++i) { load_vert(&(*verts)[i], buf); } } static void load_newguidess(NEWGUIDES** n, char** buf) { int i; int count; NEWGUIDES* n_; load_int(&count, buf); if (count == 0) { return; } (*n) = (NEWGUIDES*)malloc(sizeof(NEWGUIDES)*count); n_ = (*n); for (i = 0; i < count; ++i) { load_verts(&n_[i].hv, buf); load_verts(&n_[i].resthv, buf); load_verts(&n_[i].velocity, buf); load_verts(&n_[i].noisev, buf); load_vert(&n_[i].rest_handle, buf); load_vert(&n_[i].rest_normal, buf); load_vert(&n_[i].handle, buf); load_vert(&n_[i].normal, buf); load_float(&n_[i].uu, buf); load_float(&n_[i].vv, buf); } } static void load_rootpts(ROOTPT** r, char** buf) { int count; int i; ROOTPT* r_; load_int(&count, buf); if (count == 0) { return; } (*r) = (ROOTPT*)malloc(sizeof(ROOTPT)*count); r_ = (*r); for (i = 0; i < count; ++i) { load_int(&r_[i].id, buf); load_int(&r_[i].killme, buf); load_vert(&r_[i].resthv, buf); load_vert(&r_[i].bary, buf); load_int(&r_[i].pntid1, buf); load_int(&r_[i].pntid2, buf); load_int(&r_[i].pntid3, buf); load_int(&r_[i].closest_clump, buf); load_float(&r_[i].distance, buf); load_int(&r_[i].total_tex, buf); load_uchars(&r_[i].tex_link, buf); load_floats(&r_[i].baked_tex, buf); load_float(&r_[i].flip, buf); } } static void load_minikernal(MINIKERNAL** kernal, char* buf) { int i, j, k_; char** b = &buf; MINIKERNAL* k; (*kernal) = (MINIKERNAL*)malloc(sizeof(MINIKERNAL)); k = (*kernal); load_int(&k->multiplier, b); load_int(&k->segs, b); load_int(&k->interpolation_type, b); load_int(&k->total_guides, b); load_int(&k->total_clumps, b); load_int(&k->total_roots, b); load_int(&k->guide_segs, b); load_int(&k->enable_interpolation, b); load_int(&k->hairlist_size, b); load_ints(&k->hairlist, b); load_int(&k->dirty, b); load_int(&k->instancing_status, b); load_int(&k->tipfade, b); load_int(&k->rand_seed_offset, b); load_int(&k->squirrel, b); for (i = 0; i < SHAVE_NUM_PARAMS; ++i) { load_float(&k->slider_val[i], b); } load_float(&k->geom_shadow, b); load_float(&k->multrot, b); load_float(&k->multrot_phase, b); load_float(&k->multrot_offset, b); load_float(&k->flyaway_percent, b); load_vert(&k->spec_tint, b); load_vert(&k->spec_tint2, b); load_newguidess(&k->guides, b); load_rootpts(&k->hair_roots, b); load_rootpts(&k->clump_roots, b); // load_newguidess(&k->return_hair, b); +question not loading return_hair from disk // load_verts(&k->multiplier_offsets, b); // load_verts(&k->multiplier_root_colors, b); // load_verts(&k->multiplier_tip_colors, b); for (i = 0; i < 20; ++i) { for (j = 0; j < 20; ++j) { for (k_ = 0; k_ < 20; ++k_) { load_float(&k->noise[i][j][k_], b); } } } load_float(&k->RESTBOUND, b); } // // file routines // const int KVERSION = 1; int save_minikernal_to_file(MINIKERNAL* k, CHNG * filename) { int version = KVERSION; FILE* f = fopen(filename, "wb"); if (!f) { return -1; } { size_t k_size = get_minikernal_size(k); char* buf = (char*)malloc(k_size); save_minikernal(k, buf); //version fwrite(&version, sizeof(version), 1, f); fwrite(buf, k_size, 1, f); free(buf); fclose(f); } return 0; } void allocate_return_hair(MINIKERNAL *k); static void load_minikernal_without_allocation(MINIKERNAL* k, char* buf) { int i, j, k_; char** b = &buf; float ff; load_int(&k->multiplier, b); load_int(&k->segs, b); load_int(&k->interpolation_type, b); load_int(&k->total_guides, b); load_int(&k->total_clumps, b); load_int(&k->total_roots, b); load_int(&k->guide_segs, b); load_int(&k->enable_interpolation, b); load_int(&k->hairlist_size, b); load_ints(&k->hairlist, b); load_int(&k->dirty, b); load_int(&k->instancing_status, b); load_int(&k->tipfade, b); load_int(&k->rand_seed_offset, b); load_int(&k->squirrel, b); for (i = 0; i < SHAVE_NUM_PARAMS; ++i) { load_float(&ff, b); k->slider_val[i]=ff; } load_float(&k->geom_shadow, b); load_float(&k->multrot, b); load_float(&k->multrot_phase, b); load_float(&k->multrot_offset, b); load_float(&k->flyaway_percent, b); load_vert(&k->spec_tint, b); load_vert(&k->spec_tint2, b); load_newguidess(&k->guides, b); load_rootpts(&k->hair_roots, b); load_rootpts(&k->clump_roots, b); allocate_return_hair(k); // load_newguidess(&k->return_hair, b); //+question not loading return_hair from disk // load_verts(&k->multiplier_offsets, b); // load_verts(&k->multiplier_root_colors, b); // load_verts(&k->multiplier_tip_colors, b); for (i = 0; i < 20; ++i) { for (j = 0; j < 20; ++j) { for (k_ = 0; k_ < 20; ++k_) { load_float(&k->noise[i][j][k_], b); } } } load_float(&k->RESTBOUND, b); } int load_minikernal_from_file(MINIKERNAL** k, CHNG* filename) { char* buf; FILE* f = fopen(filename, "rb"); if (!f) { return -1; } { int version; long fsize; fseek(f, 0, SEEK_END); fsize = ftell(f); fseek(f, 0, SEEK_SET); fread(&version, sizeof(int), 1, f); if (version != KVERSION) { return -2; } buf = (char*)malloc(fsize + 1); //we have already read version, so read `fsize - sizeof(int)` fread(buf, fsize - sizeof(int), 1, f); fclose(f); } { load_minikernal(k, buf); } return 0; } static void MYfclose( void *indata ); void SHAVEfetch_node_for_game( SHAVENODE * sn ); // create a minikernal out of the current node - note must update textures with the full count first #ifdef DOUNICODE void SHAVEwrite_nodeDISK(wchar_t *filename) #else void SHAVEwrite_nodeDISK(char *filename) #endif { MINIKERNAL k; SHAVEPARMS shavep; int *list; int count,segs; int x; SHAVENODE sn; printf ("Outputing game format\n"); // let's assume the engine is loaded and textures will available from callbacks //<<<<<<< HEAD //printf ("Outputing game format\n"); //printf ("fetching node\n"); //======= //>>>>>>> efeea345675c57cb08107eccec76b731adbe435e //SHAVEinit_node(&sn,0); sn.restMEM.data=NULL; sn.statMEM.data=NULL; sn.restMEM.size=0; sn.statMEM.size=0; SHAVEfetch_node_for_game( &sn ); SHAVEfetch_parms(&sn.shavep); count=sn.shavep.haircount[0]; segs=sn.shavep.segs[0]; k.interpolation_type=MESH_GROWTH; if (sn.shavep.haircount[4]>0) { count=sn.shavep.haircount[4]; segs=sn.shavep.segs[4]; k.interpolation_type=SPLINE_GROWTH; // spline } list=(int *) malloc ((count)*sizeof(int)); for (x=0;xk.total_roots)) printf ("woa - hair#%d's ID = %d\n",x,k.hair_roots[k.hairlist[x]].id); { CHNG tmpname[1555]; int size_shavep; FILE *fp; int total_size; size_t k_size = get_minikernal_size(&k); char* buf1 = (char*)malloc(k_size); size_t m2_size = sn.restMEM.size; char* buf2 = (char*)malloc(m2_size); size_t m3_size = sn.statMEM.size; char* buf3 = (char*)malloc(m3_size); memcpy(buf2,sn.restMEM.data,m2_size); memcpy(buf3,sn.statMEM.data,m3_size); save_minikernal(&k, buf1); RW_CONTEXT=RW_DISK; // we're outputing to disk printf ("writing header\n"); #ifdef DOUNICODE swprintf( tmpname, L"%s", filename ); fp = ( FILE * ) MYfopen( tmpname, L"wb" ); #else sprintf( tmpname, "%s", filename ); fp = ( FILE * ) MYfopen( tmpname, "wb" ); #endif total_size=k_size+m2_size+m3_size+sizeof(int)*8+sizeof(float)*2; size_shavep=sizeof(SHAVEPARMS); fwrite (&total_size,sizeof(int),1,fp); fwrite (&KVERSION,sizeof(int),1,fp); fwrite (&k_size,sizeof(int),1,fp); printf ("k_size = %d\n",k_size); fwrite (&m2_size,sizeof(int),1,fp); printf ("m2_size = %d\n",m2_size); fwrite (&m3_size,sizeof(int),1,fp); printf ("m3_size = %d\n",m3_size); fwrite (&size_shavep,sizeof(int),1,fp); fwrite (&sn.restMEM.ID,sizeof(int),1,fp); fwrite (&sn.statMEM.ID,sizeof(int),1,fp); fwrite (&sn.restMEM.time,sizeof(float),1,fp); fwrite (&sn.statMEM.time,sizeof(float),1,fp); printf ("writing kernal\n"); fwrite (buf1,k_size,1,fp); printf ("writing node\n"); fwrite (buf2,m2_size,1,fp); fwrite (buf3,m3_size,1,fp); printf ("writing parms\n"); fwrite (&sn.shavep,sizeof(SHAVEPARMS),1,fp); free (buf1); free (buf2); free (buf3); printf ("closing file\n"); MYfclose(fp); } // save_minikernal_to_file(&k, filename); printf ("freeing kernal\n"); SHAVEfree_kernal(&k); printf ("freeing node\n"); SHAVEfree_node(&sn); free(list); printf ("done writing game format\n"); } void SHAVEalloc_node( SHAVENODE * sn ); extern void SHAVEload_nodeDISK(MINIKERNAL *k,CHNG * filename) { // let's assume the kernal is up to date // load_minikernal_from_file(&k, filename); int *list; int count; int x; SHAVENODE sn; // let's assume the engine is loaded and textures will available from callbacks { CHNG tmpname[1555]; FILE *fp; float tm1,tm2; int total_size; int size_shavep; int KV; size_t k_size =0; size_t m2_size=0; size_t m3_size=0; char *buf1,*buf2,*buf3,*buf4; buf1=NULL; buf2=NULL; buf3=NULL; buf4=NULL; // save_minikernal(&k, buf1); //SHAVEinit_node(&k->shavenode,0); RW_CONTEXT=RW_DISK; // we're outputing to disk #ifdef DOUNICODE swprintf( tmpname, L"%s", filename ); fp = ( FILE * ) MYfopen( tmpname, L"rb" ); #else sprintf( tmpname, "%s", filename ); fp = ( FILE * ) MYfopen( tmpname, "rb" ); #endif if (fp) { size_shavep=sizeof(SHAVEPARMS); fread (&total_size,sizeof(int),1,fp); fread (&KV,sizeof(int),1,fp); if (KV==1) { fread (&k_size,sizeof(int),1,fp); fread (&m2_size,sizeof(int),1,fp); fread (&m3_size,sizeof(int),1,fp); fread (&size_shavep,sizeof(int),1,fp); fread (&k->shavenode.restMEM.ID,sizeof(int),1,fp); fread (&k->shavenode.statMEM.ID,sizeof(int),1,fp); fread (&tm1,sizeof(float),1,fp); fread (&tm2,sizeof(float),1,fp); buf1 = (char*)malloc(k_size); buf2 = (char*)malloc(m2_size); buf3 = (char*)malloc(m3_size); buf4 = (char*)malloc(size_shavep); fread (buf1,k_size,1,fp); fread (buf2,m2_size,1,fp); fread (buf3,m3_size,1,fp); fread (buf4,size_shavep,1,fp); // fread (&k->shavenode.shavep,size_shavep,1,fp); load_minikernal_without_allocation(k,buf1); k->shavenode.restMEM.size=(long)m2_size; k->shavenode.statMEM.size=(long)m3_size; k->shavenode.restMEM.pos=0; k->shavenode.statMEM.pos=0; k->shavenode.restMEM.data=NULL; k->shavenode.statMEM.data=NULL; k->shavenode.restMEM.time=0.0f; k->shavenode.statMEM.time=0.0f; // SHAVEalloc_node(&k->shavenode); k->shavenode.restMEM.data = (char*) malloc(m2_size*sizeof(char)); k->shavenode.statMEM.data = (char*) malloc(m3_size*sizeof(char)); memcpy(k->shavenode.restMEM.data,buf2,m2_size); memcpy(k->shavenode.statMEM.data,buf3,m3_size); memcpy(&k->shavenode.shavep,buf4,size_shavep); fclose(fp); RW_CONTEXT=RW_LOCAL; // we're outputing to disk SHAVEflush_state(&k->shavenode); SHAVEset_parms(&k->shavenode.shavep); free (buf1); free (buf2); free (buf3); free (buf4); } }// fp } for (x=0;xtotal_roots;x++) if ((k->hair_roots[x].id<0) || (k->hair_roots[x].id>k->total_roots)) printf ("input - woa - hair#%d's ID = %d\n",k->hair_roots[x].id); }