Subversion Repositories gelsvn

Rev

Rev 663 | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 663 Rev 666
Line 15... Line 15...
15
#include <vector>
15
#include <vector>
16
#include <algorithm>
16
#include <algorithm>
17
#include <queue>
17
#include <queue>
18
 
18
 
19
#include <GLGraphics/Console.h>
19
#include <GLGraphics/Console.h>
-
 
20
#include <GLGraphics/glsl_shader.h>
-
 
21
#include <GLGraphics/ShadowBuffer.h>
20
 
22
 
21
#include <CGLA/eigensolution.h>
23
#include <CGLA/eigensolution.h>
22
#include <CGLA/Vec2d.h>
24
#include <CGLA/Vec2d.h>
23
#include <CGLA/Vec3d.h>
25
#include <CGLA/Vec3d.h>
24
#include <CGLA/Mat3x3d.h>
26
#include <CGLA/Mat3x3d.h>
Line 370... Line 372...
370
            cc_smooth(me->active_mesh());
372
            cc_smooth(me->active_mesh());
371
            
373
            
372
            return;
374
            return;
373
        }
375
        }
374
        
376
        
-
 
377
        void console_root_cc_subdivide(MeshEditor* me, const std::vector<std::string> & args)
-
 
378
        {
-
 
379
            if(wantshelp(args)) {
-
 
380
                me->printf("usage: subdivide.catmull_clark ");
-
 
381
                me->printf("Does one step of Catmull-Clark subdivision");
-
 
382
                
-
 
383
                return;
-
 
384
            }
-
 
385
            me->save_active_mesh();
-
 
386
            
-
 
387
            rootCC_subdivide(me->active_mesh(),me->active_mesh());
-
 
388
            return;
-
 
389
        }
-
 
390
 
-
 
391
        
375
        void console_loop_subdivide(MeshEditor* me, const std::vector<std::string> & args)
392
        void console_loop_subdivide(MeshEditor* me, const std::vector<std::string> & args)
376
        {
393
        {
377
            if(wantshelp(args)) {
394
            if(wantshelp(args)) {
378
                me->printf("usage: subdivide.loop");
395
                me->printf("usage: subdivide.loop");
379
                me->printf("Does one step of Loop subdivision");
396
                me->printf("Does one step of Loop subdivision");
Line 385... Line 402...
385
            loop_split(me->active_mesh(),me->active_mesh());
402
            loop_split(me->active_mesh(),me->active_mesh());
386
            loop_smooth(me->active_mesh());
403
            loop_smooth(me->active_mesh());
387
            
404
            
388
            return;
405
            return;
389
        }
406
        }
-
 
407
        
390
        void console_stitch(MeshEditor* me, const std::vector<std::string> & args)
408
        void console_stitch(MeshEditor* me, const std::vector<std::string> & args)
391
        {
409
        {
392
            if(wantshelp(args)) {
410
            if(wantshelp(args)) {
393
                me->printf("usage: cleanup.stitch");
411
                me->printf("usage: cleanup.stitch <rad>");
394
                me->printf("Stitches faces");
412
                me->printf("Stitches faces");
395
                
413
                
396
                return;
414
                return;
397
            }
415
            }
398
            me->save_active_mesh();
416
            double r = 0.001;
399
            
417
            
-
 
418
            if(args.size() > 0){
-
 
419
                istringstream a0(args[0]);
-
 
420
                a0 >> r;
-
 
421
            }
-
 
422
            
-
 
423
            me->save_active_mesh();
-
 
424
            Manifold& m = me->active_mesh();
-
 
425
            Vec3d c;
-
 
426
            float rad;
-
 
427
            bsphere(m, c, rad);
400
            stitch_mesh(me->active_mesh());
428
            stitch_mesh(me->active_mesh(), r * rad);
401
            return;
429
            return;
402
        }
430
        }
403
        
431
        
-
 
432
        void console_remove_val2(MeshEditor* me, const std::vector<std::string> & args)
-
 
433
        {
-
 
434
            if(wantshelp(args)) {
-
 
435
                me->printf("usage: cleanup.remove_val2");
-
 
436
                me->printf("Removes valence 2 vertices");
-
 
437
                
-
 
438
                return;
-
 
439
            }
-
 
440
            me->save_active_mesh();
-
 
441
            Manifold& m = me->active_mesh();
-
 
442
            remove_valence_two_vertices(m);
-
 
443
            return;
-
 
444
        }
-
 
445
 
-
 
446
        
404
        void console_root3_subdivide(MeshEditor* me, const std::vector<std::string> & args)
447
        void console_root3_subdivide(MeshEditor* me, const std::vector<std::string> & args)
405
        {
448
        {
406
            if(wantshelp(args)) {
449
            if(wantshelp(args)) {
407
                me->printf("usage: subdivide.root3");
450
                me->printf("usage: subdivide.root3");
408
                me->printf("Does one step of sqrt(3) subdivision");
451
                me->printf("Does one step of sqrt(3) subdivision");
Line 761... Line 804...
761
                Walker w = m.walker(hid);
804
                Walker w = m.walker(hid);
762
                DebugRenderer::edge_colors[hid] = Vec3f(1.0-max(dist[w.vertex()],dist[w.opp().vertex()])/max_dist,0,0);
805
                DebugRenderer::edge_colors[hid] = Vec3f(1.0-max(dist[w.vertex()],dist[w.opp().vertex()])/max_dist,0,0);
763
            }
806
            }
764
            return;
807
            return;
765
        }
808
        }
-
 
809
 
-
 
810
        const Vec3f& get_color(int i)
766
        
811
        {
-
 
812
            static Vec3f ctable[100000];
-
 
813
            static bool was_here;
-
 
814
            gel_srand(0);
-
 
815
            if(!was_here)
-
 
816
            {
-
 
817
                was_here = true;
-
 
818
                ctable[0] = Vec3f(0);
-
 
819
                for(int j=1;j<100000;++j)
-
 
820
                    ctable[j] = Vec3f(0.3)+0.7*normalize(Vec3f(gel_rand(),gel_rand(),gel_rand()));
-
 
821
                ctable[3] = Vec3f(1,0,0);
-
 
822
                ctable[4] = Vec3f(0,1,0);
-
 
823
                ctable[5] = Vec3f(0,0,1);
-
 
824
                ctable[6] = Vec3f(1,0,1);
-
 
825
            }
-
 
826
            return ctable[i%100000];
-
 
827
        }
-
 
828
 
767
        void console_info(MeshEditor* me, const std::vector<std::string> & args)
829
        void console_info(MeshEditor* me, const std::vector<std::string> & args)
768
        {
830
        {
769
            if(wantshelp(args))
831
            if(wantshelp(args))
770
            {
832
            {
771
                me->printf("usage:  info");
833
                me->printf("usage:  info");
Line 777... Line 839...
777
            stringstream bbox_corners;
839
            stringstream bbox_corners;
778
            bbox_corners << p0 << " - " << p7 << endl;
840
            bbox_corners << p0 << " - " << p7 << endl;
779
            me->printf("Bounding box corners : %s", bbox_corners.str().c_str());
841
            me->printf("Bounding box corners : %s", bbox_corners.str().c_str());
780
            map<int,int> val_hist;
842
            map<int,int> val_hist;
781
            
843
            
-
 
844
            Manifold& m = me->active_mesh();
-
 
845
            for(HalfEdgeID h: m.halfedges())
-
 
846
                DebugRenderer::edge_colors[h] = Vec3f(0.3);
782
            for(VertexIDIterator vi = me->active_mesh().vertices_begin(); vi != me->active_mesh().vertices_end(); ++vi)
847
            for(VertexID v: m.vertices())
783
            {
848
            {
784
                int val = valency(me->active_mesh(), *vi);
849
                int val = valency(m,v);
785
                if(val_hist.find(val) == val_hist.end())
850
                DebugRenderer::vertex_colors[v] = get_color(val);
786
                    val_hist[val] = 0;
-
 
787
                ++val_hist[val];
851
                ++val_hist[val];
-
 
852
                
-
 
853
                if(val != 4)
-
 
854
                    circulate_vertex_ccw(m, v, [&](HalfEdgeID h){
-
 
855
                        Walker w = m.walker(h);
-
 
856
                        DebugRenderer::edge_colors[h] = Vec3f(1);
-
 
857
                        DebugRenderer::edge_colors[w.opp().halfedge()] = Vec3f(1);
-
 
858
                        while(valency(m, w.vertex())==4) {
-
 
859
                            w = w.next().opp().next();
-
 
860
                            DebugRenderer::edge_colors[w.halfedge()] = Vec3f(1);
-
 
861
                            DebugRenderer::edge_colors[w.opp().halfedge()] = Vec3f(1);
-
 
862
                        }
-
 
863
                    });
-
 
864
            }
-
 
865
            map<int, int> ngon_hist;
-
 
866
            for(FaceID f: m.faces()) {
-
 
867
                int ne = no_edges(m, f);
-
 
868
                ++ngon_hist[ne];
-
 
869
                DebugRenderer::face_colors[f] = 0.7*get_color(ne);
788
            }
870
            }
789
            
871
            
790
            me->printf("Valency histogam");
872
            me->printf("Valency histogam");
791
            for(map<int,int>::iterator iter = val_hist.begin(); iter != val_hist.end(); ++iter)
873
            for(map<int,int>::iterator iter = val_hist.begin(); iter != val_hist.end(); ++iter)
792
            {
874
            {
793
                stringstream vhl;
-
 
794
                vhl << iter->first << ", " << iter->second;
-
 
795
                me->printf("%d, %d", iter->first, iter->second);
875
                me->printf("%d, %d", iter->first, iter->second);
796
            }
876
            }
797
            
877
            
-
 
878
            me->printf("Ngon histogam");
-
 
879
            for(map<int,int>::iterator iter = ngon_hist.begin(); iter != ngon_hist.end(); ++iter)
-
 
880
            {
-
 
881
                me->printf("%d, %d", iter->first, iter->second);
-
 
882
            }
-
 
883
 
-
 
884
            
798
            me->printf("Mesh contains %d faces", me->active_mesh().no_faces());
885
            me->printf("Mesh contains %d faces", me->active_mesh().no_faces());
799
            me->printf("Mesh contains %d halfedges", me->active_mesh().no_halfedges());
886
            me->printf("Mesh contains %d halfedges", me->active_mesh().no_halfedges());
800
            me->printf("Mesh contains %d vertices", me->active_mesh().no_vertices());
887
            me->printf("Mesh contains %d vertices", me->active_mesh().no_vertices());
801
            return;
888
            return;
802
        }
889
        }
Line 1123... Line 1210...
1123
            me->active_mesh().cleanup();
1210
            me->active_mesh().cleanup();
1124
            
1211
            
1125
            return;
1212
            return;
1126
        }
1213
        }
1127
        
1214
        
-
 
1215
        void console_flip_orientation(MeshEditor* me, const std::vector<std::string> & args)
-
 
1216
        {
-
 
1217
            if(wantshelp(args)){
-
 
1218
                me->printf("usage: cleanup.flip_orientation");
-
 
1219
                me->printf("reorients all faces - flipping normal direction");
-
 
1220
                return;
-
 
1221
            }
-
 
1222
            me->save_active_mesh();
-
 
1223
            flip_orientation(me->active_mesh());
-
 
1224
            return;
-
 
1225
        }
-
 
1226
 
-
 
1227
        
1128
        void console_undo(MeshEditor* me, const std::vector<std::string> & args)
1228
        void console_undo(MeshEditor* me, const std::vector<std::string> & args)
1129
        {
1229
        {
1130
            if(wantshelp(args)) {
1230
            if(wantshelp(args)) {
1131
                me->printf("usage:  undo");
1231
                me->printf("usage:  undo");
1132
                me->printf("This function undoes one operation. Repeated undo does nothing");
1232
                me->printf("This function undoes one operation. Repeated undo does nothing");
Line 1193... Line 1293...
1193
            return;
1293
            return;
1194
        }
1294
        }
1195
        else {
1295
        else {
1196
            
1296
            
1197
            switch(key) {
1297
            switch(key) {
-
 
1298
                    case 'R':
-
 
1299
                {
-
 
1300
                    theConsole.key_up();
-
 
1301
                    theConsole.keyboard(13);
-
 
1302
                    active_visobj().post_create_display_list();
-
 
1303
                }
-
 
1304
                    break;
1198
                case 'q': exit(0);
1305
                case 'q': exit(0);
1199
                case '\033':
1306
                case '\033':
1200
                    console_visible = false;
1307
                    console_visible = false;
1201
                    break;
1308
                    break;
1202
                case '1':
1309
                case '1':
Line 1337... Line 1444...
1337
    
1444
    
1338
    void MeshEditor::release_mesh()
1445
    void MeshEditor::release_mesh()
1339
    {
1446
    {
1340
        dragging = false;
1447
        dragging = false;
1341
    }
1448
    }
-
 
1449
    
-
 
1450
    
1342
 
1451
    
1343
    
1452
    
1344
    mutex parallel_work;
1453
    mutex parallel_work;
1345
    void MeshEditor::display(int scale){
1454
    void MeshEditor::display(int scale){
-
 
1455
        // Clear screen.
1346
        glClearColor(1, 1, 1, 0);
1456
        glClearColor(1, 1, 1, 0);
1347
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1457
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1348
        
1458
        
1349
//        parallel_work.lock();
1459
        //        parallel_work.lock();
1350
//        active_visobj().post_create_display_list();
1460
        //        active_visobj().post_create_display_list();
-
 
1461
        
-
 
1462
        
-
 
1463
        // Display object.
1351
        active_visobj().display(display_render_mode, theConsole, display_smooth_shading, display_gamma);
1464
        active_visobj().display(display_render_mode, theConsole, display_smooth_shading, display_gamma);
-
 
1465
        
-
 
1466
        // Draw console
1352
        if(console_visible)
1467
        if(console_visible)
1353
        {
1468
        {
1354
            glUseProgram(0);
1469
            glUseProgram(0);
1355
            theConsole.display(scale);
1470
            theConsole.display(scale);
1356
        }
1471
        }
-
 
1472
        
-
 
1473
        // Static variable controlling whether we render shadow at all.
-
 
1474
        static Console::variable<int> shadow_enable(0);
-
 
1475
        shadow_enable.reg(theConsole, "display.shadow.enable", "");
-
 
1476
        if(shadow_enable) {
-
 
1477
            // Static variables that control the shadow display created and linked to console
-
 
1478
            static Console::variable<float> zenith(1.571);
-
 
1479
            static Console::variable<float> azimuth(0);
-
 
1480
            static Console::variable<float> shadow_alpha(0.3);
-
 
1481
            azimuth.reg(theConsole, "display.shadow.azimuth", "");
-
 
1482
            zenith.reg(theConsole, "display.shadow.zenith", "");
-
 
1483
            shadow_alpha.reg(theConsole, "display.shadow.shadow_alpha", "");
-
 
1484
 
-
 
1485
            
-
 
1486
            // Shadow buffer (really a frame buffer object)
-
 
1487
            static ShadowBuffer sb;
-
 
1488
            
-
 
1489
            // String containing fragment program for shadow rendering
-
 
1490
            static string shadow_shdr_fp = "#version 120\n"
-
 
1491
            "    uniform sampler2DShadow shadow_map;\n"
-
 
1492
            "    uniform mat4 Mat;\n"
-
 
1493
            "   uniform float shadow_alpha;\n"
-
 
1494
            "    varying vec4 ep;\n"
-
 
1495
            "    void main()\n"
-
 
1496
            "    {\n"
-
 
1497
            "        vec4 light_pos =  Mat * ep;\n"
-
 
1498
            "        light_pos.z = max(0.001,min(0.999,light_pos.z-0.003));\n"
-
 
1499
            "        if(light_pos.x <=0 || light_pos.x >=1 || light_pos.y <=0 || light_pos.y>=1) gl_FragColor = vec4(1);"
1357
//        parallel_work.unlock();
1500
            "   else      gl_FragColor= vec4(1.0-shadow_alpha)+shadow_alpha*0.25*(shadow2D(shadow_map, light_pos.xyz+vec3(0.001,-0.001,0))+shadow2D(shadow_map, light_pos.xyz+vec3(0.001,0.001,0))+shadow2D(shadow_map, light_pos.xyz-vec3(0.001,0.001,0))+shadow2D(shadow_map, light_pos.xyz+vec3(-0.001,0.001,0)));\n"
-
 
1501
            "    }\n";
-
 
1502
            
-
 
1503
            // Shader program for shadow rendering is compiled and linked.
-
 
1504
            static GLuint prog = 0;
-
 
1505
            if(!prog)
-
 
1506
            {
-
 
1507
                GLuint vp = create_glsl_shader(GL_VERTEX_SHADER,"#version 120\n varying vec4 ep; void main(){ep = gl_Vertex; gl_Position = ftransform();}");
-
 
1508
                GLuint fp = create_glsl_shader(GL_FRAGMENT_SHADER, shadow_shdr_fp);
-
 
1509
                prog = glCreateProgram();
-
 
1510
                
-
 
1511
                glAttachShader(prog, vp);
-
 
1512
                glAttachShader(prog, fp);
-
 
1513
                glLinkProgram(prog);
-
 
1514
            }
-
 
1515
            
-
 
1516
            
-
 
1517
            // Setup OpenGL state for lighting - used when rendering 3D object casting shadow
-
 
1518
            Vec4f lpos = Vec4f(cos(azimuth)*cos(zenith),sin(zenith),sin(azimuth)*cos(zenith),0);
-
 
1519
            glLightfv(GL_LIGHT0, GL_POSITION, lpos.get());
-
 
1520
            Vec4f mamb(.8,.8,.8,0);
-
 
1521
            Vec4f lamb(.4,.4,.5,0);
-
 
1522
            glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mamb.get());
-
 
1523
            glLightfv(GL_LIGHT0, GL_AMBIENT, lamb.get());
-
 
1524
 
-
 
1525
            // Get old viewport dimensions. Setup rendering to FBO and set viewport
-
 
1526
            // dimensions for rendering shadows.
-
 
1527
            GLint viewp[4];
-
 
1528
            glGetIntegerv(GL_VIEWPORT, viewp);
-
 
1529
            sb.enable();
-
 
1530
            glViewport(0, 0, 1024, 1024);
-
 
1531
            
-
 
1532
            // Setup object transformations using old school GL.
-
 
1533
            Mat4x4f m;
-
 
1534
            float r = active_visobj().get_bsphere_radius();
-
 
1535
            glMatrixMode(GL_MODELVIEW);
-
 
1536
            glPushMatrix();
-
 
1537
            glLoadIdentity();
-
 
1538
            glMatrixMode(GL_PROJECTION);
-
 
1539
            glPushMatrix();
-
 
1540
            glLoadIdentity();
-
 
1541
            glOrtho(-2*r, 2*r, -2*r, 2*r, -2*r, 2*r);
-
 
1542
            gluLookAt(0.1*r*cos(azimuth)*cos(zenith),0.1*r*sin(zenith),0.1*r*sin(azimuth)*cos(zenith), 0,0,0, 0,1,0);
-
 
1543
            
-
 
1544
            // Copy the transformation matrix to user code.
-
 
1545
            glGetFloatv(GL_PROJECTION_MATRIX, m.get());
-
 
1546
            
-
 
1547
            // Draw the object in light space.
-
 
1548
            draw(active_visobj().mesh());
-
 
1549
            
-
 
1550
            // Restore transformation matrices.
-
 
1551
            glPopMatrix();
-
 
1552
            glMatrixMode(GL_MODELVIEW);
-
 
1553
            glPopMatrix();
-
 
1554
            
-
 
1555
            // Restore the usual on screen framebuffer.
-
 
1556
            glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
-
 
1557
            glDrawBuffer(GL_BACK);
-
 
1558
            glViewport(0, 0, viewp[2], viewp[3]);
-
 
1559
            
-
 
1560
            // Use shadow: bind the shadow texture to unit 0.
-
 
1561
            sb.bind_textures(0);
-
 
1562
            
-
 
1563
            // Use the shadow rendering shader program.
-
 
1564
            glUseProgram(prog);
-
 
1565
            active_visobj().view_control().set_gl_modelview();
-
 
1566
            glUniform1i(glGetUniformLocation(prog, "shadow_map"), 0);
-
 
1567
            glUniform1f(glGetUniformLocation(prog, "shadow_alpha"), shadow_alpha);
-
 
1568
            m = translation_Mat4x4f(Vec3f(0.5)) * scaling_Mat4x4f(Vec3f(0.5)) * transpose(m);
-
 
1569
            glUniformMatrix4fv(glGetUniformLocation(prog, "Mat"), 1, 1, m.get());
-
 
1570
            
-
 
1571
            
-
 
1572
            // Setup blending such that the shadow is alpha blended with model.
-
 
1573
            glDepthFunc(GL_LEQUAL);
-
 
1574
            glEnable(GL_BLEND);
-
 
1575
            glBlendFunc(GL_ZERO, GL_SRC_COLOR);
-
 
1576
 
-
 
1577
            // Draw ground plane for shadows.
-
 
1578
            Vec3d p0, p7;
-
 
1579
            bbox(active_visobj().mesh(), p0, p7);
-
 
1580
            glBegin(GL_QUADS);
-
 
1581
            glVertex3f(-100*r, p0[1],-100*r);
-
 
1582
            glVertex3f(-100*r, p0[1],100*r);
-
 
1583
            glVertex3f(100*r, p0[1],100*r);
-
 
1584
            glVertex3f(100*r, p0[1],-100*r);
-
 
1585
            glEnd();
-
 
1586
            
-
 
1587
            // Draw model again ... just to add shadow.
-
 
1588
            draw(active_visobj().mesh());
-
 
1589
            
-
 
1590
            // Disable blending and shader program.
-
 
1591
            glDisable(GL_BLEND);
-
 
1592
            glUseProgram(0);
-
 
1593
        }
-
 
1594
        //        parallel_work.unlock();
1358
//        std::this_thread::sleep_for(std::chrono::milliseconds(10));
1595
        //        std::this_thread::sleep_for(std::chrono::milliseconds(10));
1359
    }
1596
    }
1360
    
1597
    
1361
    void MeshEditor::reshape(int w, int h) {
1598
    void MeshEditor::reshape(int w, int h) {
1362
        for(VisObj& v : vo)
1599
        for(VisObj& v : vo)
1363
            v.view_control().reshape(w, h);
1600
            v.view_control().reshape(w, h);
Line 1402... Line 1639...
1402
        register_console_function("cleanup.close_holes", console_close_holes,"");
1639
        register_console_function("cleanup.close_holes", console_close_holes,"");
1403
        register_console_function("load_mesh", console_reload,"");
1640
        register_console_function("load_mesh", console_reload,"");
1404
        register_console_function("add_mesh", console_add_mesh,"");
1641
        register_console_function("add_mesh", console_add_mesh,"");
1405
        
1642
        
1406
        register_console_function("cleanup.stitch", console_stitch,"");
1643
        register_console_function("cleanup.stitch", console_stitch,"");
-
 
1644
        register_console_function("cleanup.remove_val2", console_remove_val2, "");
-
 
1645
        register_console_function("cleanup.flip_orientation", console_flip_orientation,"");
1407
        register_console_function("cleanup.remove_caps", console_remove_caps,"");
1646
        register_console_function("cleanup.remove_caps", console_remove_caps,"");
1408
        register_console_function("cleanup.remove_needles", console_remove_needles,"");
1647
        register_console_function("cleanup.remove_needles", console_remove_needles,"");
1409
        register_console_function("triangulate", console_triangulate,"");
1648
        register_console_function("triangulate", console_triangulate,"");
1410
        register_console_function("refine.split_edges", console_refine_edges,"");
1649
        register_console_function("refine.split_edges", console_refine_edges,"");
1411
        register_console_function("refine.split_faces", console_refine_faces,"");
1650
        register_console_function("refine.split_faces", console_refine_faces,"");
1412
        register_console_function("subdivide.catmull_clark", console_cc_subdivide,"");
1651
        register_console_function("subdivide.catmull_clark", console_cc_subdivide,"");
-
 
1652
        register_console_function("subdivide.rootcc", console_root_cc_subdivide,"");
1413
        register_console_function("subdivide.loop", console_loop_subdivide,"");
1653
        register_console_function("subdivide.loop", console_loop_subdivide,"");
1414
        register_console_function("subdivide.root3", console_root3_subdivide,"");
1654
        register_console_function("subdivide.root3", console_root3_subdivide,"");
1415
        register_console_function("subdivide.doo_sabin", console_doosabin_subdivide,"");
1655
        register_console_function("subdivide.doo_sabin", console_doosabin_subdivide,"");
1416
        register_console_function("subdivide.butterfly", console_butterfly_subdivide,"");
1656
        register_console_function("subdivide.butterfly", console_butterfly_subdivide,"");
1417
        register_console_function("save_mesh", console_save,"");
1657
        register_console_function("save_mesh", console_save,"");