#ifndef STIM_GL_SPHARMONICS_H #define STIM_GL_SPHARMONICS_H #include #include #include #include #include namespace stim { template class gl_spharmonics { GLuint dlist; GLuint tex; bool displacement; bool colormap; bool magnitude; void init_tex() { T* sfunc = (T*)malloc(N * N * sizeof(T)); //create a 2D array to store the spherical function Sc.get_func(sfunc, N, N); //generate the spherical function based on the Sc coefficients unsigned char* tex_buffer = (unsigned char*)malloc(3 * N * N); //create a buffer to store the texture map stim::cpu2cpu(sfunc, tex_buffer, N * N, stim::cmBrewer); //create a Brewer colormap based on the spherical function stim::buffer2image(tex_buffer, "sfunc.ppm", N, N); if (tex) glDeleteTextures(1, &tex); //if a texture already exists, delete it glGenTextures(1, &tex); //create a new texture and store the ID glBindTexture(GL_TEXTURE_2D, tex); //bind the texture glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, N, N, 0, GL_RGB, GL_UNSIGNED_BYTE, tex_buffer); //copy the color data from the buffer to the GPU glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); //initialize all of the texture parameters 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_MODULATE); } public: stim::spharmonics Sc; //spherical harmonic representing the color component stim::spharmonics Sd; //spherical harmonic representing the displacement component size_t N; gl_spharmonics(size_t slices) { N = slices; dlist = 0; //initialize the display list index to zero (no list) tex = 0; //initialize the texture index to zero (no texture) displacement = true; colormap = true; magnitude = true; } gl_spharmonics(stim::spharmonics disp, stim::spharmonics color, size_t slices) : gl_spharmonics(slices) { Sc = color; Sd = disp; } ~gl_spharmonics() { if (dlist) glDeleteLists(dlist, 1); //delete the display list when the object is destroyed } ///saves the coeffients of a spherical harmonics in a text documents. void save_coeffs(std::string filename) { std::ofstream myfile; myfile.open(filename.c_str()); for(int i = 0; i < Sd.C.size()-1; i++) { myfile << Sd.C[i] << ","; } myfile << Sd.C[Sd.C.size()-1] << std::endl; for(int i = 0; i < Sc.C.size()-1; i++) { myfile << Sc.C[i] << ","; } myfile << Sc.C[Sc.C.size()-1] << std::endl; myfile.close(); } void save(std::string filename) { if (!tex) { init_tex(); } stim::obj object; size_t theta_i, phi_i; T d_theta = (T)stim::TAU / (T)N; T d_phi = (T)stim::PI / (T)(N-1); object.matKd("sfunc.jpg"); for (phi_i = 1; phi_i < N; phi_i++) { T phi = phi_i * d_phi; object.Begin(OBJ_TRIANGLE_STRIP); for (theta_i = 0; theta_i <= N; theta_i++) { T theta = (N - theta_i) * d_theta; float theta_t = 1 - (float)theta_i / (float)N; T r; if (!displacement) r = 1; //if no displacement, set the r value to 1 (renders a unit sphere) else r = Sd(theta, phi); //otherwise calculate the displacement value glColor3f(1.0f, 1.0f, 1.0f); if (!colormap) { //if no colormap is being rendered if (r < 0) glColor3f(1.0, 0.0, 0.0); //if r is negative, render it red else glColor3f(0.0, 1.0, 0.0); //otherwise render in green } if (magnitude) { //if the magnitude is being displaced, calculate the magnitude of r if (r < 0) r = -r; } stim::vec3 s(r, theta, phi); stim::vec3 c = s.sph2cart(); stim::vec3 n; //allocate a value to store the normal if (!displacement) n = c; //if there is no displacement, the normal is spherical else n = Sd.dphi(theta, phi).cross(Sd.dtheta(theta, phi)); //otherwise calculate the normal as the cross product of derivatives object.TexCoord(theta_t, (float)phi_i / (float)N); //std::cout << theta_t <<" "<<(float)phi_i / (float)N << "----------------"; object.Normal(n[0], n[1], n[2]); object.Vertex(c[0], c[1], c[2]); T r1; if (!displacement) r1 = 1; else r1 = Sd(theta, phi - d_phi); if (!colormap) { //if no colormap is being rendered if (r1 < 0) glColor3f(1.0, 0.0, 0.0); //if r1 is negative, render it red else glColor3f(0.0, 1.0, 0.0); //otherwise render in green } if (magnitude) { //if the magnitude is being rendered, calculate the magnitude of r if (r1 < 0) r1 = -r1; } stim::vec3 s1(r1, theta, phi - d_phi); stim::vec3 c1 = s1.sph2cart(); stim::vec3 n1; if (!displacement) n1 = c1; else n1 = Sd.dphi(theta, phi - d_phi).cross(Sd.dtheta(theta, phi - d_phi)); //std::cout << theta_t << " " << (float)(phi_i - 1) / (float)N << std::endl; object.TexCoord(theta_t, 1.0/(2*(N)) + (float)(phi_i-1) / (float)N); object.Normal(n1[0], n1[1], n1[2]); object.Vertex(c1[0], c1[1], c1[2]); } object.End(); } object.matKd(); object.save(filename); } /// This function renders the spherical harmonic to the current OpenGL context void render() { //glShadeModel(GL_FLAT); glPushAttrib(GL_ENABLE_BIT); glDisable(GL_CULL_FACE); glEnable(GL_DEPTH_TEST); glDepthMask(GL_TRUE); if (!tex) { init_tex(); } if (colormap) { glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, tex); } if (!dlist) { dlist = glGenLists(1); glNewList(dlist, GL_COMPILE); glPushAttrib(GL_ENABLE_BIT); glEnable(GL_NORMALIZE); //Draw the Sphere size_t theta_i, phi_i; T d_theta = (T)stim::TAU / (T)N; T d_phi = (T)stim::PI / (T)(N-1); for (phi_i = 1; phi_i < N; phi_i++) { T phi = phi_i * d_phi; glBegin(GL_QUAD_STRIP); for (theta_i = 0; theta_i <= N; theta_i++) { T theta = (N - theta_i) * d_theta; float theta_t = 1 - (float)theta_i / (float)N; T r; if (!displacement) r = 1; //if no displacement, set the r value to 1 (renders a unit sphere) else r = Sd(theta, phi); //otherwise calculate the displacement value glColor3f(1.0f, 1.0f, 1.0f); if (!colormap) { //if no colormap is being rendered if (r < 0) glColor3f(1.0, 0.0, 0.0); //if r is negative, render it red else glColor3f(0.0, 1.0, 0.0); //otherwise render in green } if (magnitude) { //if the magnitude is being displaced, calculate the magnitude of r if (r < 0) r = -r; } stim::vec3 s(r, theta, phi); stim::vec3 c = s.sph2cart(); stim::vec3 n; //allocate a value to store the normal if (!displacement) n = c; //if there is no displacement, the normal is spherical else n = Sd.dphi(theta, phi).cross(Sd.dtheta(theta, phi)); //otherwise calculate the normal as the cross product of derivatives glTexCoord2f(theta_t, (float)phi_i / (float)N); //std::cout << theta_t <<" "<<(float)phi_i / (float)N << "----------------"; glNormal3f(n[0], n[1], n[2]); glVertex3f(c[0], c[1], c[2]); T r1; if (!displacement) r1 = 1; else r1 = Sd(theta, phi - d_phi); if (!colormap) { //if no colormap is being rendered if (r1 < 0) glColor3f(1.0, 0.0, 0.0); //if r1 is negative, render it red else glColor3f(0.0, 1.0, 0.0); //otherwise render in green } if (magnitude) { //if the magnitude is being rendered, calculate the magnitude of r if (r1 < 0) r1 = -r1; } stim::vec3 s1(r1, theta, phi - d_phi); stim::vec3 c1 = s1.sph2cart(); stim::vec3 n1; if (!displacement) n1 = c1; else n1 = Sd.dphi(theta, phi - d_phi).cross(Sd.dtheta(theta, phi - d_phi)); //std::cout << theta_t << " " << (float)(phi_i - 1) / (float)N << std::endl; glTexCoord2f(theta_t, 1.0/(2*(N)) + (float)(phi_i-1) / (float)N); glNormal3f(n1[0], n1[1], n1[2]); glVertex3f(c1[0], c1[1], c1[2]); } glEnd(); } glPopAttrib(); glEndList(); } glCallList(dlist); //call the display list to render glPopAttrib(); glDisable(GL_DEPTH_TEST); glDepthMask(GL_FALSE); } /// Push a coefficient to the spherical harmonic - by default, push applies the component to both the displacement and color SH void push(T coeff) { Sd.push(coeff); Sc.push(coeff); } /// Resize the spherical harmonic coefficient array void resize(size_t s) { Sd.resize(s); Sc.resize(s); } /// Set a spherical harmonic coefficient to the given value void setc(unsigned int c, T value) { Sd.setc(c, value); Sc.setc(c, value); } void project(T* data, size_t x, size_t y, size_t nc) { Sd.project(data, x, y, nc); Sc = Sd; } /// Project a set of samples onto the basis void project(std::vector >& vlist, size_t nc) { Sd.project(vlist, nc); Sc = Sd; } /// Calculate a density function from a list of points in spherical coordinates void pdf(std::vector >& vlist, size_t nc) { Sd.pdf(vlist, nc); Sc = Sd; } void slices(size_t s) { N = s; } size_t slices() { return N; } void rendermode(bool displace, bool color, bool mag = true) { displacement = displace; colormap = color; magnitude = mag; } }; } #endif