Subversion Repositories gelsvn

Rev

Rev 393 | 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
 */
11
#include <iostream>
12
#include <CGLA/eigensolution.h>
13
#include <CGLA/Vec2d.h>
14
#include <CGLA/Vec3d.h>
15
#include <CGLA/Mat3x3d.h>
16
#include <CGLA/Mat2x2d.h>
17
#include <CGLA/Mat2x3d.h>
18
 
19
#include <LinAlg/Matrix.h>
20
#include <LinAlg/Vector.h>
21
#include <LinAlg/LapackFunc.h>
22
 
23
#include <Util/Timer.h>
24
#include <Util/ArgExtracter.h>
25
 
26
#include <GL/glew.h>
27
#include <GLGraphics/gel_glut.h>
28
#include <GLGraphics/draw.h>
29
#include <GLGraphics/glsl_shader.h>
30
#include <GLGraphics/GLViewController.h>
31
 
32
#include <HMesh/Manifold.h>
33
#include <HMesh/VertexCirculator.h>
34
#include <HMesh/FaceCirculator.h>
35
#include <HMesh/build_manifold.h>
36
#include <HMesh/mesh_optimization.h>
37
#include <HMesh/triangulate.h>
38
#include <HMesh/load.h>
387 jab 39
#include <HMesh/quadric_simplify.h>
40
#include <HMesh/smooth.h>
386 jab 41
#include <HMesh/x3d_save.h>
388 jab 42
#include <HMesh/obj_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>
395 jab 51
#include <Util/Timer.h>
386 jab 52
#include "harmonics.h"
53
#include "wireframe.h"
54
 
391 jab 55
using namespace std;
56
using namespace HMesh;
57
using namespace Geometry;
58
using namespace GLGraphics;
59
using namespace CGLA;
60
using namespace Util;
61
using namespace LinAlg;
386 jab 62
 
391 jab 63
int WINX=800, WINY=800;
64
 
65
class VisObj
66
{
67
	string file;
68
	GLViewController view_ctrl;
69
	GLuint display_list;
70
	bool create_display_list;
71
	Manifold mani;
72
	Harmonics* harmonics;
73
 
74
public:
75
 
76
	Manifold& mesh() {return mani;}
77
	GLViewController& view_control() {return view_ctrl;}
78
 
79
	bool reload(string _file)
80
	{
81
		if(_file != "") file = _file;
82
		mani.clear();
83
		if(!load(file, mani))
84
			return false;
85
		Vec3f c(0,0,0);
86
		float r = 5;
87
		mani.get_bsphere(c,r);
88
		view_ctrl.set_centre(c);
89
		view_ctrl.set_eye_dist(2*r);
90
		return true;
91
	}
92
 
93
	VisObj():
94
	file(""), view_ctrl(WINX,WINY, Vec3f(0), 1.0), display_list(glGenLists(1)), create_display_list(true), harmonics(0) 
95
	{
96
	}
97
 
98
	void display(bool wire, bool harm, bool flat)
99
	{
395 jab 100
/*		static Timer tim;
101
		tim.start();*/
391 jab 102
		if(create_display_list)
103
		{
104
			create_display_list = false;
105
 
106
			glNewList(display_list,GL_COMPILE);
107
			if(wire)
108
			{
395 jab 109
				draw_as_wire(mani,false);
391 jab 110
				glUseProgram(0);	
111
			}
112
			else if(harm)
113
				harmonics->draw();
114
			else 
115
				draw(mani,!flat);
116
			glEndList();
117
		}
118
		view_ctrl.set_gl_modelview();
119
		glCallList(display_list);
395 jab 120
		// tim.get_secs();
391 jab 121
	}
122
 
123
 
124
	void post_create_display_list()
125
	{
126
		create_display_list = true;
127
	}
128
 
129
	void harmonics_analyze_mesh()
130
	{
131
		delete harmonics;
132
		harmonics = new Harmonics(mani);
133
	}
134
 
135
	void harmonics_reset_shape()
136
	{
137
		if(harmonics)
138
			harmonics->reset_shape();
139
	}
140
 
141
	void harmonics_parse_key(unsigned char key)
142
	{
143
		harmonics->parse_key(key);
144
	}
145
 
146
	void harmonics_partial_reconstruct(int eig0, int eig1, float scale)
147
	{
148
		if(harmonics)
149
			harmonics->partial_reconstruct(eig0, eig1, scale);
150
	}
151
 
152
};
153
 
154
inline VisObj& get_vis_obj(int i)
155
{
156
	static VisObj vo[9];
157
	return vo[i];
158
}
159
 
160
inline VisObj& avo()
161
{
162
	static CVar<int> active("active_mesh",0);
163
	return get_vis_obj(active);
164
}
165
 
166
inline Manifold& active_mesh()
167
{
168
	return avo().mesh();
169
}
170
 
171
inline GLViewController& active_view_control()
172
{
173
	return avo().view_control();
174
}
175
 
386 jab 176
// Single global instance so glut can get access
177
GLConsole theConsole;
178
 
179
////////////////////////////////////////////////////////////////////////////////
180
char* ConsoleHelp(std::vector<std::string> &args)
181
{
182
    theConsole.Printf("");
183
    theConsole.Printf("----------------- HELP -----------------");
391 jab 184
    theConsole.Printf("Press ESC key to open and close console");
386 jab 185
    theConsole.Printf("Press TAB to see the available commands and functions");
186
    theConsole.Printf("Functions are shown in green and variables in yellow");
187
    theConsole.Printf("Setting a value: [command] = value");
188
    theConsole.Printf("Getting a value: [command]");
189
    theConsole.Printf("Functions: [function] [arg1] [arg2] ...");
391 jab 190
    theConsole.Printf("Entering arg1=? or arg1=help will give a description.");
386 jab 191
    theConsole.Printf("History: Up and Down arrow keys move through history.");
192
    theConsole.Printf("Tab Completion: TAB does tab completion and makes suggestions.");
391 jab 193
    theConsole.Printf("");
194
    theConsole.Printf("Keyboard commands (when console is not active):");
195
    theConsole.Printf("w   : toggle wireframe");
196
    theConsole.Printf("f   : toggle flatshading");
197
    theConsole.Printf("1-9 : switch between active meshes.");
395 jab 198
    theConsole.Printf("d   : (display.show_harmonics = 1) diffuse light on and off");
199
    theConsole.Printf("h   : (display.show_harmonics = 1) highlight on and off ");
200
    theConsole.Printf("+/- : (display.show_harmonics = 1) which eigenvector to show");
391 jab 201
    theConsole.Printf("q   : quit program");
202
    theConsole.Printf("ESC : open console");
203
    theConsole.Printf("");
204
    theConsole.Printf("Mouse: Left button rotates, middle zooms, right pans");
386 jab 205
    theConsole.Printf("----------------- HELP -----------------");
206
    theConsole.Printf("");
207
    return "";
208
}
209
 
391 jab 210
bool wantshelp(std::vector<std::string> &args)
211
{
212
	if(args.size()==0) return false;
213
	string str = args[0];
214
	if(str=="help" || str=="HELP" || str=="Help" || str=="?") return true;
215
	return false;
216
}
386 jab 217
 
391 jab 218
/// Function that aligns two meshes.
219
char* console_align(std::vector<std::string> &args)
220
{
221
	if(wantshelp(args)) 
222
		{
223
			theConsole.Printf("usage: align <dest> <src>");
224
			theConsole.Printf("This function aligns dest mesh with src");
225
			theConsole.Printf("In practice the GLViewController of src is copied to dst.");
226
			theConsole.Printf("both arguments are mandatory and must be numbers between 1 and 9.");
227
			theConsole.Printf("Note that results might be unexpexted if the meshes are not on the same scale");
228
			return "";
229
		}
386 jab 230
 
391 jab 231
	int dest = 0;
232
	if(args.size()>0)
233
	{
234
		istringstream a0(args[0]);
235
		a0 >> dest;
236
		--dest;
237
		if(dest <0 || dest>8) return "dest mesh out of range (1-9)";
238
	}
239
	else return "neither source nor destination mesh?!";
240
	int src = 0;
241
	if(args.size()>1)
242
	{
243
		istringstream a1(args[1]);
244
		a1 >> src;
245
		--src;
246
		if(src <0 || src>8) return "src mesh out of range (1-9)";
247
	}	
248
	else return "no src mesh?";
386 jab 249
 
391 jab 250
	get_vis_obj(dest).view_control() = get_vis_obj(src).view_control();
251
 
252
	return "";
386 jab 253
}
254
 
391 jab 255
 
388 jab 256
char* console_save(std::vector<std::string> &args)
257
{
391 jab 258
	if(wantshelp(args)) 
259
		{
260
			theConsole.Printf("usage: save <name.x3d|name.obj> ");
261
			return "";
262
		}
388 jab 263
	string& file_name = args[0];
264
	if(args.size() == 1)
265
	{
266
		if(file_name.substr(file_name.length()-4,file_name.length())==".obj")
267
		{
391 jab 268
			obj_save(file_name, active_mesh());
388 jab 269
			return "";
270
		}
271
		else if(file_name.substr(file_name.length()-4,file_name.length())==".x3d")
272
		{
391 jab 273
			x3d_save(file_name, active_mesh());
388 jab 274
			return "";
275
		}
276
		return "unknown format";
277
	}
278
	return "usage: save <name.x3d|name.obj> ";
279
}
386 jab 280
 
388 jab 281
char* console_refine_edges(std::vector<std::string> &args)
282
{
391 jab 283
	if(wantshelp(args)) 
284
		{
285
			theConsole.Printf("usage: refine.split_edges <length>");
286
			theConsole.Printf("splits edges longer than <length>; default is 0.5 times average length");
287
			return "";
288
		}
289
 
388 jab 290
	float thresh = 0.5;
291
	if(args.size()>0)
292
	{
293
		istringstream a0(args[0]);
294
		a0 >> thresh;
295
	}
391 jab 296
	float avg_length = average_edge_length(active_mesh());
297
	refine_edges(active_mesh(), thresh * avg_length);
388 jab 298
	return "";
391 jab 299
 
388 jab 300
}
301
 
302
char* console_refine_faces(std::vector<std::string> &args)
303
{
391 jab 304
	if(wantshelp(args)) 
305
		{
306
			theConsole.Printf("usage: refine.split_faces ");
307
			theConsole.Printf("usage:  Takes no arguments. Inserts a vertex at the centre of each face.");
308
			return "";
309
		}
310
 
311
	safe_triangulate(active_mesh());
388 jab 312
	return "";
391 jab 313
 
388 jab 314
}
315
 
316
char* console_cc_subdivide(std::vector<std::string> &args)
317
{
391 jab 318
	if(wantshelp(args)) 
319
		{
320
			theConsole.Printf("usage: refine.catmull_clark ");
321
			theConsole.Printf("Splits each polygon into four (Catmull Clark style)");
322
			return "";
323
		}
324
	cc_split(active_mesh(),active_mesh());
388 jab 325
	return "";
326
}
327
 
395 jab 328
char* console_dual(std::vector<std::string> &args)
329
{
330
	if(wantshelp(args)) 
331
	{
332
		theConsole.Printf("usage: dual ");
333
		theConsole.Printf("Produces the dual by converting each face to a vertex placed at the barycenter.");
334
		return "";
335
	}
336
 
337
	Manifold& m = active_mesh();
338
 
339
	// make sure every face knows its number
340
	m.enumerate_faces();
341
 
342
	vector<Vec3f> vertices(m.no_faces());
343
	vector<int> faces(m.no_vertices());
344
	vector<int> indices;
345
 
346
	// Create new vertices. Each face becomes a vertex whose position
347
	// is the centre of the face
348
	int i=0;
349
	for(FaceIter f=m.faces_begin(); f!=m.faces_end(); ++f,++i)
350
		vertices[i] = centre(f);
351
 
352
	// Create new faces. Each vertex is a new face with N=valency of vertex
353
	// edges.
354
	i=0;
355
	for(VertexIter v=m.vertices_begin(); v!= m.vertices_end(); ++v,++i)
356
	{
357
		VertexCirculator vc(v);
358
		vector<int> index_tmp;
359
		for(; !vc.end(); ++vc)
360
			index_tmp.push_back(vc.get_face()->touched);
361
 
362
		// Push vertex indices for this face onto indices vector.
363
		// The circulator moves around the face in a clockwise fashion
364
		// so we just reverse the ordering.
365
		indices.insert(indices.end(), index_tmp.rbegin(), index_tmp.rend());
366
 
367
		// Insert face valency in the face vector.
368
		faces[i] = vc.no_steps();
369
	}
370
 
371
	// Clear the manifold before new geometry is inserted.
372
	m.clear();
373
 
374
	// And build
375
	build_manifold(m, vertices.size(), &vertices[0], faces.size(),
376
				   &faces[0],&indices[0]);
377
 
378
	return "";
379
}
388 jab 380
 
381
 
387 jab 382
char* console_minimize_curvature(std::vector<std::string> &args)
383
{
391 jab 384
	if(wantshelp(args)) 
385
		{
386
			theConsole.Printf("usage: optimize.minimize_curvature <anneal>");
387
			theConsole.Printf("Flip edges to minimize mean curvature.");
388
			theConsole.Printf("If anneal is true, simulated annealing (slow) is used rather than a greedy scheme");
389
			return "";
390
		}
387 jab 391
	bool anneal=false;
392
	if(args.size()>0)
393
	{
394
		istringstream a0(args[0]);
395
		a0 >> anneal;
396
	}
391 jab 397
 
398
	minimize_curvature(active_mesh(), anneal);
399
	avo().post_create_display_list();
387 jab 400
	return "";
401
}
402
 
403
char* console_minimize_dihedral(std::vector<std::string> &args)
404
{
391 jab 405
	if(wantshelp(args)) 
406
		{
407
			theConsole.Printf("usage: optimize.minimize_dihedral <iter> <anneal> <use_alpha> <gamma> ");
408
			theConsole.Printf("Flip edges to minimize dihedral angles.");
409
			theConsole.Printf("Iter is the max number of iterations. anneal tells us whether to use ");
410
			theConsole.Printf("simulated annealing and not greedy optimization. use_alpha (default=true) ");
411
			theConsole.Printf("means to use angle and not cosine of anglegamma (default=4) is the power ");
412
			theConsole.Printf("to which we raise the dihedral angle");
413
			return "";
414
		}
387 jab 415
	int iter = 1000;
416
	if(args.size()>0)
417
	{
418
		istringstream a0(args[0]);
419
		a0 >> iter;
420
	}
391 jab 421
 
387 jab 422
	bool anneal = false;
423
	if(args.size()>1)
424
	{
425
		istringstream a0(args[0]);
426
		a0 >> anneal;
427
	}
391 jab 428
 
387 jab 429
	bool use_alpha = true;
388 jab 430
	if(args.size()>2)
387 jab 431
	{
432
		istringstream a0(args[0]);
433
		a0 >> use_alpha;
434
	}
391 jab 435
 
387 jab 436
	float gamma = 4.0;
437
	if(args.size()>3)
438
	{
439
		istringstream a0(args[0]);
440
		a0 >> gamma;
441
	}
442
 
443
 
391 jab 444
	minimize_dihedral_angle(active_mesh(), iter, anneal, use_alpha, gamma);
387 jab 445
	return "";
446
}
447
 
388 jab 448
char* console_maximize_min_angle(std::vector<std::string> &args)
449
{
391 jab 450
	if(wantshelp(args)) 
451
		{
452
			theConsole.Printf("usage: optimize.maximize_min_angle <thresh> <anneal>");
453
			theConsole.Printf("Flip edges to maximize min angle - to make mesh more Delaunay.");
454
			theConsole.Printf("If the dot product of the normals between adjacent faces < thresh");
455
			theConsole.Printf("no flip will be made. anneal selects simulated annealing rather ");
456
			theConsole.Printf("nthan greedy optimization.");
457
			return "";
458
		}
388 jab 459
	float thresh=0.0;
460
	if(args.size()>0)
461
	{
462
		istringstream a0(args[0]);
463
		a0 >> thresh;
464
	}
465
	bool anneal=false;
466
	if(args.size()>1)
467
	{
468
		istringstream a0(args[0]);
469
		a0 >> anneal;
470
	}
391 jab 471
	maximize_min_angle(active_mesh(),thresh,anneal);
388 jab 472
	return "";
473
}
474
 
475
 
387 jab 476
char* console_optimize_valency(std::vector<std::string> &args)
477
{
391 jab 478
	if(wantshelp(args)) 
479
		{
480
			theConsole.Printf("usage: optimize.valency <anneal> ");
481
			theConsole.Printf("Optimizes valency for triangle meshes. Anneal selects simulated annealing rather than greedy optim.");
482
			return "";
483
		}
387 jab 484
	bool anneal=false;
485
	if(args.size()>0)
486
	{
487
		istringstream a0(args[0]);
488
		a0 >> anneal;
489
	}
391 jab 490
	optimize_valency(active_mesh(), anneal);
387 jab 491
	return "";
492
}
493
 
388 jab 494
char* console_analyze(std::vector<std::string> &args)
495
{
391 jab 496
	if(wantshelp(args)) 
497
		{
498
			theConsole.Printf("usage:  harmonics.analyze");
499
			theConsole.Printf("Creates the Laplace Beltrami operator for the mesh and finds all eigensolutions.");
500
			theConsole.Printf("It also projects the vertices onto the eigenvectors - thus transforming the mesh");
501
			theConsole.Printf("to this basis.");
502
			theConsole.Printf("Note that this will stall the computer for a large mesh - as long as we use Lapack.");
503
			return "";
504
		}
505
	avo().harmonics_analyze_mesh();
388 jab 506
	return "";
507
}
508
 
509
 
386 jab 510
char* console_partial_reconstruct(std::vector<std::string> &args)
511
{
391 jab 512
	if(wantshelp(args)) 
513
		{
514
			theConsole.Printf("usage: haramonics.partial_reconstruct <e0> <e1> <s>");
515
			theConsole.Printf("Reconstruct from projections onto eigenvectors. The two first arguments indicate");
516
			theConsole.Printf("the eigenvector interval that we reconstruct from. The last argument is the ");
517
			theConsole.Printf("scaling factor. Thus, for a vertex, v, the formula for computing the position, p, is:");
518
			theConsole.Printf("for (i=e0; i<=e1;++i) p += proj[i] * Q[i][v] * s;");
519
			theConsole.Printf("where proj[i] is the 3D vector containing the x, y, and z projections of the mesh onto");
520
			theConsole.Printf("eigenvector i. Q[i][v] is the v'th coordinate of the i'th eigenvector.");
521
			theConsole.Printf("Note that if vertex coordinates are not first reset, the result is probably unexpected.");
522
			return "";
523
		}
386 jab 524
	int E0,E1;
525
	float scale;
526
	istringstream a0(args[0]);
527
	a0 >> E0;
528
	istringstream a1(args[1]);
529
	a1 >> E1;
530
	istringstream a2(args[2]);
531
	a2 >> scale;
391 jab 532
	avo().harmonics_partial_reconstruct(E0,E1,scale);
386 jab 533
	return "";
534
}
535
 
536
char* console_reset_shape(std::vector<std::string> &args)
537
{
391 jab 538
	if(wantshelp(args)) 
539
		{
540
			theConsole.Printf("usage: harmonics.reset_shape ");
541
			theConsole.Printf("Simply sets all vertices to 0,0,0. Call this before doing partial_reconstruct");
542
			theConsole.Printf("unless you know what you are doing.");
543
			return "";
544
		}
545
	avo().harmonics_reset_shape();
386 jab 546
	return "";
547
}
548
 
549
 
388 jab 550
char* console_close_holes(std::vector<std::string> &args)
551
{
391 jab 552
	if(wantshelp(args)) 
553
		{
554
			theConsole.Printf("usage: cleanup.close_holes");
555
			theConsole.Printf("This function closes holes. It simply follows the loop of halfvectors which");
556
			theConsole.Printf("enclose the hole and add a face to which they all point.");
557
			return "";
558
		}
559
	close_holes(active_mesh());
388 jab 560
	return "";
561
}
386 jab 562
 
388 jab 563
char* console_reload(std::vector<std::string> &args)
564
{
391 jab 565
	if(wantshelp(args)) 
566
		{
567
			theConsole.Printf("usage:  reload <file>");
568
			theConsole.Printf("Reloads the current file if no argument is given, but");
569
			theConsole.Printf("if an argument is given, then that becomes the current file");
570
			return "";
571
		}
572
	if(!avo().reload(args.size()>0 ? args[0]:""))
573
		return "failed to load";
388 jab 574
	return "";
575
}
576
 
577
 
387 jab 578
char* console_simplify(std::vector<std::string> &args)
579
{
391 jab 580
	if(wantshelp(args)) 
581
		{
582
			theConsole.Printf("usage: simplify <fraction> ");
583
			theConsole.Printf("Performs Garland Heckbert (quadric based) mesh simplification.");
584
			theConsole.Printf("The only argument is the fraction of vertices to keep.");
585
			return "";
586
		}
387 jab 587
	float keep_fraction;
588
	if(args.size()==0) return "you must specify fraction of vertices to keep";
589
	istringstream a0(args[0]);
590
	a0 >> keep_fraction;
391 jab 591
 
387 jab 592
	Vec3f p0, p7;
391 jab 593
	active_mesh().get_bbox(p0, p7);
387 jab 594
	Vec3f d = p7-p0;
595
	float s = 1.0/d.max_coord();
596
	Vec3f pcentre = (p7+p0)/2.0;
391 jab 597
	for(VertexIter vi = active_mesh().vertices_begin(); vi != active_mesh().vertices_end(); ++vi)
387 jab 598
		vi->pos = (vi->pos - pcentre) * s;
391 jab 599
	quadric_simplify(active_mesh(),keep_fraction,0.0001f,true);
600
	for(VertexIter vi = active_mesh().vertices_begin(); vi != active_mesh().vertices_end(); ++vi)
387 jab 601
		vi->pos = vi->pos*d.max_coord() + pcentre;
602
	return "";
603
}
604
 
391 jab 605
char* console_vertex_noise(std::vector<std::string> &args)
606
{
607
	if(wantshelp(args)) 
608
		{
609
			theConsole.Printf("usage: noise.perturb_vertices <amplitude>");
610
			theConsole.Printf("adds a random vector to each vertex. To ensure uniformness, the vector must lie in the");
611
			theConsole.Printf("unit sphere. The length of the vector is multiplied by the average edge length and then amplitude");
612
			return "";
613
		}
614
	float avg_length = average_edge_length(active_mesh());
615
 
616
	float noise_amplitude = 0.5;
617
	if(args.size()>0) 
618
	{
619
		istringstream a0(args[0]);
620
		a0 >> noise_amplitude;
621
	}
622
 
623
	srand(0);
624
	for(VertexIter vi = active_mesh().vertices_begin(); vi != active_mesh().vertices_end(); ++vi)
625
	{
626
		Vec3f v;
627
		do {
628
			v = Vec3f(rand(),rand(),rand());
629
			v /= RAND_MAX;
630
		} while(sqr_length(v) > 1.0);
631
		v -= Vec3f(0.5);
632
		v *= 2.0;
633
		v *= noise_amplitude;
634
		v *= avg_length;
635
		vi->pos += v;
636
	}		
637
	return "";
638
}
639
 
640
char* console_noisy_flips(std::vector<std::string> &args)
641
{
642
	if(wantshelp(args)) 
643
		{
644
			theConsole.Printf("usage:  noise.perturb_topology <iter>");
645
			theConsole.Printf("Perform random flips. iter (default=1) is the number of iterations.");
646
			theConsole.Printf("mostly for making nasty synthetic test cases.");
647
			return "";
648
		}
649
	int iter=1;
650
	if(args.size()>0)
651
	{
652
		istringstream a0(args[0]);
653
		a0 >> iter;
654
	}
655
 
656
	randomize_mesh(active_mesh(),  iter);
657
	return "";
658
}
659
 
387 jab 660
char* console_laplacian_smooth(std::vector<std::string> &args)
661
{
391 jab 662
	if(wantshelp(args)) 
663
		{
664
			theConsole.Printf("usage:  smooth.laplacian <weight>");
665
			theConsole.Printf("Perform Laplacian smoothing. weight is the scaling factor for the Laplacian.");
666
			return "";
667
		}
387 jab 668
	float t=1.0;
669
	if(args.size()>0)
670
	{
671
		istringstream a0(args[0]);
672
		a0 >> t;
673
	}
674
	/// Simple laplacian smoothing with an optional weight.
391 jab 675
	laplacian_smooth(active_mesh(), t);
387 jab 676
	return "";
677
}
678
 
679
char* console_taubin_smooth(std::vector<std::string> &args)
680
{
391 jab 681
	if(wantshelp(args)) 
682
		{
683
			theConsole.Printf("usage:  smooth.taubin <iter>");
684
			theConsole.Printf("Perform Taubin smoothing. iter (default=1) is the number of iterations.");
685
			return "";
686
		}
387 jab 687
	int iter=1;
688
	if(args.size()>0)
689
	{
690
		istringstream a0(args[0]);
691
		a0 >> iter;
692
	}
693
 
694
	/// Taubin smoothing is similar to laplacian smoothing but reduces shrinkage
391 jab 695
	taubin_smooth(active_mesh(),  iter);
387 jab 696
	return "";
697
}
698
 
699
char* console_fvm_smooth(std::vector<std::string> &args)
700
{	
391 jab 701
	if(wantshelp(args)) 
702
		{
703
			theConsole.Printf("usage: smooth.fuzzy_vector_median <iter>");
704
			theConsole.Printf("Smooth normals using fuzzy vector median smoothing. iter (default=1) is the number of iterations");
705
			theConsole.Printf("This function does a very good job of preserving sharp edges.");
706
			return "";
707
		}
387 jab 708
	int iter=1;
709
	if(args.size()>0)
710
	{
711
		istringstream a0(args[0]);
712
		a0 >> iter;
713
	}
714
	/** Fuzzy vector median smoothing is effective when it comes to
715
	 preserving sharp edges. */
391 jab 716
	fvm_smooth(active_mesh(),  iter);
387 jab 717
	return "";
391 jab 718
 
387 jab 719
}
720
 
388 jab 721
char* console_triangulate(std::vector<std::string> &args)
722
{	
391 jab 723
	if(wantshelp(args)) 
724
		{
725
			theConsole.Printf("usage:  triangulate");
726
			theConsole.Printf("This function triangulates all non triangular faces of the mesh.");
727
			theConsole.Printf("you may want to call it after hole closing. For a polygon it simply connects");
728
			theConsole.Printf("the two closest vertices in a recursive manner until only triangles remain");
729
			return "";
730
		}
731
	shortest_edge_triangulate(active_mesh());
388 jab 732
	return "";
733
}
734
 
735
 
736
char* console_remove_caps(std::vector<std::string> &args)
737
{	
391 jab 738
	if(wantshelp(args)) 
739
		{
740
			theConsole.Printf("usage:  cleanup.remove_caps thresh");
741
			theConsole.Printf("Remove caps (triangles with one very big angle). The thresh argument is the fraction of PI to");
742
			theConsole.Printf("use as threshold for big angle. Default is 0.85. Caps are removed by flipping.");
743
			return "";
744
		}
745
	float t=0.85;
746
	if(args.size()>0)
747
	{
748
		istringstream a0(args[0]);
749
		a0 >> t;
750
	}
751
 
752
	remove_caps_from_trimesh(active_mesh(), static_cast<float>(M_PI) *t);
388 jab 753
	return "";
754
}
755
 
756
char* console_remove_needles(std::vector<std::string> &args)
757
{	
391 jab 758
	if(wantshelp(args)) 
759
		{
760
			theConsole.Printf("usage: cleanup.remove_needles <thresh>");
761
			theConsole.Printf("Removes very short edges by collapse. thresh is multiplied by the average edge length");
762
			theConsole.Printf("to get the length shorter than which we collapse. Default = 0.1");
763
			return "";
764
		}
388 jab 765
	float thresh = 0.1;
766
	if(args.size()>0)
767
	{
768
		istringstream a0(args[0]);
769
		a0 >> thresh;
770
	}
391 jab 771
	float avg_length = average_edge_length(active_mesh());
772
	remove_needles_from_trimesh(active_mesh(), thresh * avg_length);
388 jab 773
	return "";
774
}
775
 
391 jab 776
void reshape(int W, int H)
777
{
778
	active_view_control().reshape(W,H);
779
}
780
 
386 jab 781
void display() 
782
{
783
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
784
 
388 jab 785
	static CVar<int> display_wireframe("display.wireframe",0);
395 jab 786
	static CVar<int> display_eigenmodes("display.show_harmonics",0);
388 jab 787
	static CVar<int> display_flat("display.flatshading",0);
386 jab 788
 
789
	glPushMatrix();
790
 
391 jab 791
	avo().display(display_wireframe, display_eigenmodes, display_flat);
386 jab 792
 
793
	glPopMatrix();
794
 
795
	glUseProgram(0);
796
	theConsole.RenderConsole();
797
 
798
	glutSwapBuffers();
799
}
800
 
801
void animate() 
802
{	
395 jab 803
	//usleep( (int)1e4 );
391 jab 804
	active_view_control().try_spin();
386 jab 805
	glutPostRedisplay();
806
}
807
 
808
 
809
void mouse(int button, int state, int x, int y) 
810
{
811
	Vec2i pos(x,y);
812
	if (state==GLUT_DOWN) 
813
	{
814
		if (button==GLUT_LEFT_BUTTON) 
391 jab 815
			active_view_control().grab_ball(ROTATE_ACTION,pos);
386 jab 816
		else if (button==GLUT_MIDDLE_BUTTON) 
391 jab 817
			active_view_control().grab_ball(ZOOM_ACTION,pos);
386 jab 818
		else if (button==GLUT_RIGHT_BUTTON) 
391 jab 819
			active_view_control().grab_ball(PAN_ACTION,pos);
386 jab 820
	}
821
	else if (state==GLUT_UP)
391 jab 822
		active_view_control().release_ball();
386 jab 823
}
824
 
825
void motion(int x, int y) {
826
	Vec2i pos(x,y);
391 jab 827
	active_view_control().roll_ball(Vec2i(x,y));
386 jab 828
}
829
 
830
void keyboard_spec(int key, int x, int y)
831
{
391 jab 832
	int mod = glutGetModifiers();
833
	if( theConsole.isOpen() ) {
834
		// If shift held, scroll the console
835
		if( mod == GLUT_ACTIVE_SHIFT ) {
836
			switch (key){
837
				case GLUT_KEY_UP:
838
					theConsole.ScrollDownLine();
839
					break;
840
				case GLUT_KEY_DOWN: 
841
					theConsole.ScrollUpLine();
842
					break;
843
			}
844
		} else {
845
			theConsole.StandardKeyBindings( key );
846
		}
847
	}
386 jab 848
}
849
 
850
template<typename T>
851
T& get_CVar_ref(const std::string& s)
852
{
853
	return *reinterpret_cast<T*> (GetCVarData(s));
854
}
855
 
856
void keyboard(unsigned char key, int x, int y) 
857
{	
858
	if(theConsole.isOpen())
391 jab 859
	{
386 jab 860
		switch(key) {
861
			case '\033': 
862
				theConsole.ToggleConsole();
863
			default:      
864
				//send keystroke to console
865
				if( theConsole.isOpen() ){
866
					theConsole.EnterCommandCharacter(key);
867
				}
868
				break;
388 jab 869
		}
391 jab 870
		if(key == 13)	avo().post_create_display_list();
871
 
872
	}	
386 jab 873
	else {
874
		int& display_wireframe = get_CVar_ref<int>("display.wireframe");
388 jab 875
		int& display_flat = get_CVar_ref<int>("display.flatshading");
391 jab 876
		int& active  = get_CVar_ref<int>("active_mesh");
386 jab 877
 
391 jab 878
 
386 jab 879
		switch(key) {
880
			case 'q': exit(0);
881
			case '\033':
882
				theConsole.ToggleConsole();
883
				break;
391 jab 884
			case '1':
885
			case '2':
886
			case '3':
887
			case '4':
888
			case '5':
889
			case '6':
890
			case '7':
891
			case '8':
892
			case '9':
893
				active = key - '1'; break;
894
			case 'f': display_flat = !display_flat; break;
386 jab 895
			case 'w':
896
				display_wireframe = !display_wireframe;
897
				break;
898
		}
391 jab 899
 
395 jab 900
		if(get_CVar_ref<int>("display.show_harmonics"))
391 jab 901
			avo().harmonics_parse_key(key);
902
 
903
		avo().post_create_display_list();		
386 jab 904
	}
905
}
906
 
907
void init_glut(int argc, char** argv)
908
{
909
	glutInitDisplayMode(GLUT_RGBA|GLUT_DOUBLE|GLUT_DEPTH);
910
	glutInitWindowSize(WINX, WINY);
911
	glutInit(&argc, argv);
912
	glutCreateWindow("Shape Harmonics");
913
	glutDisplayFunc(display);
914
	glutKeyboardFunc(keyboard);
915
	glutSpecialFunc(keyboard_spec);
916
	glutReshapeFunc(reshape);
917
	glutMouseFunc(mouse);
918
	glutMotionFunc(motion);
919
	glutIdleFunc(animate);
920
}
921
 
922
void init_gl()
923
{
924
	glewInit();
925
	glEnable(GL_LIGHTING);
926
	glEnable(GL_LIGHT0);
388 jab 927
	glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, 1);
386 jab 928
 
929
	initialize_wireframe_shaders();
930
 
931
 
932
	// Set the value of a uniform
933
	//glUniform2f(glGetUniformLocation(prog_P0,"WIN_SCALE"), win_size_x/2.0, win_size_y/2.0);
934
 
935
	glMatrixMode(GL_MODELVIEW);
936
	glLoadIdentity();
937
	glClearColor(0.50f, 0.50f, 0.50f, 0.f);
938
	glColor4f(1.0f, 1.0f, 1.0f, 0.f);
939
	glEnable(GL_DEPTH_TEST);
940
 
941
	static CVar<ConsoleFunc> help( "help", ConsoleHelp );
391 jab 942
	static CVar<ConsoleFunc> rs("harmonics.reset_shape", console_reset_shape);
943
	static CVar<ConsoleFunc> ha("harmonics.analyze", console_analyze);
944
	static CVar<ConsoleFunc> pr("harmonics.partial_reconstruct", console_partial_reconstruct);
387 jab 945
	static CVar<ConsoleFunc> simpl("simplify", console_simplify);
391 jab 946
	static CVar<ConsoleFunc> lsmooth("smooth.laplacian", console_laplacian_smooth);
947
	static CVar<ConsoleFunc> tsmooth("smooth.taubin", console_taubin_smooth);
948
	static CVar<ConsoleFunc> fsmooth("smooth.fuzzy_vector_median", console_fvm_smooth);
949
 
950
	static CVar<ConsoleFunc> opt_val("optimize.valency", console_optimize_valency);
951
	static CVar<ConsoleFunc> min_dih("optimize.minimize_dihedral_angles", console_minimize_dihedral);
952
	static CVar<ConsoleFunc> min_curv("optimize.minimize_curvature", console_minimize_curvature);
953
	static CVar<ConsoleFunc> max_min_angle("optimize.maximize_min_angle", console_maximize_min_angle);
954
	static CVar<ConsoleFunc> close_holes_fun("cleanup.close_holes", console_close_holes);
388 jab 955
	static CVar<ConsoleFunc> reload_fun("reload", console_reload);
391 jab 956
 
957
	static CVar<ConsoleFunc> rem_caps_fun("cleanup.remove_caps", console_remove_caps);
958
	static CVar<ConsoleFunc> rem_needles_fun("cleanup.remove_needles", console_remove_needles);
388 jab 959
	static CVar<ConsoleFunc> triangulate_fun("triangulate", console_triangulate);
391 jab 960
	static CVar<ConsoleFunc> refine_fun("refine.split_edges", console_refine_edges);
961
	static CVar<ConsoleFunc> refine_face_fun("refine.split_faces", console_refine_faces);
962
	static CVar<ConsoleFunc> subd_fun("refine.catmull_clark", console_cc_subdivide);
388 jab 963
	static CVar<ConsoleFunc> save_fun("save", console_save);
391 jab 964
	static CVar<ConsoleFunc> noise_fun("noise.perturb_vertices", console_vertex_noise);
965
	static CVar<ConsoleFunc> noise_fun2("noise.perturb_topology", console_noisy_flips);
966
 
395 jab 967
	static CVar<ConsoleFunc> dualize("dual", console_dual);
968
 
391 jab 969
	static CVar<ConsoleFunc> align_fun("align", console_align);
387 jab 970
 
971
 
386 jab 972
}
973
 
974
int main(int argc, char** argv)
975
{
976
	ArgExtracter ae(argc, argv);
391 jab 977
 
978
	init_glut(argc,argv);
979
	init_gl();
980
 
981
	Harmonics::init();
982
 
983
		if(argc>1)
386 jab 984
	{		
391 jab 985
		string file = ae.get_last_arg();
986
		avo().reload(file);
386 jab 987
	}
988
 
989
 
990
	glutMainLoop();
991
}
992
 
993