Blame view

stim/visualization/gl_spharmonics-dep.h 6.29 KB
01707489   David Mayerich   implemented a new...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
  #ifndef STIM_GL_SPHARMONICS_H
  #define STIM_GL_SPHARMONICS_H
  
  #include <GL/gl.h>
  
  #include <stim/gl/error.h>
  #include <stim/visualization/colormap.h>
  #include <stim/math/spharmonics.h>
  
  namespace stim{
  
  	
  template <typename T>
  class gl_spharmonics : public spharmonics<T>{
  
  protected:
  
  	using stim::spharmonics<T>::SH;
  	stim::spharmonics<T> surface;	//harmonic that stores the surface information
  	stim::spharmonics<T> color;	//harmonic that stores the color information
  	T* func_surface;		//stores the raw function data (samples at each point)
  	T* func_color;			//stores the raw color data (samples at each point)
  	GLuint color_tex;		//texture map that acts as a colormap for the spherical function
  	unsigned int N;			//resolution of the spherical grid
  
  	///generates the 
  	void gen_surface(){
  		//allocate memory and initialize the function to zero
  		func_surface = (T*) malloc(N * N * sizeof(T));
  		memset(func_surface, 0, sizeof(T) * N * N);
  
  		double theta, phi;
  		double result;
  		int l, m;
  
  
  		l = m = 0;
  		//for each coefficient
  		for(unsigned int c = 0; c < surface.C.size(); c++){				
  
  			//iterate through the entire 2D grid representing the function
  			for(unsigned int xi = 0; xi < N; xi++){
  				for(unsigned int yi = 0; yi < N; yi++){
  
  					//get the spherical coordinates for each grid point
  					theta = (2 * PI) * ((double)xi / (N-1));
  					phi = PI * ((double)yi / (N-1));
  
  					//sum the contribution of the current spherical harmonic based on the coefficient
  					result = surface.C[c] * SH(l, m, theta, phi);
  
  					//store the result in a 2D array (which will later be used as a texture map)
  					func_surface[yi * N + xi] += result;
  				}
  			}
  
  			//keep track of m and l here
  			m++;			//increment m
  			//if we're in a new tier, increment l and set m = -l
  			if(m > l){		
  				l++;
  				m = -l;
  			}
  		}
  	}
  
  	///generates the color function
  	void gen_color(){
  
  		//initialize the function to zero
  		func_color = (T*) malloc(N * N * sizeof(T));
  		memset(func_color, 0, sizeof(T) * N * N);
  
  		double theta, phi;
  		double result;
  		int l, m;
  
  
  		l = m = 0;
  		//for each coefficient
  		for(unsigned int c = 0; c < color.C.size(); c++){				
  
  			//iterate through the entire 2D grid representing the function
  			for(unsigned int xi = 0; xi < N; xi++){
  				for(unsigned int yi = 0; yi < N; yi++){
  
  					//get the spherical coordinates for each grid point
  					theta = (2 * PI) * ((double)xi / (N-1));
  					phi = PI * ((double)yi / (N-1));
  
  					//sum the contribution of the current spherical harmonic based on the coefficient
  					result = color.C[c] * SH(l, m, theta, phi);
  
  					//store the result in a 2D array (which will later be used as a texture map)
  					func_color[yi * N + xi] += result;
  				}
  			}
  
  			//keep track of m and l here
  			m++;			//increment m
  			//if we're in a new tier, increment l and set m = -l
  			if(m > l){		
  				l++;
  				m = -l;
  			}
  		}
  	}
  
  	void gl_prep_draw(){
  
  		//enable depth testing
  			//this has to be used instead of culling because the sphere can have negative values
  		glEnable(GL_DEPTH_TEST);
  		glDepthMask(GL_TRUE);
  		glEnable(GL_TEXTURE_2D);	//enable 2D texture mapping
  	}
  
  	//draw a texture mapped sphere representing the function surface
  	void gl_draw_sphere() {
  
  		//bind the 2D texture representing the color map
  		glBindTexture(GL_TEXTURE_2D, color_tex);
  
  		//Draw the Sphere
  		int i, j;
  
  		for(i = 1; i <= N-1; i++) {
  			double phi0 = PI * ((double) (i - 1) / (N-1));
  			double phi1 = PI * ((double) i / (N-1));
  
  			glBegin(GL_QUAD_STRIP);
  			for(j = 0; j <= N; j++) {
  
  				//calculate the indices into the function array
  				int phi0_i = i-1;
  				int phi1_i = i;
  				int theta_i = j;
  				if(theta_i == N)
  					theta_i = 0;
  
  				double v0 = func_surface[phi0_i * N + theta_i];
  				double v1 = func_surface[phi1_i * N + theta_i];
  
  				v0 = fabs(v0);
  				v1 = fabs(v1);
  
  
  				double theta = 2 * PI * (double) (j - 1) / N;
  				double x0 = v0 * cos(theta) * sin(phi0);
  				double y0 = v0 * sin(theta) * sin(phi0);
  				double z0 = v0 * cos(phi0);
  
  				double x1 = v1 * cos(theta) * sin(phi1);
  				double y1 = v1 * sin(theta) * sin(phi1);
  				double z1 = v1 * cos(phi1);
  
  				glTexCoord2f(theta / (2 * PI), phi0 / PI);
  				glVertex3f(x0, y0, z0);
  
  				glTexCoord2f(theta / (2 * PI), phi1 / PI);
  				glVertex3f(x1, y1, z1);
  			}
  			glEnd();
  		}
  
  		glBindTexture(GL_TEXTURE_2D, 0);
  	}
  
  	void gen_texture()
  	{
  		//allocate space for the color map
  		unsigned int bytes = N * N * sizeof(unsigned char) * 3;
  		unsigned char* color_image;
  		color_image = (unsigned char*) malloc(bytes);
  
  		//generate a colormap from the function
  		stim::cpu2cpu<double>(func_color, color_image, N*N, stim::cmBrewer);
  
  		//prep everything for drawing
  		gl_prep_draw();			
  
  		//generate an OpenGL texture map in the current context
  		glGenTextures(1, &color_tex);
  		//bind the texture
  		glBindTexture(GL_TEXTURE_2D, color_tex);
  
  		//copy the color data from the buffer to the GPU
  		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, N, N, 0, GL_RGB, GL_UNSIGNED_BYTE, color_image);
  
  		//initialize all of the texture parameters
  		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
  		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  		glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
  			
  		//free the buffer
  		free(color_image);
  	}
  
  	void gl_init(unsigned int n){
  
  		//set the sphere resolution
  		N = n;
  
  		//set up the surface data.
  		gen_surface();
  
  		//set up the color data and generate the corresponding texture.
  		gen_color();
  		gen_texture();
  
  	}
  
  public:
  	gl_spharmonics<T>(unsigned int n = 256) {
  		gl_init(n);
  	}
  
  	gl_spharmonics<T>( stim::spharmonics<T> in_function, unsigned int n = 256)
  	{
  		surface = in_function;
  		color = in_function;	
  		gl_init(n);
  	}
  
  	gl_spharmonics<T>( stim::spharmonics<T> in_function, stim::spharmonics<T> in_color, unsigned int n = 256)
  	{
  		surface = in_function;
  		color = in_color;	
  		gl_init(n);
  	}
  
  	gl_spharmonics<T>& operator=(const spharmonics<T> rhs) {
  		gl_spharmonics<T> result(rhs.C.size());
  		result.C = spharmonics<T>::rhs.C;
  		return result;
  	}
  
  	void glRender(){
  		//set all OpenGL parameters required for drawing
  		gl_prep_draw();
  
  		//draw the sphere
  		gl_draw_sphere();
  	}
  
  	void glInit(unsigned int n = 256){
  		gl_init(n);
  	}
  };		//end gl_spharmonics
  
  
  };		//end namespace stim
  
  
  
  
  #endif