Subversion Repositories gelsvn

Rev

Rev 399 | Rev 409 | Go to most recent revision | Only display areas with differences | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 399 Rev 403
1
/*
1
/*
2
 *  harmonics.cpp
2
 *  harmonics.cpp
3
 *  GEL
3
 *  GEL
4
 *
4
 *
5
 *  Created by J. Andreas Bærentzen on 01/09/08.
5
 *  Created by J. Andreas Bærentzen on 01/09/08.
6
 *  Copyright 2008 __MyCompanyName__. All rights reserved.
6
 *  Copyright 2008 __MyCompanyName__. All rights reserved.
7
 *
7
 *
8
 */
8
 */
9
 
9
 
10
#include <iostream>
10
#include <iostream>
11
#include <CGLA/Vec3f.h>
11
#include <CGLA/Vec3f.h>
12
#include <CGLA/Vec3d.h>
12
#include <CGLA/Vec3d.h>
13
#include <LinAlg/Matrix.h>
13
#include <LinAlg/Matrix.h>
14
#include <LinAlg/Vector.h>
14
#include <LinAlg/Vector.h>
15
#include <LinAlg/LapackFunc.h>
15
#include <LinAlg/LapackFunc.h>
16
 
16
 
17
#include <GL/glew.h>
17
#include <GL/glew.h>
18
#include <GLGraphics/glsl_shader.h>
18
#include <GLGraphics/glsl_shader.h>
19
 
19
 
20
#include <HMesh/Manifold.h>
20
#include <HMesh/Manifold.h>
21
#include <HMesh/VertexCirculator.h>
21
#include <HMesh/VertexCirculator.h>
22
#include <HMesh/FaceCirculator.h>
22
#include <HMesh/FaceCirculator.h>
23
#include <HMesh/build_manifold.h>
23
#include <HMesh/build_manifold.h>
24
#include <HMesh/mesh_optimization.h>
24
#include <HMesh/mesh_optimization.h>
25
#include <HMesh/triangulate.h>
25
#include <HMesh/triangulate.h>
26
#include <HMesh/load.h>
26
#include <HMesh/load.h>
27
#include <HMesh/x3d_save.h>
27
#include <HMesh/x3d_save.h>
28
 
28
 
29
#include <GLConsole/GLConsole.h>
29
#include <GLConsole/GLConsole.h>
30
 
30
 
31
#include "harmonics.h"
31
#include "harmonics.h"
32
 
32
 
33
using namespace CGLA;
33
using namespace CGLA;
34
using namespace std;
34
using namespace std;
35
using namespace HMesh;
35
using namespace HMesh;
36
using namespace Geometry;
36
using namespace Geometry;
37
using namespace GLGraphics;
37
using namespace GLGraphics;
38
using namespace LinAlg;
38
using namespace LinAlg;
39
 
39
 
40
bool Harmonics::is_initialized=false;
40
bool Harmonics::is_initialized=false;
41
GLuint Harmonics::prog_P0;
41
GLuint Harmonics::prog_P0;
42
 
42
 
43
 
43
 
44
namespace
44
namespace
45
{
45
{
46
 
46
 
47
	string vss =
47
	string vss =
48
"#version 120\n"
48
"#version 120\n"
49
"#extension GL_EXT_gpu_shader4 : enable\n"
49
"#extension GL_EXT_gpu_shader4 : enable\n"
50
"	\n"
50
"	\n"
51
"	\n"
51
"	\n"
52
"	attribute float eigenvalue;\n"
52
"	attribute float eigenvalue;\n"
53
"	attribute float eigenvalue2;\n"
53
"	attribute float eigenvalue2;\n"
54
"	varying vec3 normal;\n"
54
"	varying vec3 normal;\n"
55
"	varying float eig;\n"
55
"	varying float eig;\n"
56
"	varying float eig2;\n"
56
"	varying float eig2;\n"
57
"	\n"
57
"	\n"
58
"	void main(void)\n"
58
"	void main(void)\n"
59
"	{\n"
59
"	{\n"
60
"		gl_Position =  ftransform();\n"
60
"		gl_Position =  ftransform();\n"
61
"		normal = normalize(gl_NormalMatrix * gl_Normal);\n"
61
"		normal = normalize(gl_NormalMatrix * gl_Normal);\n"
62
"		eig = eigenvalue;\n"
62
"		eig = eigenvalue;\n"
63
"		eig2 = eigenvalue2;\n"
63
"		eig2 = eigenvalue2;\n"
64
"	}\n";
64
"	}\n";
65
	
65
	
66
string fss = 	
66
string fss = 	
67
"#version 120\n"
67
"#version 120\n"
68
"#extension GL_EXT_gpu_shader4 : enable\n"
68
"#extension GL_EXT_gpu_shader4 : enable\n"
69
"	\n"
69
"	\n"
70
"	varying vec3 normal;\n"
70
"	varying vec3 normal;\n"
71
"	varying float eig;\n"
71
"	varying float eig;\n"
72
"	varying float eig2;\n"
72
"	varying float eig2;\n"
73
"	uniform float eig_max;\n"
73
"	uniform float eig_max;\n"
74
"	uniform float eig_max2;\n"
74
"	uniform float eig_max2;\n"
75
"	uniform bool do_highlight;\n"
75
"	uniform bool do_highlight;\n"
76
"	uniform bool do_diffuse;\n"
76
"	uniform bool do_diffuse;\n"
77
"	const vec3 light_dir = vec3(0,0,1);\n"
77
"	const vec3 light_dir = vec3(0,0,1);\n"
78
"	\n"
78
"	\n"
79
"	void main()\n"
79
"	void main()\n"
80
"	{\n"
80
"	{\n"
81
"		float dot_ln = dot(light_dir, normal);\n"
81
"		float dot_ln = dot(light_dir, normal);\n"
82
"		\n"
82
"		\n"
83
"		float eig_norm = eig/eig_max;\n"
83
"		float eig_norm = eig/eig_max;\n"
84
"		float stripe_signal = 100 * eig_norm;\n"
84
"		float stripe_signal = 100 * eig_norm;\n"
85
"		vec4 stripe_col = abs(stripe_signal) < 3.14 ? vec4(1,1,0,0) : vec4(.1,.1,.1,0);\n"
85
"		vec4 stripe_col = abs(stripe_signal) < 3.14 ? vec4(1,1,0,0) : vec4(.1,.1,.1,0);\n"
86
"		\n"
86
"		\n"
87
"		gl_FragColor = eig_norm * vec4(-1,0,1,0);\n"
87
"		gl_FragColor = eig_norm * vec4(-1,0,1,0);\n"
88
"		if(do_diffuse)   gl_FragColor *= dot_ln;\n"
88
"		if(do_diffuse)   gl_FragColor *= dot_ln;\n"
89
"		if(do_highlight) gl_FragColor += dot_ln*dot_ln*dot_ln*dot_ln*dot_ln*dot_ln*dot_ln*vec4(.5,.5,.5,0);\n"
89
"		if(do_highlight) gl_FragColor += dot_ln*dot_ln*dot_ln*dot_ln*dot_ln*dot_ln*dot_ln*vec4(.5,.5,.5,0);\n"
90
"		gl_FragColor += stripe_col * smoothstep(0.8,1.0,cos(stripe_signal));\n"
90
"		gl_FragColor += stripe_col * smoothstep(0.8,1.0,cos(stripe_signal));\n"
91
"	}\n";
91
"	}\n";
92
	
92
	
93
	double voronoi_area(VertexIter v)
93
	double voronoi_area(VertexIter v)
94
	{
94
	{
95
	double area_mixed = 0;
95
	double area_mixed = 0;
96
	//For each triangle T from the 1-ring neighborhood of x
96
	//For each triangle T from the 1-ring neighborhood of x
97
	for(VertexCirculator vc(v); !vc.end(); ++vc)
97
	for(VertexCirculator vc(v); !vc.end(); ++vc)
98
	{
98
	{
99
		FaceIter f = vc.get_face();
99
		FaceIter f = vc.get_face();
100
		double f_area = area(f);
100
		double f_area = area(f);
101
		
101
		
102
		HalfEdgeIter he = vc.get_halfedge();
102
		HalfEdgeIter he = vc.get_halfedge();
103
		Vec3d v1(he->vert->pos);
103
		Vec3d v1(he->vert->pos);
104
		Vec3d v2(he->next->vert->pos);
104
		Vec3d v2(he->next->vert->pos);
105
		Vec3d v0(he->next->next->vert->pos);
105
		Vec3d v0(he->next->next->vert->pos);
106
		
106
		
107
		double a0 = acos(dot(v1-v0, v2-v0)/(length(v1-v0)*length(v2-v0)));
107
		double a0 = acos(dot(v1-v0, v2-v0)/(length(v1-v0)*length(v2-v0)));
108
		double a1 = acos(dot(v2-v1, v0-v1)/(length(v2-v1)*length(v0-v1)));
108
		double a1 = acos(dot(v2-v1, v0-v1)/(length(v2-v1)*length(v0-v1)));
109
		double a2 = acos(dot(v0-v2, v1-v2)/(length(v0-v2)*length(v1-v2)));
109
		double a2 = acos(dot(v0-v2, v1-v2)/(length(v0-v2)*length(v1-v2)));
110
		
110
		
111
		if(a0>(M_PI/2.0) && a1>(M_PI/2.0) && a2>(M_PI/2.0)) // f is non-obtuse
111
		if(a0>(M_PI/2.0) && a1>(M_PI/2.0) && a2>(M_PI/2.0)) // f is non-obtuse
112
		{
112
		{
113
			// Add Voronoi formula (see Section 3.3)
113
			// Add Voronoi formula (see Section 3.3)
114
			area_mixed += (1.0/8) * 
114
			area_mixed += (1.0/8) * 
115
			((1.0/tan(a1)) * sqr_length(v2-v0) + 
115
			((1.0/tan(a1)) * sqr_length(v2-v0) + 
116
			 (1.0/tan(a2)) * sqr_length(v1-v0));
116
			 (1.0/tan(a2)) * sqr_length(v1-v0));
117
		}
117
		}
118
		else // Voronoi inappropriate
118
		else // Voronoi inappropriate
119
		{
119
		{
120
			// Add either area(f)/4 or area(f)/2
120
			// Add either area(f)/4 or area(f)/2
121
			if(a0>M_PI/2.0)// the angle of f at x is obtuse
121
			if(a0>M_PI/2.0)// the angle of f at x is obtuse
122
				area_mixed += f_area/2;
122
				area_mixed += f_area/2;
123
			else
123
			else
124
				area_mixed += f_area/4;
124
				area_mixed += f_area/4;
125
		}
125
		}
126
	}
126
	}
127
	return area_mixed;
127
	return area_mixed;
128
}
128
}
129
 
129
 
130
	double barycentric_area(VertexIter v)
130
	double barycentric_area(VertexIter v)
131
	{
131
	{
132
	double barea = 0;
132
	double barea = 0;
133
	//For each triangle T from the 1-ring neighborhood of x
133
	//For each triangle T from the 1-ring neighborhood of x
134
	for(VertexCirculator vc(v); !vc.end(); ++vc)
134
	for(VertexCirculator vc(v); !vc.end(); ++vc)
135
	{
135
	{
136
		FaceIter f = vc.get_face();
136
		FaceIter f = vc.get_face();
137
		barea += area(f)/3.0;
137
		barea += area(f)/3.0;
138
	}
138
	}
139
	return barea;
139
	return barea;
140
}
140
}
141
 
141
 
142
}
142
}
143
 
143
 
144
void Harmonics::make_laplace_operator()
144
void Harmonics::make_laplace_operator()
145
{
145
{
146
	Q.Resize(mani.no_vertices(), mani.no_vertices());
146
	Q.Resize(mani.no_vertices(), mani.no_vertices());
147
	
147
	
148
	for(VertexIter v = mani.vertices_begin(); v != mani.vertices_end(); ++v)
148
	for(VertexIter v = mani.vertices_begin(); v != mani.vertices_end(); ++v)
149
		if(!is_boundary(v))
149
		if(!is_boundary(v))
150
		{
150
		{
151
			int i = v->touched;
151
			int i = v->touched;
152
			double area_i = voronoi_area(v);
152
			double area_i = voronoi_area(v);
153
			Vec3d vertex(v->pos);
153
			Vec3d vertex(v->pos);
154
			Vec3d curv_normal(0);
154
			Vec3d curv_normal(0);
155
			double a_sum = 0;
155
			double a_sum = 0;
156
			for(VertexCirculator vc(v); !vc.end(); ++vc)
156
			for(VertexCirculator vc(v); !vc.end(); ++vc)
157
			{
157
			{
158
				int j = vc.get_vertex()->touched;
158
				int j = vc.get_vertex()->touched;
159
				double area_j = voronoi_area(vc.get_vertex());
159
				double area_j = voronoi_area(vc.get_vertex());
160
				HalfEdgeIter h = vc.get_halfedge();
160
				HalfEdgeIter h = vc.get_halfedge();
161
				Vec3d nbr(h->vert->pos);
161
				Vec3d nbr(h->vert->pos);
162
				Vec3d left(h->next->vert->pos);
162
				Vec3d left(h->next->vert->pos);
163
				Vec3d right(h->opp->prev->opp->vert->pos);
163
				Vec3d right(h->opp->prev->opp->vert->pos);
164
				
164
				
165
				double d_left = dot(normalize(nbr-left),
165
				double d_left = dot(normalize(nbr-left),
166
									normalize(vertex-left));
166
									normalize(vertex-left));
167
				double d_right = dot(normalize(nbr-right),
167
				double d_right = dot(normalize(nbr-right),
168
									 normalize(vertex-right));
168
									 normalize(vertex-right));
169
				double a_left  = acos(min(1.0, max(-1.0, d_left)));
169
				double a_left  = acos(min(1.0, max(-1.0, d_left)));
170
				double a_right = acos(min(1.0, max(-1.0, d_right)));
170
				double a_right = acos(min(1.0, max(-1.0, d_right)));
171
				
171
				
172
				double w = 1.0/tan(a_left) + 1.0/tan(a_right);
172
				double w = 1.0/tan(a_left) + 1.0/tan(a_right);
173
				
173
				
174
				Q[i][j] = -w/sqrt(area_i*area_j);						
174
				Q[i][j] = -w/sqrt(area_i*area_j);						
175
				//Q[i][j] = -1;						
175
				//Q[i][j] = -1;						
176
				a_sum += Q[i][j];
176
				a_sum += Q[i][j];
177
			}
177
			}
178
			Q[i][i] = -a_sum;
178
			Q[i][i] = -a_sum;
179
		}
179
		}
180
	EigenSolutionsSym(Q,V);
180
	EigenSolutionsSym(Q,V);
181
	
181
	
182
}
182
}
183
 
183
 
184
 
184
 
185
Harmonics::Harmonics(Manifold& _mani):mani(_mani)
185
Harmonics::Harmonics(Manifold& _mani):mani(_mani)
186
{
186
{
187
	assert(is_initialized);
187
	assert(is_initialized);
188
		
188
		
189
	triangulate(mani);
189
	triangulate(mani);
190
	mani.enumerate_vertices();
190
	mani.enumerate_vertices();
191
	maximum_eigenvalue = mani.no_vertices()-1;
191
	maximum_eigenvalue = mani.no_vertices()-1;
192
	make_laplace_operator();
192
	make_laplace_operator();
193
	
193
	
194
	proj.resize(maximum_eigenvalue);
194
	proj.resize(maximum_eigenvalue);
195
	max_eig_values.resize(maximum_eigenvalue, 1e-10);
195
	max_eig_values.resize(maximum_eigenvalue, 1e-10);
196
 
196
 
197
	for(int es=0; es<maximum_eigenvalue; ++es)
197
	for(int es=0; es<maximum_eigenvalue; ++es)
198
	{
198
	{
199
		proj[es] = Vec3d(0.0);
199
		proj[es] = Vec3d(0.0);
200
		for(VertexIter v=mani.vertices_begin(); v != mani.vertices_end(); ++v)
200
		for(VertexIter v=mani.vertices_begin(); v != mani.vertices_end(); ++v)
201
		{
201
		{
202
 
202
 
203
			proj[es] +=  Vec3d(v->pos) * Q[es][v->touched];
203
			proj[es] +=  Vec3d(v->pos) * Q[es][v->touched];
204
			max_eig_values[es] = max(max_eig_values[es], static_cast<float>(abs(Q[es][v->touched])));
204
			max_eig_values[es] = max(max_eig_values[es], static_cast<float>(abs(Q[es][v->touched])));
205
		}
205
		}
206
	}
206
	}
207
}
207
}
208
 
208
 
209
void Harmonics::add_frequency(int es, float scale)
209
void Harmonics::add_frequency(int es, float scale)
210
{
210
{
211
	if(es<maximum_eigenvalue)
211
	if(es<maximum_eigenvalue)
212
		for(VertexIter v=mani.vertices_begin(); v != mani.vertices_end(); ++v)
212
		for(VertexIter v=mani.vertices_begin(); v != mani.vertices_end(); ++v)
213
		{
213
		{
214
			Vec3f p = Vec3f(proj[es]);
214
			Vec3f p = Vec3f(proj[es]);
215
			float p0 = p[0];
-
 
216
			float p1 = p[1];
-
 
217
			float p2 = p[2];
-
 
218
			int idx = v->touched;
-
 
219
			double Qval = Q[es][v->touched];
215
			double Qval = Q[es][v->touched];
220
			
216
			
221
			v->pos += p * Qval * scale; // Vec3f(proj[es] * Q[es][v->touched] * scale); 	
217
			v->pos += p * Qval * scale; 	
222
		}
218
		}
223
}
219
}
224
 
220
 
225
void Harmonics::reset_shape()
221
void Harmonics::reset_shape()
226
{
222
{
227
	for(VertexIter v=mani.vertices_begin(); v != mani.vertices_end(); ++v)
223
	for(VertexIter v=mani.vertices_begin(); v != mani.vertices_end(); ++v)
228
		v->pos = Vec3f(0);	
224
		v->pos = Vec3f(0);	
229
}
225
}
230
void Harmonics::partial_reconstruct(int E0, int E1, float scale)
226
void Harmonics::partial_reconstruct(int E0, int E1, float scale)
231
{
227
{
232
	for(int es=E0;es<=E1;++es)
228
	for(int es=E0;es<=E1;++es)
233
		add_frequency(es, scale);
229
		add_frequency(es, scale);
234
}
230
}
235
 
231
 
236
 
232
 
237
template<typename T>
233
template<typename T>
238
T& get_CVar_ref(const std::string& s)
234
T& get_CVar_ref(const std::string& s)
239
{
235
{
240
	return *reinterpret_cast<T*> (GetCVarData(s));
236
	return *reinterpret_cast<T*> (GetCVarData(s));
241
}
237
}
242
 
238
 
243
void Harmonics::parse_key(unsigned char key)
239
void Harmonics::parse_key(unsigned char key)
244
{
240
{
245
		int& display_eigenvalue = get_CVar_ref<int>("display.harmonics.eigenvalue");
241
		int& display_eigenvalue = get_CVar_ref<int>("display.harmonics.eigenvalue");
246
		int& display_diffuse = get_CVar_ref<int>("display.harmonics.diffuse");
242
		int& display_diffuse = get_CVar_ref<int>("display.harmonics.diffuse");
247
		int& display_highlight = get_CVar_ref<int>("display.harmonics.highlight");
243
		int& display_highlight = get_CVar_ref<int>("display.harmonics.highlight");
248
		switch(key) {
244
		switch(key) {
249
			case '+': 
245
			case '+': 
250
				display_eigenvalue = min(display_eigenvalue+1, maximum_eigenvalue); 
246
				display_eigenvalue = min(display_eigenvalue+1, maximum_eigenvalue); 
251
				break;
247
				break;
252
			case '-': 
248
			case '-': 
253
				display_eigenvalue = max(display_eigenvalue-1, 0); 
249
				display_eigenvalue = max(display_eigenvalue-1, 0); 
254
				break;
250
				break;
255
			case 'd':	
251
			case 'd':	
256
				display_diffuse = !display_diffuse; 
252
				display_diffuse = !display_diffuse; 
257
				break;
253
				break;
258
			case 'h':
254
			case 'h':
259
				display_highlight = !display_highlight;
255
				display_highlight = !display_highlight;
260
				break;			
256
				break;			
261
		}
257
		}
262
 
258
 
263
}
259
}
264
 
260
 
265
void Harmonics::draw()
261
void Harmonics::draw()
266
{
262
{
267
	int& display_eigen = get_CVar_ref<int>("display.harmonics.eigenvalue");
263
	int& display_eigen = get_CVar_ref<int>("display.harmonics.eigenvalue");
268
	int& display_eigen2 = get_CVar_ref<int>("display.harmonics.eigenvalue");
264
	int& display_eigen2 = get_CVar_ref<int>("display.harmonics.eigenvalue");
269
	int& do_diffuse = get_CVar_ref<int>("display.harmonics.diffuse");
265
	int& do_diffuse = get_CVar_ref<int>("display.harmonics.diffuse");
270
	int& do_highlight = get_CVar_ref<int>("display.harmonics.highlight");
266
	int& do_highlight = get_CVar_ref<int>("display.harmonics.highlight");
271
 
267
 
272
 
268
 
273
	glUseProgram(prog_P0);
269
	glUseProgram(prog_P0);
274
	glUniform1f(glGetUniformLocation(prog_P0,"eig_max"),max_eig_values[display_eigen]);
270
	glUniform1f(glGetUniformLocation(prog_P0,"eig_max"),max_eig_values[display_eigen]);
275
	glUniform1f(glGetUniformLocation(prog_P0,"eig_max2"),max_eig_values[display_eigen2]);
271
	glUniform1f(glGetUniformLocation(prog_P0,"eig_max2"),max_eig_values[display_eigen2]);
276
	glUniform1i(glGetUniformLocation(prog_P0,"do_diffuse"),do_diffuse);
272
	glUniform1i(glGetUniformLocation(prog_P0,"do_diffuse"),do_diffuse);
277
   	glUniform1i(glGetUniformLocation(prog_P0,"do_highlight"),do_highlight);
273
   	glUniform1i(glGetUniformLocation(prog_P0,"do_highlight"),do_highlight);
278
	GLuint attrib = glGetAttribLocationARB(prog_P0, "eigenvalue");
274
	GLuint attrib = glGetAttribLocationARB(prog_P0, "eigenvalue");
279
	GLuint attrib2 = glGetAttribLocationARB(prog_P0, "eigenvalue2");
275
	GLuint attrib2 = glGetAttribLocationARB(prog_P0, "eigenvalue2");
280
	
276
	
281
	glFrontFace(GL_CW);
277
	glFrontFace(GL_CW);
282
	for(FaceIter f=mani.faces_begin(); f != mani.faces_end(); ++f)
278
	for(FaceIter f=mani.faces_begin(); f != mani.faces_end(); ++f)
283
	{
279
	{
284
		FaceCirculator fc(f);
280
		FaceCirculator fc(f);
285
		glBegin(GL_TRIANGLES);
281
		glBegin(GL_TRIANGLES);
286
		while(!fc.end())
282
		while(!fc.end())
287
		{
283
		{
288
			int i = fc.get_vertex()->touched;
284
			int i = fc.get_vertex()->touched;
289
			glVertexAttrib1f(attrib,Q[display_eigen][i]);
285
			glVertexAttrib1f(attrib,Q[display_eigen][i]);
290
			glVertexAttrib1f(attrib2,Q[display_eigen2][i]);
286
			glVertexAttrib1f(attrib2,Q[display_eigen2][i]);
291
			glNormal3fv(normal(fc.get_vertex()).get());
287
			glNormal3fv(normal(fc.get_vertex()).get());
292
			glVertex3fv(fc.get_vertex()->pos.get());
288
			glVertex3fv(fc.get_vertex()->pos.get());
293
			++fc;
289
			++fc;
294
		}
290
		}
295
		glEnd();
291
		glEnd();
296
	}
292
	}
297
	glFrontFace(GL_CCW);
293
	glFrontFace(GL_CCW);
298
	glUseProgram(0);
294
	glUseProgram(0);
299
}
295
}
300
 
296
 
301
void Harmonics::init()
297
void Harmonics::init()
302
{
298
{
303
	is_initialized = true;
299
	is_initialized = true;
304
	string shader_path = "/Users/jab/GEL/apps/MeshEdit/";
300
	string shader_path = "/Users/jab/GEL/apps/MeshEdit/";
305
	GLuint vs = create_glsl_shader(GL_VERTEX_SHADER, vss);
301
	GLuint vs = create_glsl_shader(GL_VERTEX_SHADER, vss);
306
	GLuint fs = create_glsl_shader(GL_FRAGMENT_SHADER, fss);
302
	GLuint fs = create_glsl_shader(GL_FRAGMENT_SHADER, fss);
307
	
303
	
308
	// Create the program
304
	// Create the program
309
	prog_P0 = glCreateProgram();
305
	prog_P0 = glCreateProgram();
310
	
306
	
311
	// Attach all shaders
307
	// Attach all shaders
312
	if(vs) glAttachShader(prog_P0, vs);
308
	if(vs) glAttachShader(prog_P0, vs);
313
	if(fs) glAttachShader(prog_P0, fs);
309
	if(fs) glAttachShader(prog_P0, fs);
314
	
310
	
315
	// Link the program object and print out the info log
311
	// Link the program object and print out the info log
316
	glLinkProgram(prog_P0);
312
	glLinkProgram(prog_P0);
317
	print_glsl_program_log(prog_P0);
313
	print_glsl_program_log(prog_P0);
318
	
314
	
319
	// Install program object as part of current state
315
	// Install program object as part of current state
320
	glUseProgram(0);
316
	glUseProgram(0);
321
	
317
	
322
	static CVar<int> display_eigen("display.harmonics.eigenvalue",0);
318
	static CVar<int> display_eigen("display.harmonics.eigenvalue",0);
323
	static CVar<int> display_eigen2("display.harmonics.eigenvalue2",0);
319
	static CVar<int> display_eigen2("display.harmonics.eigenvalue2",0);
324
	static CVar<int> do_highlight("display.harmonics.highlight",1);
320
	static CVar<int> do_highlight("display.harmonics.highlight",1);
325
	static CVar<int> do_diffuse("display.harmonics.diffuse",1);
321
	static CVar<int> do_diffuse("display.harmonics.diffuse",1);
326
 
322
 
327
}
323
}
328
 
324