Blame view

stim/visualization/gl_spharmonics.h 4.59 KB
487a9b49   David Mayerich   added the ability...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
  #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:

321ff17a   David Mayerich   Optimized the mat...
17
18
  	using spharmonics<T>::C;

  	using spharmonics<T>::SH;

487a9b49   David Mayerich   added the ability...
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
  	

  	T* func;		//stores the raw function 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

  

  	void gen_function(){

  

  		//initialize the function to zero

  		memset(func, 0, sizeof(double) * N * N);

  

  		double theta, phi;

  		double result;

  		int l, m;

  

  

  		l = m = 0;

  		//for each coefficient

  		for(unsigned int c = 0; c < 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 = C[c] * SH(l, m, theta, phi);

  

  					//store the result in a 2D array (which will later be used as a texture map)

  					func[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[phi0_i * N + theta_i];

  				double v1 = func[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();

  		}

  	}

  

  	void gl_init(unsigned int n){

  

  		//set the sphere resolution

  		N = n;

  

  		//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);

  

  		//allocate space for the function

  		func = (double*) malloc(N * N * sizeof(double));

  

  		//generate a functional representation that will be used for the texture map and vertices

  		gen_function();

  

  		//generate a colormap from the function

  		stim::cpu2cpu<double>(func, 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);

  	}

  

  public:

  

  	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);

  		gen_function();

  	}

  

  

  };		//end gl_spharmonics

  

  

  };		//end namespace stim

  

  

  

  

321ff17a   David Mayerich   Optimized the mat...
189
  #endif