Subversion Repositories gelsvn

Rev

Rev 417 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
386 jab 1
/*
2
 *  MeshEdit is a small application which allows you to load and edit a mesh.
3
 *  The mesh will be stored in GEL's half edge based Manifold data structure.
4
 *  A number of editing operations are supported. Most of these are accessible from the 
5
 *  console that pops up when you hit 'esc'.
6
 *
7
 *  Created by J. Andreas Bærentzen on 15/08/08.
8
 *  Copyright 2008 __MyCompanyName__. All rights reserved.
9
 *
10
 */
399 jab 11
 
12
#include <string>
386 jab 13
#include <iostream>
14
#include <CGLA/eigensolution.h>
15
#include <CGLA/Vec2d.h>
16
#include <CGLA/Vec3d.h>
17
#include <CGLA/Mat3x3d.h>
18
#include <CGLA/Mat2x2d.h>
19
#include <CGLA/Mat2x3d.h>
20
 
21
#include <LinAlg/Matrix.h>
22
#include <LinAlg/Vector.h>
23
#include <LinAlg/LapackFunc.h>
24
 
25
#include <Util/Timer.h>
26
#include <Util/ArgExtracter.h>
27
 
28
#include <GL/glew.h>
29
#include <GLGraphics/gel_glut.h>
30
 
31
#include <HMesh/Manifold.h>
32
#include <HMesh/VertexCirculator.h>
33
#include <HMesh/FaceCirculator.h>
34
#include <HMesh/build_manifold.h>
35
#include <HMesh/mesh_optimization.h>
36
#include <HMesh/triangulate.h>
37
#include <HMesh/load.h>
387 jab 38
#include <HMesh/quadric_simplify.h>
39
#include <HMesh/smooth.h>
386 jab 40
#include <HMesh/x3d_save.h>
388 jab 41
#include <HMesh/obj_save.h>
434 jab 42
#include <HMesh/off_save.h>
387 jab 43
#include <HMesh/mesh_optimization.h>
388 jab 44
#include <HMesh/triangulate.h>
45
#include <HMesh/close_holes.h>
46
#include <HMesh/caps_and_needles.h>
47
#include <HMesh/refine_edges.h>
48
#include <HMesh/subdivision.h>
386 jab 49
 
50
#include <GLConsole/GLConsole.h>
394 jab 51
#include <Util/Timer.h>
386 jab 52
#include "harmonics.h"
412 jab 53
#include "curvature.h"
399 jab 54
#include "Renderer.h"
55
#include "VisObj.h"
386 jab 56
 
391 jab 57
using namespace std;
58
using namespace HMesh;
59
using namespace Geometry;
60
using namespace GLGraphics;
61
using namespace CGLA;
62
using namespace Util;
63
using namespace LinAlg;
412 jab 64
using namespace CVarUtils;
386 jab 65
 
391 jab 66
inline VisObj& get_vis_obj(int i)
67
{
68
	static VisObj vo[9];
69
	return vo[i];
70
}
71
 
72
inline VisObj& avo()
73
{
412 jab 74
	static int& active = CreateCVar("active_mesh",0);
391 jab 75
	return get_vis_obj(active);
76
}
77
 
78
inline Manifold& active_mesh()
79
{
80
	return avo().mesh();
81
}
82
 
83
inline GLViewController& active_view_control()
84
{
85
	return avo().view_control();
86
}
87
 
386 jab 88
// Single global instance so glut can get access
412 jab 89
Trie CVarTrie;
386 jab 90
GLConsole theConsole;
91
 
92
////////////////////////////////////////////////////////////////////////////////
93
char* ConsoleHelp(std::vector<std::string> &args)
94
{
95
    theConsole.Printf("");
96
    theConsole.Printf("----------------- HELP -----------------");
391 jab 97
    theConsole.Printf("Press ESC key to open and close console");
386 jab 98
    theConsole.Printf("Press TAB to see the available commands and functions");
99
    theConsole.Printf("Functions are shown in green and variables in yellow");
100
    theConsole.Printf("Setting a value: [command] = value");
101
    theConsole.Printf("Getting a value: [command]");
102
    theConsole.Printf("Functions: [function] [arg1] [arg2] ...");
391 jab 103
    theConsole.Printf("Entering arg1=? or arg1=help will give a description.");
386 jab 104
    theConsole.Printf("History: Up and Down arrow keys move through history.");
105
    theConsole.Printf("Tab Completion: TAB does tab completion and makes suggestions.");
391 jab 106
    theConsole.Printf("");
107
    theConsole.Printf("Keyboard commands (when console is not active):");
399 jab 108
    theConsole.Printf("w   : switch to display.render_mode = wireframe");
109
    theConsole.Printf("i   : switch to display.render_mode = isophotes");
110
    theConsole.Printf("r   : switch to display.render_mode = reflection");
401 jab 111
    theConsole.Printf("m   : switch to display.render_mode = metallic");
112
    theConsole.Printf("g   : switch to display.render_mode = glazed");
113
    theConsole.Printf("n   : switch to display.render_mode = normal");
399 jab 114
    theConsole.Printf("h   : switch to display.render_mode = harmonics");
115
    theConsole.Printf("f   : toggle smooth/flat shading");
391 jab 116
    theConsole.Printf("1-9 : switch between active meshes.");
399 jab 117
    theConsole.Printf("d   : (display.render_mode = harmonics) diffuse light on and off");
118
    theConsole.Printf("h   : (display.render_mode = harmonics) highlight on and off ");
119
    theConsole.Printf("+/- : (display.render_mode = harmonics) which eigenvector to show");
391 jab 120
    theConsole.Printf("q   : quit program");
121
    theConsole.Printf("ESC : open console");
122
    theConsole.Printf("");
123
    theConsole.Printf("Mouse: Left button rotates, middle zooms, right pans");
386 jab 124
    theConsole.Printf("----------------- HELP -----------------");
125
    theConsole.Printf("");
126
    return "";
127
}
128
 
391 jab 129
bool wantshelp(std::vector<std::string> &args)
130
{
131
	if(args.size()==0) return false;
132
	string str = args[0];
133
	if(str=="help" || str=="HELP" || str=="Help" || str=="?") return true;
134
	return false;
135
}
386 jab 136
 
391 jab 137
/// Function that aligns two meshes.
138
char* console_align(std::vector<std::string> &args)
139
{
140
	if(wantshelp(args)) 
399 jab 141
	{
142
		theConsole.Printf("usage: align <dest> <src>");
143
		theConsole.Printf("This function aligns dest mesh with src");
144
		theConsole.Printf("In practice the GLViewController of src is copied to dst.");
145
		theConsole.Printf("both arguments are mandatory and must be numbers between 1 and 9.");
146
		theConsole.Printf("Note that results might be unexpexted if the meshes are not on the same scale");
147
		return "";
148
	}
149
 
391 jab 150
	int dest = 0;
151
	if(args.size()>0)
152
	{
153
		istringstream a0(args[0]);
154
		a0 >> dest;
155
		--dest;
156
		if(dest <0 || dest>8) return "dest mesh out of range (1-9)";
157
	}
158
	else return "neither source nor destination mesh?!";
159
	int src = 0;
160
	if(args.size()>1)
161
	{
162
		istringstream a1(args[1]);
163
		a1 >> src;
164
		--src;
165
		if(src <0 || src>8) return "src mesh out of range (1-9)";
166
	}	
167
	else return "no src mesh?";
386 jab 168
 
391 jab 169
	get_vis_obj(dest).view_control() = get_vis_obj(src).view_control();
170
 
171
	return "";
386 jab 172
}
173
 
434 jab 174
char* console_flatten(std::vector<std::string> &args)
175
{
176
	if(wantshelp(args)) 
177
	{
178
		theConsole.Printf("usage: flatten <floater|harmonic|barycentric>");
179
		theConsole.Printf("This function flattens a meshs with a simple boundary. It is mostly for showing mesh");
180
		theConsole.Printf("parametrization methods. The current mesh MUST have a SINGLE boundary loop");
181
		theConsole.Printf("This loop is mapped to the unit circle in a regular fashion (equal angle intervals).");
182
		theConsole.Printf("All non boundary vertices are placed at the origin. Then the system is relaxed iteratively");
183
		theConsole.Printf("using the weight scheme given as argument.");
184
		return "";
185
	}
186
	enum WeightScheme {FLOATER_W, HARMONIC_W, BARYCENTRIC_W};
187
	WeightScheme ws = BARYCENTRIC_W;
188
	if(args.size()>0)
189
	{
190
		if(args[0] == "floater")
191
			ws = FLOATER_W;
192
		else if(args[0] == "harmonic")
193
			ws = HARMONIC_W;
194
	}
195
	else
196
		return "";
197
 
198
	active_mesh().enumerate_vertices();
199
	active_mesh().enumerate_halfedges();
200
 
201
	vector<float> edge_weights(active_mesh().no_halfedges());
202
	for(HalfEdgeIter h=active_mesh().halfedges_begin(); h != active_mesh().halfedges_end(); ++h)
203
		if(!is_boundary(h))
204
		{
205
			Vec3f p0 = h->vert->pos;
206
			Vec3f p1 = h->next->vert->pos;
207
			Vec3f p2 = h->opp->vert->pos;
208
			Vec3f p3 = h->opp->next->vert->pos;
209
 
210
			if(ws == FLOATER_W)
211
			{
212
				float d = acos(min(1.0f, max(-1.0f, dot(normalize(p2-p0), normalize(p3-p0)))));
213
				float g = acos(min(1.0f, max(-1.0f, dot(normalize(p2-p0), normalize(p1-p0)))));
214
				edge_weights[h->opp->touched]  = (tan(d/2) + tan(g/2)) / (p0-p2).length();
215
 
216
 
217
				d = acos(min(1.0f, max(-1.0f, dot(normalize(p0-p2), normalize(p1-p2)))));
218
				g = acos(min(1.0f, max(-1.0f, dot(normalize(p0-p2), normalize(p3-p2)))));
219
				edge_weights[h->touched]  = (tan(d/2) + tan(g/2)) / (p0-p2).length();
220
			}
221
			else if(ws == HARMONIC_W)
222
			{
223
 
224
				float a = acos(min(1.0f, max(-1.0f, dot(normalize(p0-p3), normalize(p2-p3)))));
225
				float b = acos(min(1.0f, max(-1.0f, dot(normalize(p2-p1), normalize(p0-p1)))));
226
				float w=0;
227
				if(a+b < M_PI)
228
					w = sin(a+b)/(sin(a)+sin(b));
229
				edge_weights[h->touched]  = w;
230
				edge_weights[h->opp->touched]  = w;
231
			}
232
			else
233
			{
234
				edge_weights[h->touched]  = valency(h->opp->vert);
235
				edge_weights[h->opp->touched]  = valency(h->vert);
236
			}	
237
		}
238
 
239
	ofstream ofs("parametrized.obj");
240
 
241
	ofs << "mtllib parametrized.mtl\nusemtl mat\n" << endl;
242
 
243
	VertexIter v;
244
	for(v=active_mesh().vertices_begin(); v != active_mesh().vertices_end(); ++v)
245
		ofs << "v " << v->pos[0] << " " << v->pos[1] << " " << v->pos[2] << endl;
246
	ofs << endl;
247
 
248
 
249
	for(v=active_mesh().vertices_begin(); v != active_mesh().vertices_end(); ++v)
250
	{
251
		if(is_boundary(v))
252
			break;
253
	}
254
	int n=0;
255
	VertexIter bv = v;
256
	do{
257
		++n;
258
		bv = bv->he->vert;
259
	}
260
	while(bv != v);
261
 
262
	int i=0;
263
	do{
264
		float a = 2.0*M_PI*float(i)/n;
265
		bv->pos = Vec3f(cos(a), sin(a), 0);
266
		++i;
267
		bv = bv->he->vert;
268
	}
269
	while(bv != v);
270
 
271
	for(v=active_mesh().vertices_begin(); v != active_mesh().vertices_end(); ++v)
272
		if(!is_boundary(v))
273
			v->pos = Vec3f(0.0);
274
 
275
	for(int i=0;i<10000;++i)
276
		for(v=active_mesh().vertices_begin(); v != active_mesh().vertices_end(); ++v)
277
			if(!is_boundary(v))
278
			{
279
				Vec3f p_new(0);
280
				float w_sum = 0;
281
				for(VertexCirculator vc(v); !vc.end(); ++vc)
282
				{
283
					float w = edge_weights[vc.get_halfedge()->touched];
284
					p_new += vc.get_vertex()->pos * w;
285
					w_sum += w;
286
				}
287
				v->pos = p_new/w_sum;
288
			}
289
 
290
	for(v=active_mesh().vertices_begin(); v != active_mesh().vertices_end(); ++v)
291
		ofs << "vt " << (0.5*v->pos[0]+0.5) << " " << (0.5*v->pos[1]+0.5)  << endl;
292
 
293
	ofs << endl;
294
 
295
	for(FaceIter f = active_mesh().faces_begin(); f != active_mesh().faces_end(); ++f)
296
	{
297
		ofs << "f ";
298
		for(FaceCirculator fc(f); !fc.end(); ++fc)
299
		{
300
			int idx = fc.get_vertex()->touched + 1;
301
			ofs << idx << "/" << idx <<" ";
302
		}
303
		ofs << endl;
304
	}
305
 
306
	return "";
307
}
391 jab 308
 
388 jab 309
char* console_save(std::vector<std::string> &args)
310
{
391 jab 311
	if(wantshelp(args)) 
399 jab 312
	{
313
		theConsole.Printf("usage: save <name.x3d|name.obj> ");
314
		return "";
315
	}
388 jab 316
	string& file_name = args[0];
317
	if(args.size() == 1)
318
	{
319
		if(file_name.substr(file_name.length()-4,file_name.length())==".obj")
320
		{
391 jab 321
			obj_save(file_name, active_mesh());
388 jab 322
			return "";
323
		}
434 jab 324
		else if(file_name.substr(file_name.length()-4,file_name.length())==".off")
325
		{
326
			off_save(file_name, active_mesh());
327
			return "";
328
		}
388 jab 329
		else if(file_name.substr(file_name.length()-4,file_name.length())==".x3d")
330
		{
391 jab 331
			x3d_save(file_name, active_mesh());
388 jab 332
			return "";
333
		}
334
		return "unknown format";
335
	}
336
	return "usage: save <name.x3d|name.obj> ";
337
}
386 jab 338
 
415 jab 339
////////////////////////////////////////////////////////////////////////////////
340
/**
341
 */
342
char* ConsoleSaveHistory( std::vector<std::string> &vArgs )
412 jab 343
{
415 jab 344
    if( vArgs.size() != 0 ) {
345
        theConsole.SaveHistory( vArgs[0] );
346
    }
347
    else {
348
        theConsole.SaveHistory();
349
    }
350
	return "";
412 jab 351
}
352
 
415 jab 353
////////////////////////////////////////////////////////////////////////////////
354
/**
355
 */
356
char* ConsoleLoadHistory( std::vector<std::string> &vArgs )
412 jab 357
{
415 jab 358
    if( vArgs.size() != 0 ) {
359
        theConsole.LoadHistory( vArgs[0] );
360
    }
361
    else {
362
        theConsole.LoadHistory();
363
    }
364
	return "";
412 jab 365
}
366
 
415 jab 367
////////////////////////////////////////////////////////////////////////////////
368
/**
369
 */
370
char* ConsoleClearHistory( std::vector<std::string> &vArgs )
371
{
372
	theConsole.ClearHistory();
373
	return "";
374
}
412 jab 375
 
415 jab 376
////////////////////////////////////////////////////////////////////////////////
377
/**
378
 */
379
char* ConsoleStartScript( std::vector<std::string> &vArgs )
380
{
381
    theConsole.StartScript();
382
	return "";
383
}
384
 
385
////////////////////////////////////////////////////////////////////////////////
386
/**
387
 */
388
char* ConsoleStopScript( std::vector<std::string> &vArgs )
389
{
390
    theConsole.StopScript();
391
	return "";
392
}
393
 
394
////////////////////////////////////////////////////////////////////////////////
395
/**
396
 */
397
char* ConsoleShowScript( std::vector<std::string> &vArgs )
398
{
399
    theConsole.ShowScript();
400
	return "";
401
}
402
 
403
////////////////////////////////////////////////////////////////////////////////
404
/**
405
 */
406
char* ConsoleRunScript( std::vector<std::string> &vArgs )
407
{
408
    theConsole.RunScript();
409
    return "";
410
}
411
 
412
////////////////////////////////////////////////////////////////////////////////
413
/**
414
 */
415
char* ConsoleSaveScript( std::vector<std::string> &vArgs )
416
{
417
    if( vArgs.size() != 0 ) {
418
        theConsole.SaveScript( vArgs[0] );
419
    }
420
    else {
421
        theConsole.SaveScript();
422
    }
423
	return "";
424
}
425
 
426
////////////////////////////////////////////////////////////////////////////////
427
/**
428
 */
429
char* ConsoleLaunchScript( std::vector<std::string> &vArgs )
430
{
431
    if( vArgs.size() != 0 ) {
432
        theConsole.LaunchScript( vArgs[0] );
433
    } 
434
    else {
435
        theConsole.LaunchScript();
436
    }
437
	return "";
438
}
439
 
440
 
441
////////////////////////////////////////////////////////////////////////////////
442
/**
443
 */
444
char* ConsoleLoad( std::vector<std::string> &vArgs )
445
{
446
    std::string sFile = "cvars.xml";
447
    std::vector< std::string > vAcceptedSubstrings;
448
 
449
    if( vArgs.size() > 0 ) {
450
        sFile = vArgs[0]; 
451
        for( size_t i=1; i<vArgs.size(); i++ ) {
452
            vAcceptedSubstrings.push_back( vArgs[i] );
453
        }
454
    }
455
    theConsole.Printf("Loading file from \"%s\".", sFile.c_str() );
456
    if( !CVarUtils::Load( sFile, vAcceptedSubstrings) ) {
457
        theConsole.Printf( "Error loading file.\n" );
458
    }
459
    return "";
460
}
461
 
462
 
388 jab 463
char* console_refine_edges(std::vector<std::string> &args)
464
{
391 jab 465
	if(wantshelp(args)) 
399 jab 466
	{
467
		theConsole.Printf("usage: refine.split_edges <length>");
468
		theConsole.Printf("splits edges longer than <length>; default is 0.5 times average length");
469
		return "";
470
	}
471
 
388 jab 472
	float thresh = 0.5;
473
	if(args.size()>0)
474
	{
475
		istringstream a0(args[0]);
476
		a0 >> thresh;
477
	}
391 jab 478
	float avg_length = average_edge_length(active_mesh());
479
	refine_edges(active_mesh(), thresh * avg_length);
388 jab 480
	return "";
391 jab 481
 
388 jab 482
}
483
 
484
char* console_refine_faces(std::vector<std::string> &args)
485
{
391 jab 486
	if(wantshelp(args)) 
399 jab 487
	{
488
		theConsole.Printf("usage: refine.split_faces ");
489
		theConsole.Printf("usage:  Takes no arguments. Inserts a vertex at the centre of each face.");
490
		return "";
491
	}
492
 
391 jab 493
	safe_triangulate(active_mesh());
388 jab 494
	return "";
391 jab 495
 
388 jab 496
}
497
 
498
char* console_cc_subdivide(std::vector<std::string> &args)
499
{
391 jab 500
	if(wantshelp(args)) 
399 jab 501
	{
502
		theConsole.Printf("usage: refine.catmull_clark ");
503
		theConsole.Printf("Splits each polygon into four (Catmull Clark style)");
504
		return "";
505
	}
391 jab 506
	cc_split(active_mesh(),active_mesh());
388 jab 507
	return "";
508
}
509
 
394 jab 510
char* console_dual(std::vector<std::string> &args)
511
{
512
	if(wantshelp(args)) 
513
	{
514
		theConsole.Printf("usage: dual ");
515
		theConsole.Printf("Produces the dual by converting each face to a vertex placed at the barycenter.");
516
		return "";
517
	}
518
 
519
	Manifold& m = active_mesh();
520
 
521
	// make sure every face knows its number
522
	m.enumerate_faces();
523
 
524
	vector<Vec3f> vertices(m.no_faces());
399 jab 525
	vector<int> faces;
394 jab 526
	vector<int> indices;
527
 
528
	// Create new vertices. Each face becomes a vertex whose position
529
	// is the centre of the face
530
	int i=0;
531
	for(FaceIter f=m.faces_begin(); f!=m.faces_end(); ++f,++i)
532
		vertices[i] = centre(f);
533
 
534
	// Create new faces. Each vertex is a new face with N=valency of vertex
535
	// edges.
536
	i=0;
537
	for(VertexIter v=m.vertices_begin(); v!= m.vertices_end(); ++v,++i)
399 jab 538
		if(!is_boundary(v))
539
		{
540
			VertexCirculator vc(v);
541
			vector<int> index_tmp;
542
			for(; !vc.end(); ++vc)
543
				index_tmp.push_back(vc.get_face()->touched);
544
 
545
			// Push vertex indices for this face onto indices vector.
546
			// The circulator moves around the face in a clockwise fashion
547
			// so we just reverse the ordering.
548
			indices.insert(indices.end(), index_tmp.rbegin(), index_tmp.rend());
549
 
550
			// Insert face valency in the face vector.
551
			faces.push_back(vc.no_steps());
552
		}
394 jab 553
 
554
	// Clear the manifold before new geometry is inserted.
555
	m.clear();
556
 
557
	// And build
558
	build_manifold(m, vertices.size(), &vertices[0], faces.size(),
559
				   &faces[0],&indices[0]);
560
 
561
	return "";
562
}
388 jab 563
 
564
 
387 jab 565
char* console_minimize_curvature(std::vector<std::string> &args)
566
{
391 jab 567
	if(wantshelp(args)) 
399 jab 568
	{
569
		theConsole.Printf("usage: optimize.minimize_curvature <anneal>");
570
		theConsole.Printf("Flip edges to minimize mean curvature.");
571
		theConsole.Printf("If anneal is true, simulated annealing (slow) is used rather than a greedy scheme");
572
		return "";
573
	}
387 jab 574
	bool anneal=false;
575
	if(args.size()>0)
576
	{
577
		istringstream a0(args[0]);
578
		a0 >> anneal;
579
	}
391 jab 580
 
581
	minimize_curvature(active_mesh(), anneal);
582
	avo().post_create_display_list();
387 jab 583
	return "";
584
}
585
 
586
char* console_minimize_dihedral(std::vector<std::string> &args)
587
{
391 jab 588
	if(wantshelp(args)) 
399 jab 589
	{
590
		theConsole.Printf("usage: optimize.minimize_dihedral <iter> <anneal> <use_alpha> <gamma> ");
591
		theConsole.Printf("Flip edges to minimize dihedral angles.");
592
		theConsole.Printf("Iter is the max number of iterations. anneal tells us whether to use ");
593
		theConsole.Printf("simulated annealing and not greedy optimization. use_alpha (default=true) ");
594
		theConsole.Printf("means to use angle and not cosine of anglegamma (default=4) is the power ");
595
		theConsole.Printf("to which we raise the dihedral angle");
596
		return "";
597
	}
387 jab 598
	int iter = 1000;
599
	if(args.size()>0)
600
	{
601
		istringstream a0(args[0]);
602
		a0 >> iter;
603
	}
391 jab 604
 
387 jab 605
	bool anneal = false;
606
	if(args.size()>1)
607
	{
608
		istringstream a0(args[0]);
609
		a0 >> anneal;
610
	}
391 jab 611
 
387 jab 612
	bool use_alpha = true;
388 jab 613
	if(args.size()>2)
387 jab 614
	{
615
		istringstream a0(args[0]);
616
		a0 >> use_alpha;
617
	}
391 jab 618
 
387 jab 619
	float gamma = 4.0;
620
	if(args.size()>3)
621
	{
622
		istringstream a0(args[0]);
623
		a0 >> gamma;
624
	}
625
 
626
 
391 jab 627
	minimize_dihedral_angle(active_mesh(), iter, anneal, use_alpha, gamma);
387 jab 628
	return "";
629
}
630
 
388 jab 631
char* console_maximize_min_angle(std::vector<std::string> &args)
632
{
391 jab 633
	if(wantshelp(args)) 
399 jab 634
	{
635
		theConsole.Printf("usage: optimize.maximize_min_angle <thresh> <anneal>");
636
		theConsole.Printf("Flip edges to maximize min angle - to make mesh more Delaunay.");
637
		theConsole.Printf("If the dot product of the normals between adjacent faces < thresh");
638
		theConsole.Printf("no flip will be made. anneal selects simulated annealing rather ");
639
		theConsole.Printf("nthan greedy optimization.");
640
		return "";
641
	}
388 jab 642
	float thresh=0.0;
643
	if(args.size()>0)
644
	{
645
		istringstream a0(args[0]);
646
		a0 >> thresh;
647
	}
648
	bool anneal=false;
649
	if(args.size()>1)
650
	{
651
		istringstream a0(args[0]);
652
		a0 >> anneal;
653
	}
391 jab 654
	maximize_min_angle(active_mesh(),thresh,anneal);
388 jab 655
	return "";
656
}
657
 
658
 
387 jab 659
char* console_optimize_valency(std::vector<std::string> &args)
660
{
391 jab 661
	if(wantshelp(args)) 
399 jab 662
	{
663
		theConsole.Printf("usage: optimize.valency <anneal> ");
664
		theConsole.Printf("Optimizes valency for triangle meshes. Anneal selects simulated annealing rather than greedy optim.");
665
		return "";
666
	}
387 jab 667
	bool anneal=false;
668
	if(args.size()>0)
669
	{
670
		istringstream a0(args[0]);
671
		a0 >> anneal;
672
	}
391 jab 673
	optimize_valency(active_mesh(), anneal);
387 jab 674
	return "";
675
}
676
 
388 jab 677
char* console_analyze(std::vector<std::string> &args)
678
{
391 jab 679
	if(wantshelp(args)) 
399 jab 680
	{
681
		theConsole.Printf("usage:  harmonics.analyze");
682
		theConsole.Printf("Creates the Laplace Beltrami operator for the mesh and finds all eigensolutions.");
683
		theConsole.Printf("It also projects the vertices onto the eigenvectors - thus transforming the mesh");
684
		theConsole.Printf("to this basis.");
685
		theConsole.Printf("Note that this will stall the computer for a large mesh - as long as we use Lapack.");
686
		return "";
687
	}
391 jab 688
	avo().harmonics_analyze_mesh();
388 jab 689
	return "";
690
}
691
 
692
 
386 jab 693
char* console_partial_reconstruct(std::vector<std::string> &args)
694
{
434 jab 695
	if(args.size() != 3)
411 jrf 696
		theConsole.Printf("usage: haramonics.partial_reconstruct <e0> <e1> <s>");
434 jab 697
 
698
	if(wantshelp(args)) 
399 jab 699
	{
700
		theConsole.Printf("Reconstruct from projections onto eigenvectors. The two first arguments indicate");
701
		theConsole.Printf("the eigenvector interval that we reconstruct from. The last argument is the ");
702
		theConsole.Printf("scaling factor. Thus, for a vertex, v, the formula for computing the position, p, is:");
703
		theConsole.Printf("for (i=e0; i<=e1;++i) p += proj[i] * Q[i][v] * s;");
704
		theConsole.Printf("where proj[i] is the 3D vector containing the x, y, and z projections of the mesh onto");
705
		theConsole.Printf("eigenvector i. Q[i][v] is the v'th coordinate of the i'th eigenvector.");
706
		theConsole.Printf("Note that if vertex coordinates are not first reset, the result is probably unexpected.");
411 jrf 707
	}
434 jab 708
 
709
	if(args.size() != 3)
399 jab 710
		return "";
434 jab 711
 
712
	int E0,E1;
386 jab 713
	float scale;
714
	istringstream a0(args[0]);
715
	a0 >> E0;
716
	istringstream a1(args[1]);
717
	a1 >> E1;
718
	istringstream a2(args[2]);
719
	a2 >> scale;
391 jab 720
	avo().harmonics_partial_reconstruct(E0,E1,scale);
386 jab 721
	return "";
722
}
723
 
724
char* console_reset_shape(std::vector<std::string> &args)
725
{
391 jab 726
	if(wantshelp(args)) 
399 jab 727
	{
728
		theConsole.Printf("usage: harmonics.reset_shape ");
729
		theConsole.Printf("Simply sets all vertices to 0,0,0. Call this before doing partial_reconstruct");
730
		theConsole.Printf("unless you know what you are doing.");
731
		return "";
732
	}
391 jab 733
	avo().harmonics_reset_shape();
386 jab 734
	return "";
735
}
736
 
737
 
388 jab 738
char* console_close_holes(std::vector<std::string> &args)
739
{
391 jab 740
	if(wantshelp(args)) 
399 jab 741
	{
742
		theConsole.Printf("usage: cleanup.close_holes");
743
		theConsole.Printf("This function closes holes. It simply follows the loop of halfvectors which");
744
		theConsole.Printf("enclose the hole and add a face to which they all point.");
745
		return "";
746
	}
391 jab 747
	close_holes(active_mesh());
388 jab 748
	return "";
749
}
386 jab 750
 
388 jab 751
char* console_reload(std::vector<std::string> &args)
752
{
391 jab 753
	if(wantshelp(args)) 
399 jab 754
	{
412 jab 755
		theConsole.Printf("usage:  load <file>");
756
		theConsole.Printf("(Re)loads the current file if no argument is given, but");
399 jab 757
		theConsole.Printf("if an argument is given, then that becomes the current file");
758
		return "";
759
	}
391 jab 760
	if(!avo().reload(args.size()>0 ? args[0]:""))
761
		return "failed to load";
388 jab 762
	return "";
763
}
764
 
765
 
387 jab 766
char* console_simplify(std::vector<std::string> &args)
767
{
391 jab 768
	if(wantshelp(args)) 
399 jab 769
	{
770
		theConsole.Printf("usage: simplify <fraction> ");
771
		theConsole.Printf("Performs Garland Heckbert (quadric based) mesh simplification.");
772
		theConsole.Printf("The only argument is the fraction of vertices to keep.");
773
		return "";
774
	}
387 jab 775
	float keep_fraction;
776
	if(args.size()==0) return "you must specify fraction of vertices to keep";
777
	istringstream a0(args[0]);
778
	a0 >> keep_fraction;
391 jab 779
 
387 jab 780
	Vec3f p0, p7;
391 jab 781
	active_mesh().get_bbox(p0, p7);
387 jab 782
	Vec3f d = p7-p0;
783
	float s = 1.0/d.max_coord();
784
	Vec3f pcentre = (p7+p0)/2.0;
391 jab 785
	for(VertexIter vi = active_mesh().vertices_begin(); vi != active_mesh().vertices_end(); ++vi)
387 jab 786
		vi->pos = (vi->pos - pcentre) * s;
391 jab 787
	quadric_simplify(active_mesh(),keep_fraction,0.0001f,true);
788
	for(VertexIter vi = active_mesh().vertices_begin(); vi != active_mesh().vertices_end(); ++vi)
387 jab 789
		vi->pos = vi->pos*d.max_coord() + pcentre;
790
	return "";
791
}
792
 
391 jab 793
char* console_vertex_noise(std::vector<std::string> &args)
794
{
795
	if(wantshelp(args)) 
399 jab 796
	{
797
		theConsole.Printf("usage: noise.perturb_vertices <amplitude>");
403 jab 798
		theConsole.Printf("adds a random vector to each vertex. A random vector in the unit cube is generated and");
799
		theConsole.Printf("to ensure an isotropic distribution, vectors outside the unit ball are discarded.");
800
		theConsole.Printf("The vector is multiplied by the average edge length and then by the amplitude specified.");
801
		theConsole.Printf("If no amplitude is specified, the default (0.5) is used.");
399 jab 802
		return "";
803
	}
391 jab 804
	float avg_length = average_edge_length(active_mesh());
805
 
806
	float noise_amplitude = 0.5;
807
	if(args.size()>0) 
808
	{
809
		istringstream a0(args[0]);
810
		a0 >> noise_amplitude;
811
	}
812
 
417 jrf 813
	gel_srand(0);
391 jab 814
	for(VertexIter vi = active_mesh().vertices_begin(); vi != active_mesh().vertices_end(); ++vi)
815
	{
816
		Vec3f v;
817
		do {
417 jrf 818
			v = Vec3f(gel_rand(),gel_rand(),gel_rand());
819
			v /= GEL_RAND_MAX;
391 jab 820
		} while(sqr_length(v) > 1.0);
821
		v -= Vec3f(0.5);
822
		v *= 2.0;
823
		v *= noise_amplitude;
824
		v *= avg_length;
825
		vi->pos += v;
826
	}		
827
	return "";
828
}
829
 
412 jab 830
char* console_perpendicular_vertex_noise(std::vector<std::string> &args)
831
{
832
	if(wantshelp(args)) 
833
	{
834
		theConsole.Printf("usage: noise.perturb_vertices_perpendicular <amplitude>");
835
		theConsole.Printf("adds the normal times a random scalar times amplitude times");
836
		theConsole.Printf("times average edge length to the vertex. (default amplitude=0.5)");
837
		return "";
838
	}
839
	float avg_length = average_edge_length(active_mesh());
840
 
841
	float noise_amplitude = 0.5;
842
	if(args.size()>0) 
843
	{
844
		istringstream a0(args[0]);
845
		a0 >> noise_amplitude;
846
	}
847
 
848
	vector<Vec3f> normals(active_mesh().no_vertices());
849
	int i=0;
850
	for(VertexIter vi = active_mesh().vertices_begin(); vi != active_mesh().vertices_end(); ++vi,++i)
851
		normals[i] = normal(vi);
852
	i=0;
417 jrf 853
	gel_srand(0);
412 jab 854
	for(VertexIter vi = active_mesh().vertices_begin(); vi != active_mesh().vertices_end(); ++vi,++i)
855
	{
417 jrf 856
		float rval = 0.5-gel_rand()/float(GEL_RAND_MAX);
412 jab 857
		vi->pos += normals[i]*rval*noise_amplitude*avg_length*2.0;
858
	}
859
	return "";
860
}
861
 
391 jab 862
char* console_noisy_flips(std::vector<std::string> &args)
863
{
864
	if(wantshelp(args)) 
399 jab 865
	{
866
		theConsole.Printf("usage:  noise.perturb_topology <iter>");
867
		theConsole.Printf("Perform random flips. iter (default=1) is the number of iterations.");
868
		theConsole.Printf("mostly for making nasty synthetic test cases.");
869
		return "";
870
	}
391 jab 871
	int iter=1;
872
	if(args.size()>0)
873
	{
874
		istringstream a0(args[0]);
875
		a0 >> iter;
876
	}
877
 
878
	randomize_mesh(active_mesh(),  iter);
879
	return "";
880
}
881
 
387 jab 882
char* console_laplacian_smooth(std::vector<std::string> &args)
883
{
391 jab 884
	if(wantshelp(args)) 
399 jab 885
	{
412 jab 886
		theConsole.Printf("usage:  smooth.laplacian <weight> <iter>");
399 jab 887
		theConsole.Printf("Perform Laplacian smoothing. weight is the scaling factor for the Laplacian.");
412 jab 888
		theConsole.Printf("default weight = 1.0. Default number of iterations = 1");
399 jab 889
		return "";
890
	}
387 jab 891
	float t=1.0;
892
	if(args.size()>0)
893
	{
894
		istringstream a0(args[0]);
895
		a0 >> t;
896
	}
412 jab 897
	int iter=1;
898
	if(args.size()>1)
899
	{
900
		istringstream a0(args[1]);
901
		a0 >> iter;
902
	}
903
 
387 jab 904
	/// Simple laplacian smoothing with an optional weight.
412 jab 905
	for(int i=0;i<iter;++i) laplacian_smooth(active_mesh(), t);
387 jab 906
	return "";
907
}
908
 
412 jab 909
char* console_mean_curvature_smooth(std::vector<std::string> &args)
910
{
911
	if(wantshelp(args)) 
912
	{
913
		theConsole.Printf("usage:  smooth.mean_curvature <weight> <iter>");
914
		theConsole.Printf("Perform mean curvature smoothing. weight is the scaling factor for the");
915
		theConsole.Printf("mean curvature vector which has been normalized by dividing by edge lengths");
916
		theConsole.Printf("this allows for larger steps as suggested by Desbrun et al.");
917
		theConsole.Printf("default weight = 1.0. Default number of iterations = 1");
918
		return "";
919
	}
920
	float t=1.0;
921
	if(args.size()>0)
922
	{
923
		istringstream a0(args[0]);
924
		a0 >> t;
925
	}
926
	int iter=1;
927
	if(args.size()>1)
928
	{
929
		istringstream a0(args[1]);
930
		a0 >> iter;
931
	}	
932
	vector<Vec3d> new_pos(active_mesh().no_vertices());
933
	for(int j=0;j<iter;++j)
934
	{
935
		int i=0;
936
		for(VertexIter v = active_mesh().vertices_begin(); v != active_mesh().vertices_end(); ++v,++i) {
937
			Vec3d m;
938
			double w_sum;
939
			unnormalized_mean_curvature_normal(v, m, w_sum);
940
			new_pos[i] = Vec3d(v->pos)  - (t * m/w_sum);
941
		}
942
		i=0;
943
		for(VertexIter v = active_mesh().vertices_begin(); v != active_mesh().vertices_end(); ++v,++i)
944
			v->pos = Vec3f(new_pos[i]);
945
	}
946
	return "";
947
}
948
 
434 jab 949
const double angle_defect(VertexIter v)
950
{
951
	if(!is_boundary(v))
952
	{
953
		Vec3f vertex(v->pos);
954
		vector<Vec3d> edges;
955
		for(VertexCirculator vc(v); !vc.end(); ++vc)
956
		{
957
			Vec3d e(normalize(vc.get_vertex()->pos-vertex));
958
			edges.push_back(e);
959
		}
960
		int N=edges.size();
961
		double angle_sum = 0;
962
		for(int i=0;i<N;++i)
963
		{
964
			double dot_prod = 
965
			s_max(-1.0, s_min(1.0, dot(edges[i],edges[(i+1)%N])));
966
			angle_sum += acos(dot_prod);
967
		}
968
		return fabs(2*M_PI - angle_sum);
969
	}
970
	return 1000;
971
}
412 jab 972
 
434 jab 973
char* console_experimental_smooth(std::vector<std::string> &args)
974
{
975
	if(wantshelp(args)) 
976
	{
977
		theConsole.Printf("usage:  smooth.experimental <weight> <iter>");
978
		theConsole.Printf("Perform experimental smoothing. weight is the scaling factor for the");
979
		theConsole.Printf("experimetnal vector which has been normalized by dividing by edge lengths");
980
		theConsole.Printf("this allows for larger steps as suggested by Desbrun et al.");
981
		theConsole.Printf("default weight = 1.0. Default number of iterations = 1");
982
		return "";
983
	}
984
	float t=1.0;
985
	if(args.size()>0)
986
	{
987
		istringstream a0(args[0]);
988
		a0 >> t;
989
	}
990
	int iter=1;
991
	if(args.size()>1)
992
	{
993
		istringstream a0(args[1]);
994
		a0 >> iter;
995
	}	
996
 
997
	Vec3f p0_before, p7_before;
998
	active_mesh().get_bbox(p0_before, p7_before);
999
 
1000
	double avg_area=0.0;
1001
	for(FaceIter f=active_mesh().faces_begin(); f != active_mesh().faces_end(); ++f)
1002
		avg_area += area(f);
1003
	avg_area /= active_mesh().no_faces();
1004
 
1005
	for(int j=0;j<iter;++j)
1006
	{
1007
 
1008
		vector<Vec3d> new_pos(active_mesh().no_vertices());
1009
 
1010
		int i=0;
1011
		for(VertexIter v = active_mesh().vertices_begin(); v != active_mesh().vertices_end(); ++v,++i) 
1012
			{
1013
				double w_sum=0;
1014
				Vec3d m(0);
1015
				VertexCirculator vc(v);
1016
				for(; !vc.end(); ++vc)
1017
				{
1018
					HalfEdgeIter h = vc.get_halfedge();
1019
					double area_left  = area(h->face);
1020
					double area_right = area(h->opp->face);
1021
 
1022
					double w = 0.5 * (area_left + area_right);
1023
					m += w * Vec3d(vc.get_vertex()->pos-v->pos);
1024
					w_sum += w;
1025
				}
1026
				double t2 = pow((w_sum/vc.no_steps())/avg_area,.25);
1027
				if(t2 > 1e-10)
1028
					new_pos[i] = Vec3d(v->pos)  + (t * t2 * m/w_sum);
1029
			}
1030
		i=0;
1031
		for(VertexIter v = active_mesh().vertices_begin(); v != active_mesh().vertices_end(); ++v,++i)
1032
			v->pos = Vec3f(new_pos[i]);
1033
 
1034
		active_mesh().delayed_erase();
1035
		for(HalfEdgeIter h=active_mesh().halfedges_begin(); h!=active_mesh().halfedges_end(); ++h)
1036
			if(active_mesh().is_used(h))
1037
		{
1038
			Vec3d mcna,mcnb;
1039
			double ws;
1040
 
1041
			unnormalized_mean_curvature_normal(h->vert, mcna, ws);
1042
			unnormalized_mean_curvature_normal(h->opp->vert, mcnb, ws);
1043
			if(sqr_length(mcna) < 1 && sqr_length(mcnb) < 1)
1044
				if(active_mesh().collapse_precond(h))
1045
				{
1046
					active_mesh().collapse_halfedge(h, false);
1047
				}
1048
		}
1049
		active_mesh().immediate_erase();
1050
		maximize_min_angle(active_mesh(), 0.95, false);
1051
	}
1052
 
1053
	Vec3f p0, p7;
1054
	active_mesh().get_bbox(p0, p7);
1055
	for(VertexIter vi = active_mesh().vertices_begin(); vi != active_mesh().vertices_end(); ++vi)
1056
		vi->pos = (p7_before-p0_before)*(vi->pos - p0)/(p7-p0)+p0_before;
1057
 
1058
	return "";
1059
}
1060
 
1061
 
387 jab 1062
char* console_taubin_smooth(std::vector<std::string> &args)
1063
{
391 jab 1064
	if(wantshelp(args)) 
399 jab 1065
	{
1066
		theConsole.Printf("usage:  smooth.taubin <iter>");
1067
		theConsole.Printf("Perform Taubin smoothing. iter (default=1) is the number of iterations.");
1068
		return "";
1069
	}
387 jab 1070
	int iter=1;
1071
	if(args.size()>0)
1072
	{
1073
		istringstream a0(args[0]);
1074
		a0 >> iter;
1075
	}
1076
 
1077
	/// Taubin smoothing is similar to laplacian smoothing but reduces shrinkage
391 jab 1078
	taubin_smooth(active_mesh(),  iter);
387 jab 1079
	return "";
1080
}
1081
 
1082
char* console_fvm_smooth(std::vector<std::string> &args)
1083
{	
391 jab 1084
	if(wantshelp(args)) 
399 jab 1085
	{
1086
		theConsole.Printf("usage: smooth.fuzzy_vector_median <iter>");
1087
		theConsole.Printf("Smooth normals using fuzzy vector median smoothing. iter (default=1) is the number of iterations");
1088
		theConsole.Printf("This function does a very good job of preserving sharp edges.");
1089
		return "";
1090
	}
387 jab 1091
	int iter=1;
1092
	if(args.size()>0)
1093
	{
1094
		istringstream a0(args[0]);
1095
		a0 >> iter;
1096
	}
1097
	/** Fuzzy vector median smoothing is effective when it comes to
1098
	 preserving sharp edges. */
391 jab 1099
	fvm_smooth(active_mesh(),  iter);
387 jab 1100
	return "";
391 jab 1101
 
387 jab 1102
}
1103
 
388 jab 1104
char* console_triangulate(std::vector<std::string> &args)
1105
{	
391 jab 1106
	if(wantshelp(args)) 
399 jab 1107
	{
1108
		theConsole.Printf("usage:  triangulate");
1109
		theConsole.Printf("This function triangulates all non triangular faces of the mesh.");
1110
		theConsole.Printf("you may want to call it after hole closing. For a polygon it simply connects");
1111
		theConsole.Printf("the two closest vertices in a recursive manner until only triangles remain");
1112
		return "";
1113
	}
391 jab 1114
	shortest_edge_triangulate(active_mesh());
388 jab 1115
	return "";
1116
}
1117
 
1118
 
1119
char* console_remove_caps(std::vector<std::string> &args)
1120
{	
391 jab 1121
	if(wantshelp(args)) 
399 jab 1122
	{
1123
		theConsole.Printf("usage:  cleanup.remove_caps thresh");
1124
		theConsole.Printf("Remove caps (triangles with one very big angle). The thresh argument is the fraction of PI to");
1125
		theConsole.Printf("use as threshold for big angle. Default is 0.85. Caps are removed by flipping.");
1126
		return "";
1127
	}
391 jab 1128
	float t=0.85;
1129
	if(args.size()>0)
1130
	{
1131
		istringstream a0(args[0]);
1132
		a0 >> t;
1133
	}
399 jab 1134
 
391 jab 1135
	remove_caps_from_trimesh(active_mesh(), static_cast<float>(M_PI) *t);
388 jab 1136
	return "";
1137
}
1138
 
1139
char* console_remove_needles(std::vector<std::string> &args)
1140
{	
391 jab 1141
	if(wantshelp(args)) 
399 jab 1142
	{
1143
		theConsole.Printf("usage: cleanup.remove_needles <thresh>");
1144
		theConsole.Printf("Removes very short edges by collapse. thresh is multiplied by the average edge length");
1145
		theConsole.Printf("to get the length shorter than which we collapse. Default = 0.1");
1146
		return "";
1147
	}
388 jab 1148
	float thresh = 0.1;
1149
	if(args.size()>0)
1150
	{
1151
		istringstream a0(args[0]);
1152
		a0 >> thresh;
1153
	}
391 jab 1154
	float avg_length = average_edge_length(active_mesh());
1155
	remove_needles_from_trimesh(active_mesh(), thresh * avg_length);
388 jab 1156
	return "";
1157
}
1158
 
391 jab 1159
void reshape(int W, int H)
1160
{
1161
	active_view_control().reshape(W,H);
1162
}
1163
 
386 jab 1164
void display() 
1165
{
1166
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1167
 
412 jab 1168
	static string& display_render_mode = CreateCVar<string>("display.render_mode","");
1169
	static int& display_smooth= CreateCVar<int>("display.smooth_shading",1);
386 jab 1170
 
1171
	glPushMatrix();
1172
 
399 jab 1173
	avo().display(display_render_mode, display_smooth);
386 jab 1174
 
1175
	glPopMatrix();
1176
 
1177
	glUseProgram(0);
1178
	theConsole.RenderConsole();
1179
 
1180
	glutSwapBuffers();
1181
}
1182
 
1183
void animate() 
1184
{	
394 jab 1185
	//usleep( (int)1e4 );
391 jab 1186
	active_view_control().try_spin();
386 jab 1187
	glutPostRedisplay();
1188
}
1189
 
1190
 
1191
void mouse(int button, int state, int x, int y) 
1192
{
1193
	Vec2i pos(x,y);
1194
	if (state==GLUT_DOWN) 
1195
	{
1196
		if (button==GLUT_LEFT_BUTTON) 
391 jab 1197
			active_view_control().grab_ball(ROTATE_ACTION,pos);
386 jab 1198
		else if (button==GLUT_MIDDLE_BUTTON) 
391 jab 1199
			active_view_control().grab_ball(ZOOM_ACTION,pos);
386 jab 1200
		else if (button==GLUT_RIGHT_BUTTON) 
391 jab 1201
			active_view_control().grab_ball(PAN_ACTION,pos);
386 jab 1202
	}
1203
	else if (state==GLUT_UP)
391 jab 1204
		active_view_control().release_ball();
386 jab 1205
}
1206
 
1207
void motion(int x, int y) {
1208
	Vec2i pos(x,y);
391 jab 1209
	active_view_control().roll_ball(Vec2i(x,y));
386 jab 1210
}
1211
 
1212
void keyboard_spec(int key, int x, int y)
1213
{
391 jab 1214
	int mod = glutGetModifiers();
412 jab 1215
	if( theConsole.IsOpen() ) {
391 jab 1216
		// If shift held, scroll the console
1217
		if( mod == GLUT_ACTIVE_SHIFT ) {
1218
			switch (key){
1219
				case GLUT_KEY_UP:
1220
					theConsole.ScrollDownLine();
1221
					break;
1222
				case GLUT_KEY_DOWN: 
1223
					theConsole.ScrollUpLine();
1224
					break;
1225
			}
1226
		} else {
1227
			theConsole.StandardKeyBindings( key );
1228
		}
1229
	}
386 jab 1230
}
1231
 
1232
 
1233
void keyboard(unsigned char key, int x, int y) 
1234
{	
412 jab 1235
	if(theConsole.IsOpen())
391 jab 1236
	{
386 jab 1237
		switch(key) {
1238
			case '\033': 
1239
				theConsole.ToggleConsole();
412 jab 1240
			default:
1241
				theConsole.EnterCommandCharacter(key);
434 jab 1242
				break;
388 jab 1243
		}
391 jab 1244
		if(key == 13)	avo().post_create_display_list();
1245
 
1246
	}	
386 jab 1247
	else {
412 jab 1248
		string& display_render_mode = GetCVarRef<string>("display.render_mode");
1249
		int& display_smooth = GetCVarRef<int>("display.smooth_shading");
1250
		int& active  = GetCVarRef<int>("active_mesh");
386 jab 1251
 
391 jab 1252
 
386 jab 1253
		switch(key) {
1254
			case 'q': exit(0);
1255
			case '\033':
1256
				theConsole.ToggleConsole();
1257
				break;
391 jab 1258
			case '1':
1259
			case '2':
1260
			case '3':
1261
			case '4':
1262
			case '5':
1263
			case '6':
1264
			case '7':
1265
			case '8':
1266
			case '9':
1267
				active = key - '1'; break;
399 jab 1268
			case 'f': display_smooth = !display_smooth; break;
386 jab 1269
			case 'w':
399 jab 1270
				display_render_mode = "wire"; break;
1271
			case 'n':
1272
				display_render_mode = "normal"; break;
1273
			case 'i':
1274
				display_render_mode = "isophotes"; break;
1275
			case 'r':
1276
				display_render_mode = "reflection"; break;
1277
			case 'h':
1278
				display_render_mode = "harmonics"; break;
403 jab 1279
			case 't':
1280
				display_render_mode = "toon"; break;
401 jab 1281
			case 'g':
1282
				display_render_mode = "glazed"; break;
406 jab 1283
			case 'a':
1284
				display_render_mode = "ambient_occlusion"; break;
1285
			case 'c':
1286
				display_render_mode = "copper"; break;
403 jab 1287
			case 'C':
1288
				display_render_mode = "curvature_lines"; break;
1289
			case 'M':
1290
				display_render_mode = "mean_curvature"; break;
1291
			case 'G':
1292
				display_render_mode = "gaussian_curvature"; break;
386 jab 1293
		}
391 jab 1294
 
399 jab 1295
		if(display_render_mode.substr(0,4) == "harm")
391 jab 1296
			avo().harmonics_parse_key(key);
1297
 
403 jab 1298
		if(key != '\033') avo().post_create_display_list();		
386 jab 1299
	}
1300
}
1301
 
1302
void init_glut(int argc, char** argv)
1303
{
397 jab 1304
	glutInitDisplayMode(GLUT_RGBA|GLUT_DOUBLE|GLUT_DEPTH|GLUT_ALPHA);
386 jab 1305
	glutInitWindowSize(WINX, WINY);
1306
	glutInit(&argc, argv);
1307
	glutCreateWindow("Shape Harmonics");
1308
	glutDisplayFunc(display);
1309
	glutKeyboardFunc(keyboard);
1310
	glutSpecialFunc(keyboard_spec);
1311
	glutReshapeFunc(reshape);
1312
	glutMouseFunc(mouse);
1313
	glutMotionFunc(motion);
1314
	glutIdleFunc(animate);
1315
}
1316
 
1317
void init_gl()
1318
{
1319
	glewInit();
1320
	glEnable(GL_LIGHTING);
1321
	glEnable(GL_LIGHT0);
388 jab 1322
	glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 1);
399 jab 1323
 
386 jab 1324
	// Set the value of a uniform
1325
	//glUniform2f(glGetUniformLocation(prog_P0,"WIN_SCALE"), win_size_x/2.0, win_size_y/2.0);
1326
 
1327
	glMatrixMode(GL_MODELVIEW);
1328
	glLoadIdentity();
1329
	glClearColor(0.50f, 0.50f, 0.50f, 0.f);
1330
	glColor4f(1.0f, 1.0f, 1.0f, 0.f);
406 jab 1331
	float material[4] = {1,1,1,1};
1332
	glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, material);
386 jab 1333
	glEnable(GL_DEPTH_TEST);
1334
 
412 jab 1335
	CreateCVar( "help", ConsoleHelp );
1336
	CreateCVar("harmonics.reset_shape", console_reset_shape);
1337
	CreateCVar("harmonics.analyze", console_analyze);
1338
	CreateCVar("harmonics.partial_reconstruct", console_partial_reconstruct);
1339
	CreateCVar("simplify", console_simplify);
1340
	CreateCVar("smooth.mean_curvature", console_mean_curvature_smooth);
434 jab 1341
	CreateCVar("smooth.experimental", console_experimental_smooth);
412 jab 1342
	CreateCVar("smooth.laplacian", console_laplacian_smooth);
1343
	CreateCVar("smooth.taubin", console_taubin_smooth);
1344
	CreateCVar("smooth.fuzzy_vector_median", console_fvm_smooth);
391 jab 1345
 
412 jab 1346
	CreateCVar("optimize.valency", console_optimize_valency);
1347
	CreateCVar("optimize.minimize_dihedral_angles", console_minimize_dihedral);
1348
	CreateCVar("optimize.minimize_curvature", console_minimize_curvature);
1349
	CreateCVar("optimize.maximize_min_angle", console_maximize_min_angle);
1350
	CreateCVar("cleanup.close_holes", console_close_holes);
1351
	CreateCVar("load", console_reload);
391 jab 1352
 
412 jab 1353
	CreateCVar("cleanup.remove_caps", console_remove_caps);
1354
	CreateCVar("cleanup.remove_needles", console_remove_needles);
1355
	CreateCVar("triangulate", console_triangulate);
1356
	CreateCVar("refine.split_edges", console_refine_edges);
1357
	CreateCVar("refine.split_faces", console_refine_faces);
1358
	CreateCVar("refine.catmull_clark", console_cc_subdivide);
1359
	CreateCVar("save", console_save);
1360
	CreateCVar("noise.perturb_vertices", console_vertex_noise);
1361
	CreateCVar("noise.perturb_vertices_perpendicular", console_perpendicular_vertex_noise);
1362
	CreateCVar("noise.perturb_topology", console_noisy_flips);
399 jab 1363
 
412 jab 1364
	CreateCVar("dual", console_dual);
434 jab 1365
	CreateCVar("flatten", console_flatten);
399 jab 1366
 
412 jab 1367
	CreateCVar("align", console_align);
387 jab 1368
 
415 jab 1369
	CVarUtils::CreateCVar( "history.load", ConsoleLoadHistory );
1370
    CVarUtils::CreateCVar( "history.save", ConsoleSaveHistory );
1371
    CVarUtils::CreateCVar( "history.clear", ConsoleClearHistory );
387 jab 1372
 
415 jab 1373
    CVarUtils::CreateCVar( "script.start", ConsoleStartScript );
416 jab 1374
    CVarUtils::CreateCVar(	"script.stop", ConsoleStopScript );
415 jab 1375
    CVarUtils::CreateCVar( "script.show", ConsoleShowScript );
1376
    CVarUtils::CreateCVar( "script.run", ConsoleRunScript );
1377
    CVarUtils::CreateCVar( "script.save", ConsoleSaveScript );
1378
    CVarUtils::CreateCVar( "script.launch", ConsoleLaunchScript );
1379
 
1380
 
386 jab 1381
}
1382
 
1383
int main(int argc, char** argv)
1384
{
1385
	ArgExtracter ae(argc, argv);
391 jab 1386
 
1387
	init_glut(argc,argv);
1388
	init_gl();
1389
 
1390
	Harmonics::init();
1391
 
399 jab 1392
	if(argc>1)
386 jab 1393
	{		
391 jab 1394
		string file = ae.get_last_arg();
1395
		avo().reload(file);
386 jab 1396
	}
1397
 
399 jab 1398
 
386 jab 1399
	glutMainLoop();
1400
}
1401
 
1402