Advertisement
snake5

SVG line path -> concave poly -> trimesh sample code [sgs]

Jun 20th, 2014
390
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1.  
  2. function line_intersect( la0, la1, lb0, lb1 )
  3. {
  4.     s1_x = la1.x - la0.x;   s1_y = la1.y - la0.y;
  5.     s2_x = lb1.x - lb0.x;   s2_y = lb1.y - lb0.y;
  6.    
  7.     d = -s2_x * s1_y + s1_x * s2_y;
  8.     if( d == 0 )
  9.         return null;
  10.    
  11.     s = (-s1_y * (la0.x - lb0.x) + s1_x * (la0.y - lb0.y)) / d;
  12.     t = ( s2_x * (la0.y - lb0.y) - s2_y * (la0.x - lb0.x)) / d;
  13.    
  14.     if (s >= 0 && s <= 1 && t >= 0 && t <= 1)
  15.     {
  16.         // Collision detected
  17.         return vec2( la0.x + (t * s1_x), la0.y + (t * s1_y) );
  18.     }
  19.     return null;
  20. }
  21.  
  22. function point_inside_triangle( p, t0, t1, t2 )
  23. {
  24.     en0 = ( t1 - t0 ).perp.normalized;
  25.     en1 = ( t2 - t1 ).perp.normalized;
  26.     en2 = ( t0 - t2 ).perp.normalized;
  27.     ds0 = vec2_dot( en0, p ) > vec2_dot( en0, t0 );
  28.     ds1 = vec2_dot( en1, p ) > vec2_dot( en1, t1 );
  29.     ds2 = vec2_dot( en2, p ) > vec2_dot( en2, t2 );
  30.     return ds0 == ds1 && ds1 == ds2;
  31. }
  32.  
  33. function point_in_poly( poly, pt )
  34. {
  35.     c = false;
  36.     for( i = 0, j = poly.size - 1; i < poly.size; j = i++ )
  37.     {
  38.         if( ((poly[i].y>pt.y) != (poly[j].y>pt.y)) &&
  39.             (pt.x < (poly[j].x-poly[i].x) * (pt.y-poly[i].y) / (poly[j].y-poly[i].y) + poly[i].x) )
  40.             c = !c;
  41.     }
  42.     return c;
  43. }
  44.  
  45. /* algorithm:
  46. - generate intersection points and side-turning markers (one on each intersection point)
  47. - generate edge list (expanded from path with intersection points), swapping points if the side is supposed to be turned
  48. - generate concave polygons by finding sequences of edges (each edge can only be used once, edges cannot change direction)
  49. - fill concave polygons with any (in this case, ear clipping) algorithm
  50. */
  51. function render_line_path( path )
  52. {
  53.     // GENERATE PATH WITH INTERSECTION POINTS
  54.     npath = [];
  55.     turnside = [];
  56.     foreach( p : path )
  57.     {
  58.         pp = @npath.last;
  59.         npath.push( p );
  60.         turnside.push( false );
  61.        
  62.         from = 0;
  63.         chg = npath.size - 2;
  64.         to = npath.size - 1;
  65.        
  66.         for( i = from; i < chg; ++i )
  67.         {
  68.             i1 = i + 1;
  69.             for( j = chg; j < to; ++j )
  70.             {
  71.                 j1 = j + 1;
  72.                
  73.                 pi = npath[i];
  74.                 pi1 = npath[i1];
  75.                 pj = npath[j];
  76.                 pj1 = npath[j1];
  77.                
  78.                 isp = line_intersect( pj, pj1, pi, pi1 );
  79.                 if( isp && isp != pj && isp != pj1 && isp != pi && isp != pi1 )
  80.                 {
  81.                     npath.insert( i1, isp );
  82.                     turnside.insert( i1, true );
  83.                 //  j++;
  84.                     chg++;
  85.                     to++;
  86.                     npath.insert( j1 + 1, isp );
  87.                     turnside.insert( j1 + 1, true );
  88.                 //  j--;
  89.                     to++;
  90.                 }
  91.             }
  92.         }
  93.     }
  94. //  printvar(npath);WARNING("!");
  95.    
  96.     // GENERATE EDGE LIST
  97.     sides = [];
  98.     edgelist = [];
  99.     curside = false;
  100.     for( i = 0; i < npath.size; ++i )
  101.     {
  102.         if( turnside[ i ] )
  103.             curside = !curside;
  104.         sides.push( curside );
  105.        
  106.         i1 = ( i + 1 ) % npath.size;
  107.         if( !curside )
  108.         {
  109.             edgelist.push( npath[i] );
  110.             edgelist.push( npath[i1] );
  111.         }
  112.         else
  113.         {
  114.             edgelist.push( npath[i1] );
  115.             edgelist.push( npath[i] );
  116.         }
  117.     }
  118.    
  119.     // GENERATE POLYGONS FROM EDGE LIST
  120.     PolyList = [];
  121.     while( edgelist.size )
  122.     {
  123.         poly = [ edgelist[0], edgelist[1] ];
  124.         edgelist.shift();
  125.         edgelist.shift();
  126.        
  127.         while( poly[0] != poly.last )
  128.         {
  129.             for( i = 0; i < edgelist.size; i += 2 )
  130.             {
  131.                 if( edgelist[i] == poly.last )
  132.                 {
  133.                     poly.push( edgelist[ i + 1 ] );
  134.                     edgelist.erase( i, i + 1 );
  135.                     i -= 2;
  136.                 }
  137.             }
  138.         }
  139.        
  140.         PolyList.push( poly );
  141.     }
  142.    
  143.     // CONCAVE POLYGON TRIANGULATION
  144.     triangles = [];
  145.     foreach( poly : PolyList )
  146.     {
  147.         poly = clone( poly );
  148.         // while there are ears to clip
  149.         for( numiters = 0; poly.size > 2 && numiters < poly.size; ++numiters )
  150.         {
  151.             // for each bi-edge
  152.             for( i = 0; i < poly.size; ++i )
  153.             {
  154.                 i0 = i;
  155.                 i1 = ( i + 1 ) % poly.size;
  156.                 i2 = ( i + 2 ) % poly.size;
  157.                
  158.                 t0 = poly[ i0 ];
  159.                 t1 = poly[ i1 ];
  160.                 t2 = poly[ i2 ];
  161.                
  162.                 // if triangle center not inside poly, not an ear
  163.                 if( !point_in_poly( poly, (t0+t1+t2)/3 ) )
  164.                     continue;
  165.                
  166.                 // for each other point
  167.                 for( j = 0; j < poly.size; ++j )
  168.                 {
  169.                     if( i0 == j || i1 == j || i2 == j )
  170.                         continue;
  171.                     // if any other point inside triangle, not an ear
  172.                     if( point_inside_triangle( poly[j], t0, t1, t2 ) )
  173.                         continue 2;
  174.                 }
  175.                
  176.                 triangles.push( t0 );
  177.                 triangles.push( t1 );
  178.                 triangles.push( t2 );
  179.                 poly.erase( i1 );
  180.                 i--;
  181.             }
  182.         }
  183.     }
  184.    
  185.     global g_RB, g_VD_P2CC4;
  186.    
  187.     // TRIANGLE FILL
  188.     g_RB.begin();
  189.     foreach( vtx : triangles )
  190.         g_RB.f( vtx.x, vtx.y ).cf2b( 0.5, 0.7, 0.9, 1 );
  191.     g_RB.draw( null, g_VD_P2CC4, 0, triangles.size, SS_PT_TRIANGLES );
  192.    
  193.     // PATH
  194.     g_RB.begin();
  195.     foreach( vtx : npath )
  196.         g_RB.f( vtx.x, vtx.y ).cf2b( 0.9, 0.7, 0.5, 1 );
  197.     vtx = path[0]; g_RB.f( vtx.x, vtx.y ).cf2b( 0.9, 0.7, 0.5, 1 );
  198.     g_RB.draw( null, g_VD_P2CC4, 0, path.size + 1, SS_PT_LINE_STRIP );
  199.    
  200.     // TRIANGLE WIREFRAME
  201.     g_RB.begin();
  202.     for( i = 0; i < triangles.size; i += 3 )
  203.     {
  204.         p1 = triangles[ i ];
  205.         p2 = triangles[ i+1 ];
  206.         p3 = triangles[ i+2 ];
  207.        
  208.         g_RB.f( p1.x, p1.y ).cf2b( 0.5, 0.2, 0.5, 1 );
  209.         g_RB.f( p2.x, p2.y ).cf2b( 0.5, 0.2, 0.5, 1 );
  210.        
  211.         g_RB.f( p2.x, p2.y ).cf2b( 0.5, 0.2, 0.5, 1 );
  212.         g_RB.f( p3.x, p3.y ).cf2b( 0.5, 0.2, 0.5, 1 );
  213.        
  214.         g_RB.f( p3.x, p3.y ).cf2b( 0.5, 0.2, 0.5, 1 );
  215.         g_RB.f( p1.x, p1.y ).cf2b( 0.5, 0.2, 0.5, 1 );
  216.     }
  217.     g_RB.draw( null, g_VD_P2CC4, 0, triangles.size * 2, SS_PT_LINES );
  218.    
  219.     // POLY DOTS
  220. //  poly = PolyList[13];
  221. //  foreach( i, pt : poly )
  222. //  {
  223. //      SS_Draw({ preset = "box", position = pt, scale = 24, color = color(i/poly.size,1,1,1) });
  224. //      SS_DrawTextLine( i, Font, pt.x, pt.y, color(0,1) );
  225. //  }
  226.    
  227.     // SIDE NUMBERS
  228.     foreach( i, p0 : npath )
  229.     {
  230.         p1 = npath[ (i+1) % npath.size ];
  231.         avg = (p0+p1) / 2;
  232.         SS_DrawTextLine( toint(sides[i]), Font, avg.x, avg.y, color(0.9,0.1,0.1,1) );
  233.     }
  234. }
  235.  
  236.  
  237. global testpath1 =
  238. [
  239.     vec2(32,32),
  240.     vec2(400,200),
  241.     vec2(300,480),
  242.     vec2(300,320),
  243.     vec2(100,320),
  244.     vec2(320,32),
  245.     vec2(220,32),
  246.     vec2(128,128),//
  247.     vec2(256,256),//
  248.     vec2(32,220),
  249. ];
  250.  
  251.  
  252. function configure()
  253. {
  254. }
  255.  
  256. function initialize()
  257. {
  258.     global Window = SS_CreateWindow( "SGS-SDL Game Framework :: PathProc Test",
  259.         SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 512, 512, SDL_WINDOW_OPENGLMAYBE );
  260.     Window.initRenderer( SS_RENDERER_DONTCARE, SS_RENDERER_DONTCARE, SS_RENDERER_VSYNC );
  261.     SS_InitDrawFunctions();
  262.     global Font = SS_CreateFont( "verdana.ttf", 12 );
  263. }
  264.  
  265. function update()
  266. {
  267.     SS_Clear( color(0.1,1) );
  268.     SS_SetCameraUI( 0, Window.width, 0, Window.height );
  269.     render_line_path( testpath1 );
  270.     SS_Present();
  271. }
  272.  
  273. function on_event( e )
  274. {
  275.     if( e.type == SDL_QUIT )
  276.         global sys_exit = true;
  277. }
  278.  
  279. function cleanup()
  280. {
  281. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement