Commit e4d08b323265fb544a159d3d3e7ccd2f15f31fe4

Authored by David Mayerich
1 parent 31c961c7

implemented a new spherical harmonics renderer

Showing 2 changed files with 323 additions and 110 deletions   Show diff stats
FindGLEW.cmake 0 → 100644
  1 +# Copyright (c) 2012-2016 DreamWorks Animation LLC
  2 +#
  3 +# All rights reserved. This software is distributed under the
  4 +# Mozilla Public License 2.0 ( http://www.mozilla.org/MPL/2.0/ )
  5 +#
  6 +# Redistributions of source code must retain the above copyright
  7 +# and license notice and the following restrictions and disclaimer.
  8 +#
  9 +# * Neither the name of DreamWorks Animation nor the names of
  10 +# its contributors may be used to endorse or promote products derived
  11 +# from this software without specific prior written permission.
  12 +#
  13 +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  14 +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  15 +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  16 +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  17 +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY INDIRECT, INCIDENTAL,
  18 +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  19 +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  20 +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  21 +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  22 +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  23 +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24 +# IN NO EVENT SHALL THE COPYRIGHT HOLDERS' AND CONTRIBUTORS' AGGREGATE
  25 +# LIABILITY FOR ALL CLAIMS REGARDLESS OF THEIR BASIS EXCEED US$250.00.
  26 +#
  27 +
  28 +#-*-cmake-*-
  29 +# - Find GLEW
  30 +#
  31 +# Author : Nicholas Yue yue.nicholas@gmail.com
  32 +#
  33 +# This auxiliary CMake file helps in find the GLEW headers and libraries
  34 +#
  35 +# GLEW_FOUND set if Glew is found.
  36 +# GLEW_INCLUDE_DIR GLEW's include directory
  37 +# GLEW_glew_LIBRARY GLEW libraries
  38 +# GLEW_glewmx_LIBRARY GLEWmx libraries (Mulitple Rendering Context)
  39 +
  40 +FIND_PACKAGE ( PackageHandleStandardArgs )
  41 +
  42 +FIND_PATH( GLEW_LOCATION include/GL/glew.h
  43 + "$ENV{GLEW_ROOT}"
  44 + NO_DEFAULT_PATH
  45 + NO_SYSTEM_ENVIRONMENT_PATH
  46 + )
  47 +
  48 +FIND_PACKAGE_HANDLE_STANDARD_ARGS ( GLEW
  49 + REQUIRED_VARS GLEW_LOCATION
  50 + )
  51 +
  52 +IF ( GLEW_LOCATION )
  53 +
  54 + SET( GLEW_INCLUDE_DIR "${GLEW_LOCATION}/include" CACHE STRING "GLEW include path")
  55 +
  56 + SET ( ORIGINAL_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES})
  57 + IF (GLEW_USE_STATIC_LIBS)
  58 + IF (APPLE)
  59 + SET(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
  60 + FIND_LIBRARY ( GLEW_LIBRARY_PATH GLEW PATHS ${GLEW_LOCATION}/lib
  61 + NO_DEFAULT_PATH
  62 + NO_SYSTEM_ENVIRONMENT_PATH
  63 + )
  64 + FIND_LIBRARY ( GLEWmx_LIBRARY_PATH GLEWmx PATHS ${GLEW_LOCATION}/lib
  65 + NO_DEFAULT_PATH
  66 + NO_SYSTEM_ENVIRONMENT_PATH
  67 + )
  68 + # MESSAGE ( "APPLE STATIC" )
  69 + # MESSAGE ( "GLEW_LIBRARY_PATH = " ${GLEW_LIBRARY_PATH} )
  70 + ELSEIF (WIN32)
  71 + # Link library
  72 + SET(CMAKE_FIND_LIBRARY_SUFFIXES ".lib")
  73 + FIND_LIBRARY ( GLEW_LIBRARY_PATH GLEW32S PATHS ${GLEW_LOCATION}/lib )
  74 + FIND_LIBRARY ( GLEWmx_LIBRARY_PATH GLEW32MXS PATHS ${GLEW_LOCATION}/lib )
  75 + ELSE (APPLE)
  76 + SET(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
  77 + FIND_LIBRARY ( GLEW_LIBRARY_PATH GLEW PATHS ${GLEW_LOCATION}/lib
  78 + NO_DEFAULT_PATH
  79 + NO_SYSTEM_ENVIRONMENT_PATH
  80 + )
  81 + FIND_LIBRARY ( GLEWmx_LIBRARY_PATH GLEWmx PATHS ${GLEW_LOCATION}/lib
  82 + NO_DEFAULT_PATH
  83 + NO_SYSTEM_ENVIRONMENT_PATH
  84 + )
  85 + # MESSAGE ( "LINUX STATIC" )
  86 + # MESSAGE ( "GLEW_LIBRARY_PATH = " ${GLEW_LIBRARY_PATH} )
  87 + ENDIF (APPLE)
  88 + ELSE ()
  89 + IF (APPLE)
  90 + SET(CMAKE_FIND_LIBRARY_SUFFIXES ".dylib")
  91 + FIND_LIBRARY ( GLEW_LIBRARY_PATH GLEW PATHS ${GLEW_LOCATION}/lib )
  92 + FIND_LIBRARY ( GLEWmx_LIBRARY_PATH GLEWmx PATHS ${GLEW_LOCATION}/lib )
  93 + ELSEIF (WIN32)
  94 + # Link library
  95 + SET(CMAKE_FIND_LIBRARY_SUFFIXES ".lib")
  96 + FIND_LIBRARY ( GLEW_LIBRARY_PATH GLEW32 PATHS ${GLEW_LOCATION}/lib )
  97 + FIND_LIBRARY ( GLEWmx_LIBRARY_PATH GLEW32mx PATHS ${GLEW_LOCATION}/lib )
  98 + # Load library
  99 + SET(CMAKE_FIND_LIBRARY_SUFFIXES ".dll")
  100 + FIND_LIBRARY ( GLEW_DLL_PATH GLEW32 PATHS ${GLEW_LOCATION}/bin
  101 + NO_DEFAULT_PATH
  102 + NO_SYSTEM_ENVIRONMENT_PATH
  103 + )
  104 + FIND_LIBRARY ( GLEWmx_DLL_PATH GLEW32mx PATHS ${GLEW_LOCATION}/bin
  105 + NO_DEFAULT_PATH
  106 + NO_SYSTEM_ENVIRONMENT_PATH
  107 + )
  108 + ELSE (APPLE)
  109 + # Unices
  110 + FIND_LIBRARY ( GLEW_LIBRARY_PATH GLEW PATHS ${GLEW_LOCATION}/lib
  111 + NO_DEFAULT_PATH
  112 + NO_SYSTEM_ENVIRONMENT_PATH
  113 + )
  114 + FIND_LIBRARY ( GLEWmx_LIBRARY_PATH GLEWmx PATHS ${GLEW_LOCATION}/lib
  115 + NO_DEFAULT_PATH
  116 + NO_SYSTEM_ENVIRONMENT_PATH
  117 + )
  118 + ENDIF (APPLE)
  119 + ENDIF ()
  120 + # MUST reset
  121 + SET(CMAKE_FIND_LIBRARY_SUFFIXES ${ORIGINAL_CMAKE_FIND_LIBRARY_SUFFIXES})
  122 +
  123 + SET( GLEW_GLEW_LIBRARY ${GLEW_LIBRARY_PATH} CACHE STRING "GLEW library")
  124 + SET( GLEW_GLEWmx_LIBRARY ${GLEWmx_LIBRARY_PATH} CACHE STRING "GLEWmx library")
  125 +
  126 +ENDIF ()
... ...
main.cpp
... ... @@ -9,16 +9,15 @@
9 9 #include <stim/visualization/gl_spharmonics.h>
10 10 #include <stim/math/constants.h>
11 11  
12   -#define theta_scale 0.01
13   -#define phi_scale 0.01
14   -#define zoom_scale 0.1
  12 +#define theta_scale 0.01f
  13 +#define phi_scale 0.01f
  14 +#define zoom_scale 0.1f
15 15  
16 16 //create a global camera that will specify the viewport
17 17 stim::camera cam;
18 18 int mx, my; //mouse coordinates in the window space
19 19  
20   -stim::spharmonics<double> S;
21   -stim::gl_spharmonics<double> R; //spherical harmonics to render
  20 +stim::gl_spharmonics<float> SH(300); //spherical harmonics to render
22 21  
23 22 float d = 1.5; //initial distance between the camera and the sphere
24 23  
... ... @@ -26,13 +25,19 @@ bool rotate_zoom = true; //sets the current camera mode (rotation = true, zoom =
26 25  
27 26 stim::arglist args; //class for processing command line arguments
28 27  
29   -bool zaxis = false; //render the z-axis (set via a command line flag)
  28 +bool axis = false; //render the z-axis (set via a command line flag)
30 29  
31 30 /// INTERPOLATION
32   -stim::gl_spharmonics<double> Si;
  31 +//stim::gl_spharmonics<double> Si;
33 32 bool interp = false; //if we are interpolating
34   -float alpha = 0.0; //alpha value for interpolation
35   -float dalpha = 0.1; //change in alpha value with a key press
  33 +float alpha = 0.0f; //alpha value for interpolation
  34 +float dalpha = 0.1f; //change in alpha value with a key press
  35 +
  36 +/// Visualization flags
  37 +bool mag = true;
  38 +bool cmap = true;
  39 +bool displace = true;
  40 +bool light = true;
36 41  
37 42 bool init(){
38 43  
... ... @@ -45,11 +50,47 @@ bool init(){
45 50 cam.setFOV(40);
46 51  
47 52 //initialize the texture map stuff
48   - R.glInit(256);
  53 + //R.glInit(256);
49 54  
50 55 return true;
51 56 }
52 57  
  58 +void render_axes() {
  59 + glDisable(GL_TEXTURE_2D); //turn off texture mapping
  60 + glBegin(GL_LINES);
  61 + glColor3f(1.0f, 0.0f, 0.0f); //set the color to RED and render X
  62 + glVertex3f(0.0, 0.0, 0.0);
  63 + glVertex3f(100.0, 0.0, 0.0);
  64 +
  65 + glColor3f(0.0f, 1.0f, 0.0f); //set the color to RED and render X
  66 + glVertex3f(0.0, 0.0, 0.0);
  67 + glVertex3f(0.0, 100.0, 0.0);
  68 +
  69 + glColor3f(0.0f, 0.0f, 1.0f); //set the color to RED and render X
  70 + glVertex3f(0.0, 0.0, 0.0);
  71 + glVertex3f(0.0, 0.0, 100.0);
  72 + glEnd();
  73 +}
  74 +
  75 +void render_lights() {
  76 +
  77 + stim::vec3<float> view = cam.getDirection(); //get the camera view direction
  78 + stim::vec3<float> up = cam.getUp(); //get the camera up direction
  79 + stim::vec3<float> left = view.cross(up).norm(); //create a vector pointing to the left
  80 +
  81 + GLfloat light0_diffuse[] = { 0.5f, 0.5f, 0.5f, 1 }; //create a directional light shining from the viewer's left
  82 + GLfloat light0_position[] = { left[0], left[1], left[2], 0.0 };
  83 + glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_diffuse);
  84 + glLightfv(GL_LIGHT0, GL_POSITION, light0_position);
  85 +
  86 + GLfloat light1_diffuse[] = { 0.8f, 0.8f, 0.8f, 1 }; //create a directional light shining from the viewer's position
  87 + GLfloat light1_position[] = { -view[0], -view[1], -view[2], 0.0 };
  88 + glLightfv(GL_LIGHT1, GL_DIFFUSE, light0_diffuse);
  89 + glLightfv(GL_LIGHT1, GL_POSITION, light1_position);
  90 +
  91 +
  92 +}
  93 +
53 94 //code that is run every time the user changes something
54 95 void display(){
55 96 //clear the screen
... ... @@ -73,28 +114,28 @@ void display(){
73 114 //specify the camera parameters to OpenGL
74 115 gluLookAt(p[0], p[1], p[2], d[0], d[1], d[2], u[0], u[1], u[2]);
75 116  
76   - //draw the sphere
77   - if (interp)
78   - R = (S * (1.0f - alpha) + Si * alpha);
79   - else
80   - R = S;
81   - R.glRender();
82   -
83   -
84   - //glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
85   -
86   - //draw the z-axis if requested
87   - if(zaxis){
88   - glDisable(GL_TEXTURE_2D);
89   - glColor3f(0.0f, 1.0f, 0.0f);
90   - glBegin(GL_LINES);
91   - glVertex3f(0.0, 0.0, 0.0);
92   - glVertex3f(0.0, 0.0, 100.0);
93   - glEnd();
  117 + if (light) {
  118 + glEnable(GL_LIGHTING);
  119 + glEnable(GL_LIGHT0);
  120 + glEnable(GL_LIGHT1);
  121 + }
  122 +
  123 + glEnable(GL_COLOR_MATERIAL);
  124 + glEnable(GL_CULL_FACE);
  125 + glEnable(GL_DEPTH_TEST);
  126 +
  127 + render_lights(); //render the lights
  128 + glColor3f(1.0, 1.0, 1.0);
  129 + SH.render();
  130 +
  131 + if (light) {
  132 + glDisable(GL_LIGHTING); //disable lighting to render the axes
  133 + glDisable(GL_LIGHT0);
  134 + glDisable(GL_LIGHT1);
94 135 }
95 136  
96   - //flush commands on the GPU
97   - glutSwapBuffers();
  137 + if(axis) render_axes(); //render the axes if the user requests them
  138 + glutSwapBuffers(); //swap in the back buffer (double-buffering is used to prevent tearing)
98 139 }
99 140  
100 141 void mouse_press(int button, int state, int x, int y){
... ... @@ -104,11 +145,8 @@ void mouse_press(int button, int state, int x, int y){
104 145 rotate_zoom = true;
105 146 else if(button == GLUT_RIGHT_BUTTON)
106 147 rotate_zoom = false;
107   -
108   - //if the mouse is pressed
109   - if(state == GLUT_DOWN){
110   - //set the current mouse position
111   - mx = x; my = y;
  148 + if(state == GLUT_DOWN){ //if the mouse is pressed
  149 + mx = x; my = y; //set the current mouse position
112 150 }
113 151 }
114 152  
... ... @@ -139,28 +177,26 @@ float uniformRandom()
139 177 }
140 178  
141 179 std::vector<stim::vec3 <float> >
142   -sample_sphere(int num_samples, float radius = 1.0)
143   -{
  180 +sample_sphere(int num_samples, float radius = 1.0) {
144 181  
145   - float solidAngle = stim::TAU; ///Solid angle to sample over
146   - float PHI[2], Z[2], range; ///Range of angles in cylinderical coordinates
147   - PHI[0] = solidAngle/2; ///project the solid angle into spherical coords
148   - PHI[1] = asin(0); ///
149   - Z[0] = cos(PHI[0]); ///project the z into spherical coordinates
150   - Z[1] = cos(PHI[1]); ///
151   - range = Z[0] - Z[1]; ///the range of all possible z values.
  182 + float solidAngle = (float)stim::TAU; ///Solid angle to sample over
  183 + float PHI[2], Z[2], range; ///Range of angles in cylinderical coordinates
  184 + PHI[0] = solidAngle/2; ///project the solid angle into spherical coords
  185 + PHI[1] = (float)asin(0);
  186 + Z[0] = cos(PHI[0]); ///project the z into spherical coordinates
  187 + Z[1] = cos(PHI[1]);
  188 + range = Z[0] - Z[1]; ///the range of all possible z values.
152 189  
153   - float z, theta, phi; /// temporary individual
  190 + float z, theta, phi; /// temporary individual
154 191  
155 192 std::vector<stim::vec3<float> > samples;
156 193  
157   - //srand(time(NULL)); ///set random seed
158   - srand(100); ///set random seed
  194 + srand(100); ///set random seed
159 195  
160 196 for(int i = 0; i < num_samples; i++)
161 197 {
162 198 z = uniformRandom()*range + Z[1];
163   - theta = uniformRandom() * stim::TAU;
  199 + theta = uniformRandom() * (float)stim::TAU;
164 200 phi = acos(z);
165 201 stim::vec3<float> sph(1, theta, phi);
166 202 stim::vec3<float> cart = sph.sph2cart();
... ... @@ -187,37 +223,81 @@ sample_sphere(int num_samples, float radius = 1.0)
187 223 return samples;
188 224 }
189 225  
  226 +std::vector<stim::vec3<float>> obj2vec3(stim::obj<float>& o) {
  227 + stim::vec3<float> c = o.centroid(); //calculate the centroid
  228 + size_t nv = o.numV(); //get the number of vertices in the obj file
  229 + std::vector<stim::vec3<float>> vlist(nv); //create an array to store the vertices
  230 + stim::vec3<float> p, v, s;
  231 + for (size_t vi = 0; vi < nv; vi++) { //for each vertex in the obj file
  232 + v = o.getV(vi);
  233 + p = (v - c); //center and normalize
  234 + s = p.cart2sph(); //convert to spherical coordinates
  235 + vlist[vi] = s; //store the spherical coordinates in the point list
  236 + }
  237 + return vlist;
  238 +}
  239 +
  240 +void advertise() {
  241 + std::cout << "usage: shview c0 c1 c2 c3 ... --option [A B C]" << std::endl;
  242 + std::cout << "examples:" << std::endl;
  243 + std::cout << " generate a spherical function with 4 coefficients (l=0 to 2)" << std::endl;
  244 + std::cout << " shview 1.3 0.2 2.3 1.34" << std::endl;
  245 + std::cout << " display a spherical function representing the spherical harmonic l = 3, m = -2" << std::endl;
  246 + std::cout << " shview --basis 3 -2" << std::endl;
  247 + std::cout << args.str();
  248 + exit(0);
  249 +}
  250 +
190 251 void process_arguments(int argc, char* argv[]){
191 252  
192 253 args.add("help", "prints this help");
  254 + args.section("Coefficients");
  255 + args.add("coef", "specify spherical harmonic coefficients", "", "c0 c1 c2 c3 ...");
193 256 args.add("rand", "generates a random set of SH coefficients", "", "[N min max]");
194 257 args.add("sparse", "generates a function based on a set of sparse basis functions", "", "[l0 m0 c0 l1 m1 c1 l2 m2 c2 ...]");
195   - args.add("basis", "displays the specified SH basis function", "", "n, or [l m]");
  258 + args.section("Projection");
  259 + args.add("image", "approximates a spherical function represented by an image", "", "filename1.ppm filename2.ppm");
  260 + args.add("n", "number of spherical harmonics coefficients to use for a projection", "10", "positive integer");
  261 + args.add("basis", "displays the specified SH basis function", "", "n, or [l m]");
196 262 args.add("obj", "approximates a geometric object given as a Wavefront OBJ file", "", "filename");
197 263 args.add("out", "filename for outputting spherical harmonics coefficients", "", "filename");
198   - args.add("zaxis", "render the z-axis as a green line");
199 264 args.add("pdf", "outputs the PDF if an OBJ files is given");
  265 + args.section("Visualization");
  266 + args.add("axis", "render the z-axis as a green line");
  267 + args.add("nodisp", "render the spherical function without displacement");
  268 + args.add("nocmap", "render the spherical function without color mapping");
  269 + args.add("nomag", "render the spherical function without calculating the absolute value (negative values are displaced negatively");
  270 + args.add("nolight", "render the spherical function without lighting");
200 271 args.add("interp", "interpolates between two specified sets of coefficients", "", "[c0 c1 c2 c3 ...]");
201 272  
202 273 //process the command line arguments
203 274 args.parse(argc, argv);
204 275  
205   - //set the z-axis flag
206   - if(args["zaxis"].is_set())
207   - zaxis = true;
208   -
209   - if (args["interp"]) { //if an interpolation harmonic is provided
210   - for (unsigned int a = 0; a < args["interp"].nargs(); a++)
211   - Si.push(args["interp"].as_float(a));
  276 + //if the user asks for help, give it and exit
  277 + if (args["help"].is_set()) {
  278 + advertise();
212 279 }
213 280  
  281 + //set the z-axis flag
  282 + if(args["axis"].is_set())
  283 + axis = true;
  284 + if (args["nodisp"]) displace = false;
  285 + if (args["nocmap"]) cmap = false;
  286 + if (args["nomag"]) mag = false;
  287 + if (args["nolight"]) light = false;
  288 + SH.rendermode(displace, cmap, mag);
  289 +
  290 + //if (args["interp"]) { //if an interpolation harmonic is provided
  291 + // for (unsigned int a = 0; a < args["interp"].nargs(); a++)
  292 + // Si.push(args["interp"].as_float(a));
  293 + //}
  294 +
214 295 //if arguments are specified, push them as coefficients
215   - if(args.nargs() > 0){
  296 + if(args["coef"]){
216 297 //push all of the arguments to the spherical harmonics class as coefficients
217   - for(unsigned int a = 0; a < args.nargs(); a++)
218   - S.push(atof(args.arg(a).c_str()));
  298 + for(unsigned int a = 0; a < args["coef"].nargs(); a++)
  299 + SH.push((float)args["coef"].as_float(a));
219 300 }
220   -
221 301 //if the user wants to use a random set of SH coefficients
222 302 else if(args["rand"].is_set()){
223 303  
... ... @@ -228,21 +308,21 @@ void process_arguments(int argc, char* argv[]){
228 308 }
229 309  
230 310 //seed the random number generator
231   - srand(time(NULL));
  311 + srand((unsigned int)time(NULL));
232 312  
233   - unsigned int N = args["rand"].as_int(0); //get the number of random coefficients
234   - double Cmin = args["rand"].as_float(1); //get the minimum and maximum coefficient values
235   - double Cmax = args["rand"].as_float(2);
  313 + unsigned int N = args["rand"].as_int(0); //get the number of random coefficients
  314 + float Cmin = (float)args["rand"].as_float(1); //get the minimum and maximum coefficient values
  315 + float Cmax = (float)args["rand"].as_float(2);
236 316  
237 317 //generate the coefficients
238 318 for(unsigned int c = 0; c < N; c++){
239 319  
240   - double norm = (double) rand() / RAND_MAX; //calculate a random number in the range [0, 1]
241   - double scaled = norm * (Cmax - Cmin) + Cmin; //scale the random number to [Cmin, Cmax]
242   - S.push(scaled); //push the value as a coefficient
  320 + float norm = (float) rand() / RAND_MAX; //calculate a random number in the range [0, 1]
  321 + float scaled = norm * (Cmax - Cmin) + Cmin; //scale the random number to [Cmin, Cmax]
  322 + SH.push(scaled); //push the value as a coefficient
243 323 }
244 324 }
245   - else if(args["sparse"].is_set()){
  325 + else if (args["sparse"].is_set()) {
246 326  
247 327 //calculate the number of sparse coefficients
248 328 unsigned int nC = args["sparse"].nargs() / 3;
... ... @@ -256,36 +336,59 @@ void process_arguments(int argc, char* argv[]){
256 336 int l, m;
257 337 double v;
258 338 //for each provided coefficient
259   - for(unsigned int i = 0; i < nC; i++){
  339 + for (unsigned int i = 0; i < nC; i++) {
260 340  
261 341 //load data for a single coefficient from the command line
262   - l = args["sparse"].as_int( i * 3 + 0 );
263   - m = args["sparse"].as_int( i * 3 + 1 );
264   - v = args["sparse"].as_float( i * 3 + 2 );
  342 + l = args["sparse"].as_int(i * 3 + 0);
  343 + m = args["sparse"].as_int(i * 3 + 1);
  344 + v = args["sparse"].as_float(i * 3 + 2);
265 345  
266 346 //calculate the 1D coefficient
267 347 c = pow(l + 1, 2) - (l - m) - 1;
268 348  
269 349 //update the maximum coefficient index
270   - if(c > Cmax) Cmax = c;
  350 + if (c > Cmax) Cmax = c;
271 351  
272 352 //insert the coefficient and value into vectors
273 353 C.push_back(c);
274   - V.push_back(v);
  354 + V.push_back(v);
275 355 }
276 356  
277 357 //set the size of the SH coefficient array
278   - S.resize(Cmax + 1);
279   -
  358 + SH.resize(Cmax + 1);
  359 +
280 360 //insert each coefficient
281   - for(unsigned int i = 0; i < nC; i++){
282   - S.setc(C[i], V[i]);
  361 + for (unsigned int i = 0; i < nC; i++) {
  362 + SH.setc(C[i], V[i]);
  363 + }
  364 + }
  365 + else if (args["image"]) {
  366 + if (args["image"].nargs() == 0) {
  367 + std::cout << "ERROR: an image file must be specified as an argument to --image" << std::endl;
  368 + exit(1);
  369 + }
  370 + stim::image<float> I(args["image"].as_string(0)); //load the image
  371 + if (I.channels() > 1) I = I.channel(0); //if a color image is provided, convert to monochrome
  372 + I = I.stretch(0.0f, 1.0f); //stretch the function so that it lies in [0 1]
  373 + SH.project(I.data(), I.width(), I.height(), args["n"].as_int(0)); //project the image function onto a spherical harmonics basis
  374 + if (args["image"].nargs() > 1) { //if the user provides two images
  375 + I.load(args["image"].as_string(1));
  376 + if (I.channels() > 1) I = I.channel(0); //if a color image is provided, convert to monochrome
  377 + I = I.stretch(0.0f, 1.0f); //stretch the function so that it lies in [0 1]
  378 + SH.Sc.project(I.data(), I.width(), I.height(), args["n"].as_int(0));
283 379 }
284   -
285 380 }
  381 +
286 382 else if(args["obj"].is_set()){
  383 + if (args["obj"].nargs() == 0) {
  384 + std::cout << "ERROR: an OBJ file must be specified as an argument to --obj" << std::endl;
  385 + exit(1);
  386 + }
  387 + stim::obj<float> OBJ(args["obj"].as_string(0)); //open the OBJ file
  388 + std::vector<stim::vec3<float>> vlist = obj2vec3(OBJ); //get the centered points for the OBJ
  389 + SH.pdf(vlist, args["n"].as_int(0));
287 390  
288   - std::string filename = args["obj"].as_string(0);
  391 + /*std::string filename = args["obj"].as_string(0);
289 392 unsigned int l = args["obj"].as_int(1);
290 393 int p = args["obj"].as_int(2);
291 394 std::cout << p << std::endl;
... ... @@ -354,9 +457,9 @@ void process_arguments(int argc, char* argv[]){
354 457 S.mcSample(sph[1], sph[2], weights[i]);
355 458 }
356 459 S.mcEnd();
357   -
  460 + */
358 461 }
359   - else{
  462 + /*else{
360 463 //begin Monte-Carlo sampling, using the model vertices as samples
361 464 S.mcBegin(l, l);
362 465 double theta, phi, fx, px;
... ... @@ -368,11 +471,11 @@ void process_arguments(int argc, char* argv[]){
368 471 S.mcSample(theta, phi, fx / px);
369 472 }
370 473 S.mcEnd();
371   - }
372   - }
  474 + }*/
  475 + //}
373 476  
374 477 //if the user specifies an SH basis function
375   - else if(args["basis"].is_set()){
  478 + /*if(args["basis"].is_set()){
376 479  
377 480 unsigned int n;
378 481  
... ... @@ -388,14 +491,14 @@ void process_arguments(int argc, char* argv[]){
388 491  
389 492 //add zeros for the first (n-1) coefficients
390 493 for(unsigned int c = 0; c < n; c++)
391   - S.push(0);
  494 + SH.push(0);
392 495  
393 496 //add the n'th coefficient
394   - S.push(1);
395   - }
  497 + SH.push(1);
  498 + }*/
396 499  
397 500 //output the spherical harmonics coefficients if requested
398   - if(args["out"].is_set()){
  501 + /*if(args["out"].is_set()){
399 502  
400 503 if(args["out"].nargs() == 0)
401 504 std::cout<<S.str()<<std::endl;
... ... @@ -409,26 +512,7 @@ void process_arguments(int argc, char* argv[]){
409 512  
410 513 outfile.close();
411 514 }
412   - }
413   -
414   -
415   -
416   -
417   -
418   - //if the user asks for help, give it and exit
419   - if(args["help"].is_set()){
420   - std::cout<<"usage: shview c0 c1 c2 c3 ... --option [A B C]"<<std::endl;
421   - std::cout<<"examples:"<<std::endl;
422   - std::cout<<" generate a spherical function with 4 coefficients (l=0 to 2)"<<std::endl;
423   - std::cout<<" shview 1.3 0.2 2.3 1.34"<<std::endl;
424   - std::cout<<" display a spherical function representing the spherical harmonic l = 3, m = -2"<<std::endl;
425   - std::cout<<" shview --basis 3 -2"<<std::endl;
426   -
427   -
428   -
429   - std::cout<<args.str();
430   - exit(0);
431   - }
  515 + }*/
432 516 }
433 517  
434 518 int main(int argc, char *argv[]){
... ... @@ -451,6 +535,9 @@ int main(int argc, char *argv[]){
451 535 //create the GLUT window (and an OpenGL context)
452 536 glutCreateWindow("Spherical Harmonic Viewport");
453 537  
  538 + //SH.rendermode(false, true, true);
  539 + //SH.colormap(); //use color-mapping
  540 +
454 541 //set the display function (which will be called repeatedly by glutMainLoop)
455 542 glutDisplayFunc(display);
456 543  
... ...