// Shave and a Haircut // (c) 2019 Epic Games // US Patent 6720962 #include "shaveSDKTYPES.h" #include "shaveSDKFUNCS.h" VERT lastmouseworld; VERT lastmousescreen; VERT avg_hair[15]; #include int sbrush; void set_trim( void ); static void cut_hairNOTAG( void ); static VERT Vcross( VERT a, VERT b ); static void mkmatrix( Matrix m, VERT xx, VERT yy, VERT zz, VERT b ); Matrix camOrient, icamOrient; VERT brushCamPos; VERT Gmouse_down_world; typedef enum { kBrushTip, kBrushStrand, kBrushVert, kBrushRoot } BRUSH_SELECTION_TYPE; // Begin a brush stroke. void SHAVEsculpt_setup( BRUSH_MODE mode, // BRUSH_SELECTION_TYPE type, VERT eye_point, VERT view_dir, VERT view_up, VERT mouse_down_screen, VERT mouse_down_world ) { int x, y; VERT perp; int totalhit = 0; perp.x = 0.0f; perp.y = 0.0f; perp.z = 0.0f; for( x = 0; x < 15; x++ ) avg_hair[x] = perp; Gbeen_scaled = 0; for( x = 0; x < totalverts; x++ ) { for( y = 0; y < 15; y++ ) { if( hair[x].select[y] == 1 ) hair[x].select[0] = 1; } } for( x = 0; x < total_splines; x++ ) { for( y = 0; y < 15; y++ ) { if( Shair[x].select[y] == 1 ) Shair[x].select[0] = 1; } } for( x = 0; x < totalverts; x++ ) //if (hair[0].select[0]) { float w = 0.0f; for( y = 0; y < 15; y++ ) if( w < hair[x].w[y] ) w = hair[x].w[y]; hair[x].w[0] = w; } for( x = 0; x < total_splines; x++ ) //if (hair[0].select[0]) { float w = 0.0f; for( y = 0; y < 15; y++ ) if( w < Shair[x].w[y] ) w = Shair[x].w[y]; Shair[x].w[0] = w; } for( x = 0; x < totalverts; x++ ) { if( hair[x].w[0] > 0.0f ) // if (hair[x].select[0]) { for( y = 0; y < 15; y++ ) { avg_hair[y].x += hair[x].hv[y].x; avg_hair[y].y += hair[x].hv[y].y; avg_hair[y].z += hair[x].hv[y].z; // printf ("%f %f %f ",hair[x].hv[y].x,hair[x].hv[y].y,hair[x].hv[y].z); } totalhit++; } } for( x = 0; x < total_splines; x++ ) { if( Shair[x].w[0] > 0.0f ) // if (hair[x].select[0]) { for( y = 0; y < 15; y++ ) { avg_hair[y].x += Shair[x].hv[y].x; avg_hair[y].y += Shair[x].hv[y].y; avg_hair[y].z += Shair[x].hv[y].z; // printf ("%f %f %f ",hair[x].hv[y].x,hair[x].hv[y].y,hair[x].hv[y].z); } totalhit++; } } if( totalhit > 0 ) { for( y = 0; y < 15; y++ ) { avg_hair[y].x /= ( float ) totalhit; avg_hair[y].y /= ( float ) totalhit; avg_hair[y].z /= ( float ) totalhit; // printf ("%f %f %f ",avg_hair[y].x,avg_hair[y].y,avg_hair[y].z); } //printf ("\n"); } mouse_down_screen.z *= -1.0f; mouse_down_world.z *= -1.0f; eye_point.z *= -1.0f; view_dir.z *= -1.0f; sbrush = mode; Gmouse_down_world = mouse_down_world; brushCamPos = eye_point; perp = Vcross( view_dir, view_up ); view_up = Vcross( view_dir, perp ); mkmatrix( camOrient, perp, view_up, view_dir, brushCamPos ); inverse( camOrient, icamOrient ); // printf( // "starting stroke, mode %d, screen (%f, %f), world (%f, %f, %f)\n", // mode, mouse_down_screen.x, mouse_down_screen.y, // mouse_down_world.x, mouse_down_world.y, mouse_down_world.z // ); // printf( // "cam pos (%f, %f, %f), viewing dir (%f, %f, %f)\n", // eye_point.x, eye_point.y, eye_point.z, // view_dir.x, view_dir.y, view_dir.z // ); //printf ("called setup\n"); // reset_rest(); // add_undo( ); // will need to address this for( x = 0; x < totalverts; x++ ) /* back up the verts */ { int y; hair[x].sparerestlength = hair[x].restlength; for( y = 0; y < 15; y++ ) { hair[x].sparehv[y] = hair[x].hv[y]; } } for( x = 0; x < total_splines; x++ ) /* back up the verts */ { int y; Shair[x].sparerestlength = Shair[x].restlength; for( y = 0; y < 15; y++ ) { Shair[x].sparehv[y] = Shair[x].hv[y]; } } if( DOCOLLIDE ) if( COLLISION_METHOD == 1 ) { Dcalc_plane_eq( ); // norm is a unit vector setup_poly_vox( ); resize_poly_vox = 0; } if( DOCOLLIDE ) if( COLLISION_METHOD == 0 ) find_skulls( ); Gbeen_scaled = 0; //printf ("sbrush = %d\n",sbrush); lastmouseworld = mouse_down_world; lastmousescreen = mouse_down_screen; add_undo( ); fflush( stdout ); } // Update a stroke in-progress. void SHAVEsculpt_iterate( VERT mouse_drag_screen, VERT mouse_drag_world, VERT mouse_drag_relative_screen, VERT mouse_drag_relative_world ) { int x, y; VERT mm, mms; float slider; mouse_drag_screen.z *= -1.0f; mouse_drag_relative_screen.z *= -1.0f; mouse_drag_relative_world.z *= -1.0f; mouse_drag_world.z *= -1.0f; slider = mouse_drag_screen.x - 0.5f; //printf ("mouse_drag_world %f %f %f\n", //mouse_drag_world.x, //mouse_drag_world.y, //mouse_drag_world.z); Gsculpt_cursors = 1; mm.x = mouse_drag_world.x - lastmouseworld.x; mm.y = mouse_drag_world.y - lastmouseworld.y; mm.z = mouse_drag_world.z - lastmouseworld.z; mms.x = mouse_drag_screen.x - lastmousescreen.x; mms.y = mouse_drag_screen.y - lastmousescreen.y; mms.z = mouse_drag_screen.z - lastmousescreen.z; // here's what we do for translate // for guides if( sbrush == kBrushTranslate ) { for( x = 0; x < totalverts; x++ ) { int doit = 0; // if (hair[x].w[0]>0.0f) // if (x==0) printf ("%f\n",hair[x].sparehv[14].x); if( hair[x].select[0] > 0 ) for( y = 1; y < 15; y++ ) if( hair[x].select[y] > 0 ) if( hair[x].w[y] > 0.0f ) { hair[x].hv[y].x = hair[x].hv[y].x + mm.x * hair[x].w[y]; //<- that's the weight hair[x].hv[y].y = hair[x].hv[y].y + mm.y * hair[x].w[y]; hair[x].hv[y].z = hair[x].hv[y].z + mm.z * hair[x].w[y]; doit = 1; } Gcollision_hit = 0; if( doit ) recalc_hair( x ); } for( x = 0; x < total_splines; x++ ) { int doit = 0; // if (hair[x].w[0]>0.0f) // printf ("Shair[%d].select = %f\n",x,Shair[x].select[0]); // if (x==0) printf ("%f\n",hair[x].sparehv[14].x); if( Shair[x].select[0] > 0 ) for( y = 1; y < 15; y++ ) if( Shair[x].select[y] > 0 ) if( Shair[x].w[y] > 0.0f ) { // printf ("Shair[%d].select[%d] = %f",x,y,Shair[x].select[y]); // printf ("Shair[%d].w[%d] = %f\n",x,y,Shair[x].w[y]); Shair[x].hv[y].x = Shair[x].hv[y].x + mm.x * Shair[x].w[y]; //<- that's the weight Shair[x].hv[y].y = Shair[x].hv[y].y + mm.y * Shair[x].w[y]; Shair[x].hv[y].z = Shair[x].hv[y].z + mm.z * Shair[x].w[y]; doit = 1; } Gcollision_hit = 0; //if (doit) // Srecalc_hair( x ); } } if( sbrush == kBrushScale ) { Gbeen_scaled = 1; for( x = 0; x < total_splines; x++ ) { float sl; float w = 0.0f; for( y = 1; y < 15; y++ ) { if( w < Shair[x].w[y] ) w = Shair[x].w[y]; } Shair[x].w[0] = w; Gbeen_scaled = 1; sl = mouse_drag_relative_screen.x * 3.5 + 1.0f; if( sl < 0 ) sl = 0; // if (slider<0.0f) slider=0.0f; // if (hair[x].w[0]>0.0f) // if (x==0) printf ("%f\n",hair[x].sparehv[14].x); if( Shair[x].select[0] > 0 ) for( y = 1; y < 15; y++ ) if( Shair[x].select[0] > 0 ) // we always do the whole strand with scale., if( Shair[x].w[0] > 0.0f ) { float ww, iww; ww = Shair[x].w[0]; iww = 1.0f - ww; Shair[x].hv[y].x = ( ( ( Shair[x].sparehv[y].x - Shair[x].sparehv[0].x ) * sl + Shair[x].sparehv[0].x ) * ww + Shair[x].sparehv[y].x * iww ); //<- that's the weight Shair[x].hv[y].y = ( ( ( Shair[x].sparehv[y].y - Shair[x].sparehv[0].y ) * sl + Shair[x].sparehv[0].y ) * ww + Shair[x].sparehv[y].y * iww ); //<- that's the weight Shair[x].hv[y].z = ( ( ( Shair[x].sparehv[y].z - Shair[x].sparehv[0].z ) * sl + Shair[x].sparehv[0].z ) * ww + Shair[x].sparehv[y].z * iww ); //<- that's the weight Shair[x].lasthv[y] = Shair[x].hv[y]; Shair[x].restlength = Shair[x].sparerestlength * sl * ww + Shair[x].sparerestlength * iww; Shair[x].restlength = Shair[x].sparerestlength * sl * ww + Shair[x].sparerestlength * iww; Shair[x].restlength = Shair[x].sparerestlength * sl * ww + Shair[x].sparerestlength * iww; Gbeen_scaled = 1; } Gcollision_hit = 0; } for( x = 0; x < totalverts; x++ ) { float sl; float w = 0.0f; for( y = 1; y < 15; y++ ) { if( w < hair[x].w[y] ) w = hair[x].w[y]; } hair[x].w[0] = w; sl = mouse_drag_relative_screen.x * 3.5 + 1.0f; if( sl < 0 ) sl = 0; // if (slider<0.0f) slider=0.0f; // if (hair[x].w[0]>0.0f) // if (x==0) printf ("%f\n",hair[x].sparehv[14].x); if( hair[x].restlength < 0.000001f ) { int xx; for( xx = 1; xx < 15; xx++ ) { hair[x].hv[xx] = hair[x].hv[0]; hair[x].resthv[xx] = hair[x].resthv[0]; hair[x].noisev[xx] = hair[x].noisev[0]; } } if( hair[x].restlength > 0.0f ) if( hair[x].select[0] > 0 ) for( y = 1; y < 15; y++ ) if( hair[x].select[0] > 0 ) // we always do the whole strand with scale., if( hair[x].w[0] > 0.0f ) { float ww, iww; ww = hair[x].w[0]; iww = 1.0f - ww; hair[x].hv[y].x = ( ( ( hair[x].sparehv[y].x - hair[x].sparehv[0].x ) * sl + hair[x].sparehv[0].x ) * ww + hair[x].sparehv[y].x * iww ); //<- that's the weight hair[x].hv[y].y = ( ( ( hair[x].sparehv[y].y - hair[x].sparehv[0].y ) * sl + hair[x].sparehv[0].y ) * ww + hair[x].sparehv[y].y * iww ); //<- that's the weight hair[x].hv[y].z = ( ( ( hair[x].sparehv[y].z - hair[x].sparehv[0].z ) * sl + hair[x].sparehv[0].z ) * ww + hair[x].sparehv[y].z * iww ); //<- that's the weight hair[x].lasthv[y] = hair[x].hv[y]; hair[x].restlength = hair[x].sparerestlength * sl * ww + hair[x].sparerestlength * iww; hair[x].restlength = hair[x].sparerestlength * sl * ww + hair[x].sparerestlength * iww; hair[x].restlength = hair[x].sparerestlength * sl * ww + hair[x].sparerestlength * iww; Gbeen_scaled = 1; } Gcollision_hit = 0; } } if( sbrush == kBrushRotate ) { for( x = 0; x < totalverts; x++ ) { int doit = 0; float sl; if( slider < 0.0f ) slider = 0.0f; // if (hair[x].w[0]>0.0f) // if (x==0) printf ("%f\n",hair[x].sparehv[14].x); if( hair[x].select[0] > 0 ) for( y = 1; y < 15; y++ ) if( hair[x].select[0] > 0 ) // we always do the whole strand with scale., if( hair[x].w[y] > 0.0f ) { VERT pp; float thetaz; VERT xv, yv, zv; Matrix rot; VERT qq; qq.x = 0.0f; qq.y = 0.0f; qq.z = 0.0f; pp = hair[x].sparehv[y]; pp.x -= Gmouse_down_world.x; pp.y -= Gmouse_down_world.y; pp.z -= Gmouse_down_world.z; pp = vxm( icamOrient, pp ); thetaz = hair[x].w[y] * mouse_drag_relative_screen.x * 6.283f * 3.0f; // thetaz=mouse_drag_relative_screen.x*6.283f*3.0f; // printf ("thetaz = %f\n",thetaz); xv.x = cos( thetaz ); xv.y = sin( thetaz ); xv.z = 0.0f; yv.x = cos( thetaz + 3.141 / 2.0f ); yv.y = sin( thetaz + 3.141 / 2.0f ); yv.z = 0.0f; zv.x = 0.0f; zv.y = 0.0f; zv.z = 1.0f; mkmatrix( rot, xv, yv, zv, qq ); //do the rotation pp = vxm( rot, pp ); pp = vxm( camOrient, pp ); pp.x += Gmouse_down_world.x; pp.y += Gmouse_down_world.y; pp.z += Gmouse_down_world.z; hair[x].hv[y] = pp; doit = 1; } if( doit ) recalc_hair( x ); Gcollision_hit = 0; } for( x = 0; x < total_splines; x++ ) { int doit = 0; float sl; if( slider < 0.0f ) slider = 0.0f; // if (hair[x].w[0]>0.0f) // if (x==0) printf ("%f\n",hair[x].sparehv[14].x); if( Shair[x].select[0] > 0 ) for( y = 1; y < 15; y++ ) if( Shair[x].select[0] > 0 ) // we always do the whole strand with scale., // if (hair[x].w[y]>0.0f) { VERT pp; float thetaz; VERT xv, yv, zv; Matrix rot; VERT qq; qq.x = 0.0f; qq.y = 0.0f; qq.z = 0.0f; pp = Shair[x].sparehv[y]; pp.x -= Gmouse_down_world.x; pp.y -= Gmouse_down_world.y; pp.z -= Gmouse_down_world.z; pp = vxm( icamOrient, pp ); thetaz = Shair[x].w[y] * mouse_drag_relative_screen.x * 6.283f * 3.0f; // thetaz=mouse_drag_relative_screen.x*6.283f*3.0f; // printf ("thetaz = %f\n",thetaz); xv.x = cos( thetaz ); xv.y = sin( thetaz ); xv.z = 0.0f; yv.x = cos( thetaz + 3.141 / 2.0f ); yv.y = sin( thetaz + 3.141 / 2.0f ); yv.z = 0.0f; zv.x = 0.0f; zv.y = 0.0f; zv.z = 1.0f; mkmatrix( rot, xv, yv, zv, qq ); //do the rotation pp = vxm( rot, pp ); pp = vxm( camOrient, pp ); pp.x += Gmouse_down_world.x; pp.y += Gmouse_down_world.y; pp.z += Gmouse_down_world.z; Shair[x].hv[y] = pp; doit = 1; } // if (doit) // Srecalc_hair( x ); Gcollision_hit = 0; } } if( sbrush == kBrushStand ) { for( x = 0; x < totalverts; x++ ) { int doit = 0; float slider = 0.0f; float w = 0.0f; for( y = 1; y < 15; y++ ) { if( w < hair[x].w[y] ) w = hair[x].w[y]; } hair[x].w[0] = w; // if (hair[x].w[0]>0.0f) // if (x==0) printf ("%f\n",hair[x].sparehv[14].x); if( hair[x].select[0] > 0 ) { VERT vnn[15]; for( y = 1; y < 15; y++ ) // this is the hair spread way out on the normal { vnn[y].x = hair[x].hv[0].x + vn[x].x * hair[x].restlength * 5.0f * ( float ) y; vnn[y].y = hair[x].hv[0].y + vn[x].y * hair[x].restlength * 5.0f * ( float ) y; vnn[y].z = hair[x].hv[0].z + vn[x].z * hair[x].restlength * 5.0f * ( float ) y; } for( y = 1; y < 15; y++ ) if( hair[x].select[y] > 0 ) if( hair[x].w[0] > 0.0f ) { float ww, iww, n; ww = hair[x].w[0]; // always want the whole strand to have the same weight n = 1.0 - ( y / 15.0f ); // n*=n; iww = 1.0f - ww; slider = mouse_drag_relative_screen.x; slider *= ( float ) n / 1.0f; slider *= 6.0f; slider *= ww; if( slider > .9f ) slider = .9f; if( slider < 0.0f ) slider = 0.0f; hair[x].hv[y].x = hair[x].sparehv[y].x * ( 1.0 - slider ) + vnn[y].x * slider; //<- that's the weight hair[x].hv[y].y = hair[x].sparehv[y].y * ( 1.0 - slider ) + vnn[y].y * slider; hair[x].hv[y].z = hair[x].sparehv[y].z * ( 1.0 - slider ) + vnn[y].z * slider; doit = 1; } Gcollision_hit = 0; if( doit ) recalc_hair( x ); } } for( x = 0; x < total_splines; x++ ) { int doit = 0; float slider = 0.0f; float w = 0.0f; for( y = 1; y < 15; y++ ) { if( w < Shair[x].w[y] ) w = Shair[x].w[y]; } Shair[x].w[0] = w; // if (hair[x].w[0]>0.0f) // if (x==0) printf ("%f\n",hair[x].sparehv[14].x); if( Shair[x].select[0] > 0 ) { VERT vnn[15]; for( y = 1; y < 15; y++ ) // this is the hair spread way out on the normal { vnn[y].x = Shair[x].hv[0].x + Shair[x].norm.x * Shair[x].restlength * 5.0f * ( float ) y; vnn[y].y = Shair[x].hv[0].y + Shair[x].norm.y * Shair[x].restlength * 5.0f * ( float ) y; vnn[y].z = Shair[x].hv[0].z + Shair[x].norm.z * Shair[x].restlength * 5.0f * ( float ) y; } for( y = 1; y < 15; y++ ) if( Shair[x].select[y] > 0 ) if( Shair[x].w[0] > 0.0f ) { float ww, iww, n; ww = Shair[x].w[0]; // always want the whole strand to have the same weight n = 1.0 - ( y / 15.0f ); // n*=n; iww = 1.0f - ww; slider = mouse_drag_relative_screen.x; slider *= ( float ) n / 1.0f; slider *= 6.0f; slider *= ww; if( slider > .9f ) slider = .9f; if( slider < 0.0f ) slider = 0.0f; Shair[x].hv[y].x = Shair[x].sparehv[y].x * ( 1.0 - slider ) + vnn[y].x * slider; //<- that's the weight Shair[x].hv[y].y = Shair[x].sparehv[y].y * ( 1.0 - slider ) + vnn[y].y * slider; Shair[x].hv[y].z = Shair[x].sparehv[y].z * ( 1.0 - slider ) + vnn[y].z * slider; doit = 1; } Gcollision_hit = 0; //if (doit) // Srecalc_hair( x ); } } } if( sbrush == kBrushPuff ) { for( x = 0; x < totalverts; x++ ) { int doit = 0; float slider = 0.0f; float w = 0.0f; for( y = 1; y < 15; y++ ) { if( w < hair[x].w[y] ) w = hair[x].w[y]; } hair[x].w[0] = w; // if (hair[x].w[0]>0.0f) // if (x==0) printf ("%f\n",hair[x].sparehv[14].x); if( hair[x].select[0] > 0 ) { VERT vnn[15]; for( y = 1; y < 15; y++ ) // this is the hair spread way out on the normal { vnn[y].x = hair[x].hv[0].x + vn[x].x * hair[x].restlength * 5.0f * ( float ) y; vnn[y].y = hair[x].hv[0].y + vn[x].y * hair[x].restlength * 5.0f * ( float ) y; vnn[y].z = hair[x].hv[0].z + vn[x].z * hair[x].restlength * 5.0f * ( float ) y; } for( y = 1; y < 15; y++ ) if( hair[x].select[y] > 0 ) if( hair[x].w[0] > 0.0f ) { float ww, iww, n; ww = hair[x].w[0]; // always want the whole strand to have the same weight n = 1.0 - ( y / 15.0f ); n = pow( n, 2.2 ); iww = 1.0f - ww; slider = mouse_drag_relative_screen.x; slider *= ( float ) n / 1.0f; slider *= 6.0f; slider *= ww; if( slider > 0.9f ) slider = 0.9f; if( slider < 0.0f ) slider = 0.0f; // slider*=slider; hair[x].hv[y].x = hair[x].sparehv[y].x * ( 1.0 - slider ) + vnn[y].x * slider; //<- that's the weight hair[x].hv[y].y = hair[x].sparehv[y].y * ( 1.0 - slider ) + vnn[y].y * slider; hair[x].hv[y].z = hair[x].sparehv[y].z * ( 1.0 - slider ) + vnn[y].z * slider; doit = 1; } Gcollision_hit = 0; if( doit ) recalc_hair( x ); } } for( x = 0; x < total_splines; x++ ) { int doit = 0; float slider = 0.0f; float w = 0.0f; for( y = 1; y < 15; y++ ) { if( w < Shair[x].w[y] ) w = Shair[x].w[y]; } Shair[x].w[0] = w; // if (hair[x].w[0]>0.0f) // if (x==0) printf ("%f\n",hair[x].sparehv[14].x); if( Shair[x].select[0] > 0 ) { VERT vnn[15]; for( y = 1; y < 15; y++ ) // this is the hair spread way out on the normal { vnn[y].x = Shair[x].hv[0].x + Shair[x].norm.x * Shair[x].restlength * 5.0f * ( float ) y; vnn[y].y = Shair[x].hv[0].y + Shair[x].norm.y * Shair[x].restlength * 5.0f * ( float ) y; vnn[y].z = Shair[x].hv[0].z + Shair[x].norm.z * Shair[x].restlength * 5.0f * ( float ) y; } for( y = 1; y < 15; y++ ) if( Shair[x].select[y] > 0 ) if( Shair[x].w[0] > 0.0f ) { float ww, iww, n; ww = Shair[x].w[0]; // always want the whole strand to have the same weight n = 1.0 - ( y / 15.0f ); n = pow( n, 2.2 ); iww = 1.0f - ww; slider = mouse_drag_relative_screen.x; slider *= ( float ) n / 1.0f; slider *= 6.0f; slider *= ww; if( slider > 0.9f ) slider = 0.9f; if( slider < 0.0f ) slider = 0.0f; // slider*=slider; Shair[x].hv[y].x = Shair[x].sparehv[y].x * ( 1.0 - slider ) + vnn[y].x * slider; //<- that's the weight Shair[x].hv[y].y = Shair[x].sparehv[y].y * ( 1.0 - slider ) + vnn[y].y * slider; Shair[x].hv[y].z = Shair[x].sparehv[y].z * ( 1.0 - slider ) + vnn[y].z * slider; doit = 1; } Gcollision_hit = 0; //if (doit) // Srecalc_hair( x ); } } } if( sbrush == kBrushClump ) { for( x = 0; x < totalverts; x++ ) { int doit = 0; float slider = 0.0f; float w = 0.0f; for( y = 1; y < 15; y++ ) { if( w < hair[x].w[y] ) w = hair[x].w[y]; } hair[x].w[0] = w; //if (hair[x].w[0]>0.0f) printf ("w = %f\n",hair[x].w[0]); if( hair[x].w[0] > 0.0f ) // if (x==0) printf ("%f\n",hair[x].sparehv[14].x); if( hair[x].select[0] > 0 ) { VERT vnn[15]; for( y = 0; y < 15; y++ ) // this is the hair spread way out on the normal { vnn[y] = avg_hair[y]; } hair[x].trim = 1.0f; for( y = 1; y < 15; y++ ) if( hair[x].select[y] > 0 ) if( hair[x].w[0] > 0.0f ) { float ww, iww, n; ww = hair[x].w[0]; // always want the whole strand to have the same weight n = 1.0f; iww = 1.0f - ww; slider = mouse_drag_relative_screen.x; slider *= 4.5f; slider *= ww; if( slider > 0.9f ) slider = 0.9f; if( slider < 0.0f ) slider = 0.0f; // slider*=slider; hair[x].hv[y].x = hair[x].sparehv[y].x * ( 1.0 - slider ) + vnn[y].x * slider; //<- that's the weight hair[x].hv[y].y = hair[x].sparehv[y].y * ( 1.0 - slider ) + vnn[y].y * slider; hair[x].hv[y].z = hair[x].sparehv[y].z * ( 1.0 - slider ) + vnn[y].z * slider; doit = 1; } Gcollision_hit = 0; if( doit ) recalc_hair( x ); } } for( x = 0; x < total_splines; x++ ) { int doit = 0; float slider = 0.0f; float w = 0.0f; for( y = 1; y < 15; y++ ) { if( w < Shair[x].w[y] ) w = Shair[x].w[y]; } Shair[x].w[0] = w; //if (hair[x].w[0]>0.0f) printf ("w = %f\n",hair[x].w[0]); if( Shair[x].w[0] > 0.0f ) // if (x==0) printf ("%f\n",hair[x].sparehv[14].x); if( Shair[x].select[0] > 0 ) { VERT vnn[15]; for( y = 0; y < 15; y++ ) // this is the hair spread way out on the normal { vnn[y] = avg_hair[y]; } Shair[x].trim = 1.0f; for( y = 1; y < 15; y++ ) if( Shair[x].select[y] > 0 ) if( Shair[x].w[0] > 0.0f ) { float ww, iww, n; ww = Shair[x].w[0]; // always want the whole strand to have the same weight n = 1.0f; iww = 1.0f - ww; slider = mouse_drag_relative_screen.x; slider *= 4.5f; slider *= ww; if( slider > 0.9f ) slider = 0.9f; if( slider < 0.0f ) slider = 0.0f; // slider*=slider; Shair[x].hv[y].x = Shair[x].sparehv[y].x * ( 1.0 - slider ) + vnn[y].x * slider; //<- that's the weight Shair[x].hv[y].y = Shair[x].sparehv[y].y * ( 1.0 - slider ) + vnn[y].y * slider; Shair[x].hv[y].z = Shair[x].sparehv[y].z * ( 1.0 - slider ) + vnn[y].z * slider; doit = 1; } Gcollision_hit = 0; //if (doit) // Srecalc_hair( x ); } } } // printf( // "stroke extends to: screen (%f, %f), world (%f, %f, %f)\n", // mouse_drag_screen.x, mouse_drag_screen.y, // mouse_drag_world.x, mouse_drag_world.y, mouse_drag_world.z // ); // printf( // "total change: screen (%f, %f), world (%f, %f, %f)\n", // mouse_drag_relative_screen.x, mouse_drag_relative_screen.y, // mouse_drag_relative_world.x, mouse_drag_relative_world.y, mouse_drag_relative_world.z // ); lastmouseworld = mouse_drag_world; lastmousescreen = mouse_drag_screen; Gsculpt_cursors = 0; for( x = 0; x < totalverts; x++ ) if( hair[x].restlength < 0.0001f ) { int y; VERT qq; hair[x].restlength = 0.0f; qq = v[x]; #ifdef MAX3D //qq.z*= -1.0f; #endif for( y = 0; y < 15; y++ ) hair[x].hv[y] = qq; } fflush( stdout ); } // Complete a stroke. void SHAVEsculpt_finish( ) { int x; for( x = 0; x < totalverts; x++ ) hair[x].sparerestlength = hair[x].restlength; for( x = 0; x < total_splines; x++ ) Shair[x].sparerestlength = Shair[x].restlength; for( x = 0; x < total_splines; x++ ) Sresthair[x].sparerestlength = Shair[x].restlength; make_normals( ); reset_rest( ); reset_noisespace( ); mkbounds( ); if( Gbeen_scaled ) { Smake_restlengths( ); } // printf("stroke finished\n"); // fflush(stdout); } static void cut_hairNOTAG( void ) { int x; int y; float *sel = NULL; if( totalverts > 0 ) { sel = ( float * ) malloc( totalverts * sizeof( float ) * 15 + 4 ); for( x = 0; x < totalverts; x++ ) for( y = 0; y < 15; y++ ) { sel[x * 15 + y] = hair[x].select[y]; if( y > 0 ) hair[x].select[y] = 1; } // brushtagverts( ); for( x = 0; x < totalverts; x++ ) if( hair[x].restlength > .0001f ) { int smallest = 0; for( y = 15; y > 0; y-- ) { float m = 0.0f; m = hair[x].select[y]; if( brush_stat ) m = hair[x].w[y]; if( m > 0.0f ) smallest = y; } // smallest=14; // smallest--; //// if( ( smallest > 0 ) && ( smallest < 14 ) ) // cut it here if( hair[x].select[0] ) if( smallest > 0 ) { BASEHAIR tp; float uu, tt; tp = hair[x]; for( y = 1; y < 15; y++ ) { VERT v1, v2, v3; float rem; tt = smallest / 15.0f; uu = tt * ( float ) y; v1 = hair[x].hv[( int ) floor( uu )]; v2 = hair[x].hv[( int ) floor( uu + 1 )]; rem = uu - floor( uu ); v3.x = v1.x * ( 1.0f - rem ) + v2.x * rem; v3.y = v1.y * ( 1.0f - rem ) + v2.y * rem; v3.z = v1.z * ( 1.0f - rem ) + v2.z * rem; tp.hv[y] = v3; // if( brush_stat == 0 ) // tp.select[y] = 0; } hair[x] = tp; hair[x].restlength = distance( tp.hv[0], tp.hv[1] ); if( hair[x].restlength < .0001f ) { int q; hair[x].restlength = 0.0f; hair[x].sparerestlength = 0.0f; for( q = 1; q < 15; q++ ) hair[x].hv[q] = hair[x].hv[0]; } recalc_hair( x ); } // if( ( smallest > 0 )) // && ( smallest < 14 ) ) // cut it here // { // hair[x].select[14] = 1; // hair[x].select[0] = 1; // } memcpy( &hair[x].resthv, &hair[x].hv, sizeof( VERT ) * 15 ); memcpy( &hair[x].lasthv, &hair[x].hv, sizeof( VERT ) * 15 ); //memcpy(&thishair[x],&hair[x],sizeof(BASEHAIR)); //memcpy(&lasthair[x],&hair[x],sizeof(BASEHAIR)); } for( x = 0; x < totalverts; x++ ) for( y = 0; y < 15; y++ ) hair[x].select[y] = sel[x * 15 + y]; if( sel ) free( sel ); } if( total_splines > 0 ) { sel = ( float * ) malloc( total_splines * sizeof( float ) * 15 + 4 ); for( x = 0; x < total_splines; x++ ) for( y = 0; y < 15; y++ ) { sel[x * 15 + y] = Shair[x].select[y]; if( y > 0 ) Shair[x].select[y] = 1; } // brushtagverts( ); for( x = 0; x < total_splines; x++ ) { int smallest = 0; for( y = 15; y > 0; y-- ) { float m = 0.0f; m = Shair[x].select[y]; if( brush_stat ) m = Shair[x].w[y]; if( m > 0.0f ) smallest = y; } // smallest=14; // smallest--; //// if( ( smallest > 0 ) && ( smallest < 14 ) ) // cut it here if( Shair[x].select[0] ) if( smallest > 0 ) { BASEHAIR tp; float uu, tt; tp = Shair[x]; for( y = 1; y < 15; y++ ) { VERT v1, v2, v3; float rem; tt = smallest / 15.0f; uu = tt * ( float ) y; v1 = Shair[x].hv[( int ) floor( uu )]; v2 = Shair[x].hv[( int ) floor( uu + 1 )]; rem = uu - floor( uu ); v3.x = v1.x * ( 1.0f - rem ) + v2.x * rem; v3.y = v1.y * ( 1.0f - rem ) + v2.y * rem; v3.z = v1.z * ( 1.0f - rem ) + v2.z * rem; tp.hv[y] = v3; // if( brush_stat == 0 ) // tp.select[y] = 0; } Shair[x] = tp; Shair[x].restlength = distance( tp.hv[0], tp.hv[1] ); Srecalc_hair( x ); } // if( ( smallest > 0 )) // && ( smallest < 14 ) ) // cut it here // { // Shair[x].select[14] = 1; // Shair[x].select[0] = 1; // } memcpy( &Sresthair[x].hv, &Shair[x].hv, sizeof( VERT ) * 15 ); memcpy( &Shair[x].lasthv, &Shair[x].hv, sizeof( VERT ) * 15 ); memcpy( &Sresthair[x].lasthv, &Shair[x].hv, sizeof( VERT ) * 15 ); //memcpy(&thisShair[x],&Shair[x],sizeof(BASEHAIR)); //memcpy(&lastShair[x],&Shair[x],sizeof(BASEHAIR)); } for( x = 0; x < total_splines; x++ ) for( y = 0; y < 15; y++ ) Shair[x].select[y] = sel[x * 15 + y]; if( sel ) free( sel ); } reset_noisespace( ); // tagverts( ); // brushtagverts( ); //++U add_undo( ); testvar = 0; } void SHAVEcut( VERT eye_point, VERT view_dir, VERT mouse_down_screen, VERT mouse_down_world ) { int x; add_undo( ); set_trim( ); cut_hairNOTAG( ); Gbeen_scaled = 1; for( x = 0; x < totalverts; x++ ) hair[x].sparerestlength = hair[x].restlength; for( x = 0; x < total_splines; x++ ) Shair[x].sparerestlength = Shair[x].restlength; make_normals( ); reset_rest( ); reset_noisespace( ); // reset_rest( ); mkbounds( ); // printf( // "cut at screen (%f, %f), world (%f, %f, %f)\n", // mouse_down_screen.x, mouse_down_screen.y, // mouse_down_world.x, mouse_down_world.y, mouse_down_world.z // ); // printf( // "cam pos (%f, %f, %f), viewing dir (%f, %f, %f)\n", // eye_point.x, eye_point.y, eye_point.z, // view_dir.x, view_dir.y, view_dir.z // ); // fflush(stdout); } static void atten_len( void ); void SHAVEattenuate( ) { printf( "attenuate\n" ); atten_len( ); fflush( stdout ); } void SHAVEpop_selected( ) { add_undo( ); SOFTpop_select( 1.0f ); printf( "pop selected\n" ); fflush( stdout ); } void SHAVEpop_zero_sized( ) { add_undo( ); SOFTpop_zero( ); printf( "pop zero-sized\n" ); fflush( stdout ); } static void M_toggle_collision( void ); void SHAVEtoggle_collision( ) { M_toggle_collision( ); printf( "toggle collision\n" ); fflush( stdout ); } void SHAVElock( ) { SOFTlock_select( ); printf( "lock\n" ); fflush( stdout ); } void SHAVEunlock( ) { SOFTunlock_select( ); printf( "unlock\n" ); fflush( stdout ); } void SHAVEundo( ) { undo_op( ); // printf( "undo\n" ); fflush( stdout ); } void SHAVErecomb( void ) { add_undo( ); recomb_select( ); printf( "recomb\n" ); fflush( stdout ); } void SHAVEreplace_rest_interactive( void ) { printf( "replace_rest_interactive\n" ); fflush( stdout ); } void SHAVEselect_grow( void ) { BASEHAIR *temp = NULL; int x, y; add_undo( ); if( totalverts > 0 ) { temp = ( BASEHAIR * ) malloc( totalverts * sizeof( BASEHAIR ) ); for( x = 0; x < totalverts; x++ ) memcpy( &temp[x], &hair[x], sizeof( BASEHAIR ) ); } if( total_splines > 0 ) { temp = ( BASEHAIR * ) malloc( total_splines * sizeof( BASEHAIR ) ); for( x = 0; x < total_splines; x++ ) memcpy( &temp[x], &Shair[x], sizeof( BASEHAIR ) ); } if( totalverts > 0 ) { for( x = 0; x < totalfaces; x++ ) { int g; BASEHAIR tmp; for( y = 0; y < 15; y++ ) tmp.select[y] = 0; for( y = face_start[x]; y < face_end[x]; y++ ) { int t; g = facelist[y]; for( t = 0; t < 15; t++ ) { tmp.select[t] += hair[g].select[t]; if( tmp.select[t] > 1 ) tmp.select[t] = 1; } } for( y = face_start[x]; y < face_end[x]; y++ ) { int t; g = facelist[y]; for( t = 0; t < 15; t++ ) { temp[g].select[t] += tmp.select[t]; if( temp[g].select[t] > 1 ) temp[g].select[t] = 1; } } } for( x = 0; x < totalverts; x++ ) for( y = 0; y < 15; y++ ) if( temp[x].select[y] >= 1 ) hair[x].select[y] = 1; } if( total_splines > 0 ) { for( x = 0; x < total_splines; x++ ) { int g; //for (y=face_start[x];y= 0 ) for( t = 0; t < 15; t++ ) { temp[g].select[t] += Shair[x].select[t]; } } //for (y=face_start[x];y= 1 ) Shair[x].select[y] = 1; } printf( "select_grow\n" ); fflush( stdout ); if( temp ) free( temp ); } void SHAVEselect_inverse( void ) { int x, y; add_undo( ); for( x = 0; x < totalverts; x++ ) { int flip = 0; for( y = 1; y < 15; y++ ) { flip = hair[x].select[y]; if( flip == 0 ) hair[x].select[y] = 1; if( flip == 1 ) hair[x].select[y] = 0; } flip = 0; if (hair[x].select[0]==0) for( y = 1; y < 15; y++ ) flip+=hair[x].select[y]; if (flip>0) hair[x].select[0]=1; if (flip==0) hair[x].select[0]=0; } for( x = 0; x < total_splines; x++ ) { int flip = 0; for( y = 1; y < 15; y++ ) { flip = Shair[x].select[y]; if( flip == 0 ) Shair[x].select[y] = 1; if( flip == 1 ) Shair[x].select[y] = 0; } flip=0; if (Shair[x].select[0]==0) for( y = 1; y < 15; y++ ) flip+=Shair[x].select[y]; if (flip>0) Shair[x].select[0]=1; if (flip==0) Shair[x].select[0]=0; for( y = 0; y < 15; y++ ) Sresthair[x].select[y] = Shair[x].select[y]; for( y = 0; y < 15; y++ ) Sthishair[x].select[y] = Shair[x].select[y]; } printf( "select_inverse\n" ); fflush( stdout ); } void SHAVEselect_rotate_up( void ) { int x, y; for( x = 0; x < totalverts; x++ ) { int q; q = hair[x].select[14]; for( y = 14; y > 1; y-- ) { hair[x].select[y] = hair[x].select[y - 1]; } hair[x].select[1] = q; } for( x = 0; x < total_splines; x++ ) { int q; q = Shair[x].select[14]; for( y = 14; y > 1; y-- ) { Shair[x].select[y] = Shair[x].select[y - 1]; } hair[x].select[1] = q; } printf( "select_rotate_up\n" ); fflush( stdout ); } void SHAVEselect_hide( void ) { int g; SOFTGUIDE guide; for( g = 0; SHAVEfetch_guide( g, &guide ) != -1; g++ ) { if( guide.select[0] ) { guide.hidden = 1; SHAVEput_guideNOCALC( g, &guide ); } } } void SHAVEselect_unhide( void ) { int g; SOFTGUIDE guide; for( g = 0; SHAVEfetch_guide( g, &guide ) != -1; g++ ) { if( guide.hidden ) { guide.hidden = 0; SHAVEput_guideNOCALC( g, &guide ); } } } void set_trim( void ) { int x, y; int nz = -1; float nzz = 0.0f; if( totalverts > 0 ) { for( x = 0; x < totalverts; x++ ) { for( y = 14; y >= 0; y-- ) { if( nz == -1 ) if( hair[x].w[y] == 0.0f ) nz = y; } if( ( nz > -1 ) && ( nz <= 13 ) && ( nz > 0 ) ) // a cut will occur { float delt = 0.0f; delt = hair[x].w[nz + 1] - hair[x].w[nz]; delt = hair[x].w[nz] / delt; // this is the remainder .. ? hair[x].trim = ( float ) nz + delt; // this is the trim value } for( x = 0; x < totalverts; x++ ) { if( hair[x].trim < 0 ) hair[x].trim = 1.0f; } } } if( total_splines > 0 ) { for( x = 0; x < total_splines; x++ ) { for( y = 14; y >= 0; y-- ) { if( nz == -1 ) if( Shair[x].w[y] == 0.0f ) nz = y; } if( ( nz > -1 ) && ( nz <= 13 ) && ( nz > 0 ) ) // a cut will occur { float delt = 0.0f; delt = Shair[x].w[nz + 1] - Shair[x].w[nz]; delt = Shair[x].w[nz] / delt; // this is the remainder .. ? Shair[x].trim = ( float ) nz + delt; // this is the trim value } //for (x=0;x