浏览代码

merge

Former-commit-id: 1de52832499111c778af97e021ad138450775501
Alec Jacobson (jalec 11 年之前
父节点
当前提交
d4dd58b422

+ 0 - 3
examples/ambient-occlusion-mex/mexFunction.cpp

@@ -1,10 +1,7 @@
 #include "parse_rhs.h"
 
 #include <igl/matlab/mexStream.h>
-#include <igl/matlab/MatlabWorkspace.h>
-#include <igl/embree/EmbreeIntersector.h>
 #include <igl/embree/ambient_occlusion.h>
-#include <igl/matlab_format.h>
 
 #include <igl/read.h>
 #include <igl/per_vertex_normals.h>

+ 2 - 2
examples/ambient-occlusion/Makefile

@@ -9,8 +9,8 @@ all: example
 .PHONY: example
 
 LIBIGL=../../
-LIBIGL_INC=-I$(LIBIGL)/include -DIGL_HEADER_ONLY
-#LIBIGL_LIB=-L$(LIBIGL)/lib -ligl -liglembree
+LIBIGL_INC=-I$(LIBIGL)/include
+LIBIGL_LIB=-L$(LIBIGL)/lib -ligl -liglembree
 
 EIGEN3_INC=-I/opt/local/include/eigen3 -I/opt/local/include/eigen3/unsupported
 

+ 3 - 4
examples/ambient-occlusion/example.cpp

@@ -48,7 +48,7 @@ Eigen::MatrixXd V,N,C,mid;
 Eigen::MatrixXi F;
 // Bounding box diagonal length
 double bbd;
-igl::EmbreeIntersector<Eigen::MatrixXd::Scalar,Eigen::MatrixXi::Scalar> * ei;
+igl::EmbreeIntersector ei;
 // Running ambient occlusion
 Eigen::VectorXd S;
 int tot_num_samples = 0;
@@ -154,7 +154,7 @@ void display()
     }
     VectorXd Si;
     const int num_samples = 20;
-    ambient_occlusion(*ei,V,N,num_samples,Si);
+    ambient_occlusion(ei,V,N,num_samples,Si);
     S *= (double)tot_num_samples;
     S += Si*(double)num_samples;
     tot_num_samples += num_samples;
@@ -373,7 +373,7 @@ int main(int argc, char * argv[])
   bbd = (V.colwise().maxCoeff() - V.colwise().minCoeff()).maxCoeff();
 
   // Init embree
-  ei = new EmbreeIntersector<MatrixXd::Scalar,MatrixXi::Scalar>(V,F);
+  ei.init(V.cast<float>(),F.cast<int>());
 
   // Init glut
   glutInit(&argc,argv);
@@ -405,6 +405,5 @@ int main(int argc, char * argv[])
   glutMotionFunc(mouse_drag);
   glutPassiveMotionFunc((GLUTmousemotionfun)TwEventMouseMotionGLUT);
   glutMainLoop();
-  delete ei;
   return 0;
 }

+ 2 - 0
examples/embree/Makefile

@@ -9,6 +9,8 @@ all: example
 .PHONY: example
 
 LIBIGL=../../
+#LIBIGL_INC=-I$(LIBIGL)/include -DIGL_HEADER_ONLY
+#LIBIGL_LIB=
 LIBIGL_INC=-I$(LIBIGL)/include
 LIBIGL_LIB=-L$(LIBIGL)/lib -ligl -liglembree
 

+ 19 - 28
examples/embree/example.cpp

@@ -1,4 +1,3 @@
-#define IGL_HEADER_ONLY
 #include <igl/embree/EmbreeIntersector.h>
 #include <igl/OpenGL_convenience.h>
 #include <igl/per_face_normals.h>
@@ -38,11 +37,11 @@ double bbd;
 // Faces
 Eigen::MatrixXi F;
 // Embree intersection structure
-igl::EmbreeIntersector<double,int> * ei;
+igl::EmbreeIntersector ei;
 // Hits collected
 std::vector<igl::Hit > hits;
 // Ray information, "projection screen" corners
-Eigen::Vector3d win_s,s,d,dir,NW,NE,SE,SW;
+Eigen::Vector3f win_s,s,d,dir,NW,NE,SE,SW;
 // Textures and framebuffers for "projection screen"
 GLuint tex_id = 0, fbo_id = 0, dfbo_id = 0;
 
@@ -192,18 +191,18 @@ void display()
     glEnable(GL_DEPTH_TEST);
     glBegin(GL_LINES);
     glColor3f(1,0,0);
-    glVertex3dv(s.data());
+    glVertex3fv(s.data());
     glColor3f(1,0,0);
-    glVertex3dv(d.data());
+    glVertex3fv(d.data());
     glEnd();
 
     // Draw the start and end points used for ray
     glPointSize(10.0);
     glBegin(GL_POINTS);
     glColor3f(1,0,0);
-    glVertex3dv(s.data());
+    glVertex3fv(s.data());
     glColor3f(0,0,1);
-    glVertex3dv(d.data());
+    glVertex3fv(d.data());
     glEnd();
   }
 
@@ -246,10 +245,10 @@ void display()
     glColor4f(0,0,0,1.0);
     glPointSize(10.0);
     glBegin(GL_POINTS);
-    glVertex3dv(SW.data());
-    glVertex3dv(SE.data());
-    glVertex3dv(NE.data());
-    glVertex3dv(NW.data());
+    glVertex3fv(SW.data());
+    glVertex3fv(SE.data());
+    glVertex3fv(NE.data());
+    glVertex3fv(NW.data());
     glEnd();
 
     glDisable(GL_LIGHTING);
@@ -258,13 +257,13 @@ void display()
     glColor4f(1,1,1,0.7);
     glBegin(GL_QUADS);
     glTexCoord2d(0,0);
-    glVertex3dv(SW.data());
+    glVertex3fv(SW.data());
     glTexCoord2d(1,0);
-    glVertex3dv(SE.data());
+    glVertex3fv(SE.data());
     glTexCoord2d(1,1);
-    glVertex3dv(NE.data());
+    glVertex3fv(NE.data());
     glTexCoord2d(0,1);
-    glVertex3dv(NW.data());
+    glVertex3fv(NW.data());
     glEnd();
     glBindTexture(GL_TEXTURE_2D, 0);
     glDisable(GL_TEXTURE_2D);
@@ -288,7 +287,7 @@ void display()
     glLoadIdentity();
     glPointSize(20.0);
     glBegin(GL_POINTS);
-    glVertex2dv(win_s.data());
+    glVertex2fv(win_s.data());
     glEnd();
   }
   report_gl_error();
@@ -317,8 +316,8 @@ void mouse_move(int mouse_x, int mouse_y)
   push_scene();
   push_object();
   // Unproject mouse at 0 depth and some positive depth
-  win_s = Vector3d(mouse_x,height-mouse_y,0);
-  Vector3d win_d(mouse_x,height-mouse_y,1);
+  win_s = Vector3f(mouse_x,height-mouse_y,0);
+  Vector3f win_d(mouse_x,height-mouse_y,1);
   unproject(win_s,s);
   unproject(win_d,d);
   pop_object();
@@ -327,7 +326,7 @@ void mouse_move(int mouse_x, int mouse_y)
   // Shoot ray at unprojected mouse in view direction
   dir = d-s;
   int num_rays_shot;
-  ei->intersectRay(s,dir,hits,num_rays_shot);
+  ei.intersectRay(s,dir,hits,num_rays_shot);
   for(vector<igl::Hit>::iterator hit = hits.begin();
       hit != hits.end();
       hit++)
@@ -417,12 +416,6 @@ void mouse_drag(int mouse_x, int mouse_y)
 }
 
 
-void cleanup()
-{
-  using namespace std;
-  delete ei;
-}
-
 void key(unsigned char key, int mouse_x, int mouse_y)
 {
   using namespace std;
@@ -431,7 +424,6 @@ void key(unsigned char key, int mouse_x, int mouse_y)
     // Ctrl-c and esc exit
     case char(3):
     case char(27):
-      cleanup();
       exit(0);
     default:
       cout<<"Unknown key command: "<<key<<" "<<int(key)<<endl;
@@ -471,7 +463,7 @@ int main(int argc, char * argv[])
     V.colwise().minCoeff()).maxCoeff();
 
   // Init embree
-  ei = new EmbreeIntersector<double,int>(V,F);
+  ei.init(V.cast<float>(),F.cast<int>());
 
   // Init glut
   glutInit(&argc,argv);
@@ -485,6 +477,5 @@ int main(int argc, char * argv[])
   glutMotionFunc(mouse_drag);
   glutPassiveMotionFunc(mouse_move);
   glutMainLoop();
-  cleanup();
   return 0;
 }

+ 143 - 22
examples/patches/example.cpp

@@ -30,6 +30,8 @@
 #include <igl/orient_outward.h>
 #include <igl/embree/orient_outward_ao.h>
 #include <igl/unique_simplices.h>
+#include <igl/C_STR.h>
+#include <igl/write.h>
 
 #include <Eigen/Core>
 #include <Eigen/Geometry>
@@ -54,6 +56,7 @@
 #include <stack>
 #include <iostream>
 
+int cc_selected = -1;
 
 Eigen::MatrixXd V;
 Eigen::VectorXd Vmid,Vmin,Vmax;
@@ -66,6 +69,7 @@ struct State
   Eigen::MatrixXd N;
   Eigen::MatrixXd C;
 } s;
+std::string out_filename;
 
 // See README for descriptions
 enum RotationType
@@ -75,6 +79,13 @@ enum RotationType
   NUM_ROTATION_TYPES = 2,
 } rotation_type;
 
+enum OrientMethod
+{
+  ORIENT_METHOD_OUTWARD = 0,
+  ORIENT_METHOD_AO = 1,
+  NUM_ORIENT_METHODS = 2,
+} orient_method = ORIENT_METHOD_AO;
+
 std::stack<State> undo_stack;
 std::stack<State> redo_stack;
 
@@ -97,6 +108,10 @@ Eigen::Vector4f light_pos(-0.1,-0.1,0.9,0);
 #define REBAR_NAME "temp.rbr"
 igl::ReTwBar rebar;
 
+// Forward
+void init_patches();
+void init_relative();
+
 void push_undo()
 {
   undo_stack.push(s);
@@ -112,6 +127,23 @@ void TW_CALL set_camera_rotation(const void * value, void *clientData)
   std::copy(quat,quat+4,s.camera.rotation);
 }
 
+void TW_CALL set_orient_method(const void * value, void * clientData)
+{
+  const OrientMethod old_orient_method = orient_method;
+  orient_method = *(const OrientMethod *)value;
+  if(orient_method != old_orient_method)
+  {
+    init_patches();
+    init_relative();
+  }
+}
+
+void TW_CALL get_orient_method(void * value, void *clientData)
+{
+  OrientMethod * om = (OrientMethod *)(value);
+  *om = orient_method;
+}
+
 void TW_CALL set_rotation_type(const void * value, void * clientData)
 {
   using namespace Eigen;
@@ -299,6 +331,38 @@ void display()
     {
       draw_mesh(V,F,s.N,s.C);
     }
+  
+    // visualize selected patch
+    glLineWidth(10);
+    glBegin(GL_TRIANGLES);
+    glColor3d(0, 0, 0);
+    // loop over faces
+    for(int i = 0; i<F.rows();i++)
+    {
+      if (CC(i) != cc_selected) continue;
+      // loop over corners of triangle
+      for(int j = 0;j<3;j++)
+      {
+        glVertex3d(V(F(i,j),0),V(F(i,j),1),V(F(i,j),2));
+      }
+    }
+    glEnd();
+    glLineWidth(1);
+    glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
+    glBegin(GL_TRIANGLES);
+    glColor3d(1, 0, 0);
+    // loop over faces
+    for(int i = 0; i<F.rows();i++)
+    {
+      if (CC(i) != cc_selected) continue;
+      // loop over corners of triangle
+      glNormal3d(s.N(i,0),s.N(i,1),s.N(i,2));
+      for(int j = 0;j<3;j++)
+      {
+        glVertex3d(V(F(i,j),0),V(F(i,j),1),V(F(i,j),2));
+      }
+    }
+    glEnd();
   }
   glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
   if(fill_visible)
@@ -539,20 +603,20 @@ void init_patches()
   }
   bfs_orient(F,F,CC);
   VectorXi I;
-  char c;
-  cout << "use ambient occlusion to determine patch orientation? (y/n):";
-  cin >> c;
-  if (c == 'y')
-  {
-    orient_outward_ao(V,F,CC,F.rows() * 100,F,I);
-  }
-  else
+  switch(orient_method)
   {
-    orient_outward(V,F,CC,F,I);
+    case ORIENT_METHOD_AO:
+      cout<<"orient_outward_ao()"<<endl;
+      orient_outward_ao(V,F,CC,100, F.rows() * 100,F,I);
+      break;
+    case ORIENT_METHOD_OUTWARD:
+    default:
+      cout<<"orient_outward()"<<endl;
+      orient_outward(V,F,CC,F,I);
+      break;
   }
   double num_cc = (double)CC.maxCoeff()+1.0;
   cout<<"There are "<<num_cc<<" 'manifold/orientable' patches of faces."<<endl;
-  randomly_color(CC,s.C);
 }
 
 void undo()
@@ -577,6 +641,26 @@ void redo()
   }
 }
 
+bool save(const std::string & out_filename)
+{
+  using namespace std;
+  using namespace igl;
+  if(write(out_filename,V,F))
+  {
+    cout<<GREENGIN("Saved mesh to `"<<out_filename<<"` successfully.")<<endl;
+    return true;
+  }else
+  {
+    cout<<REDRUM("Failed to save mesh to `"<<out_filename<<"`.")<<endl;
+    return false;
+  }
+}
+
+void TW_CALL saveCB(void * /*clientData*/)
+{
+  save(out_filename);
+}
+
 void key(unsigned char key, int mouse_x, int mouse_y)
 {
   using namespace std;
@@ -594,6 +678,7 @@ void key(unsigned char key, int mouse_x, int mouse_y)
       {
         push_undo();
         s.N *= -1.0;
+        F = F.rowwise().reverse().eval();
         break;
       }
     case 'z':
@@ -617,6 +702,17 @@ void key(unsigned char key, int mouse_x, int mouse_y)
           s.camera.rotation);
         break;
       }
+    case 'u':
+        mouse_wheel(0, 1,mouse_x,mouse_y);
+        break;
+    case 'j':
+        mouse_wheel(0,-1,mouse_x,mouse_y);
+        break;
+    case 'n':
+      cc_selected = (cc_selected + 1) % (CC.maxCoeff() + 2);
+      cout << "selected cc: " << cc_selected << endl;
+      glutPostRedisplay();
+      break;
     default:
       if(!TwEventKeyboardGLUT(key,mouse_x,mouse_y))
       {
@@ -632,21 +728,25 @@ int main(int argc, char * argv[])
   using namespace Eigen;
   using namespace igl;
   string filename = "../shared/truck.obj";
-  if(argc < 2)
+  switch(argc)
   {
-    cerr<<"Usage:"<<endl<<"    ./example input.obj"<<endl;
-    cout<<endl<<"Opening default mesh..."<<endl;
-  }else
-  {
-    // Read and prepare mesh
-    filename = argv[1];
+    case 3:
+      out_filename = argv[2];
+    case 2:
+      // Read and prepare mesh
+      filename = argv[1];
+      break;
+    default:
+      cerr<<"Usage:"<<endl<<"    ./example input.obj (output.obj)"<<endl;
+      cout<<endl<<"Opening default mesh..."<<endl;
+      break;
   }
 
   // print key commands
   cout<<"[Click] and [drag]  Rotate model using trackball."<<endl;
   cout<<"[Z,z]               Snap rotation to canonical view."<<endl;
-  cout<<"[⌘ Z]               Undo."<<endl;
-  cout<<"[⇧ ⌘ Z]             Redo."<<endl;
+  cout<<"[Command+Z]         Undo."<<endl;
+  cout<<"[Shift+Command+Z]   Redo."<<endl;
   cout<<"[^C,ESC]            Exit."<<endl;
 
   // dirname, basename, extension and filename
@@ -703,8 +803,8 @@ int main(int argc, char * argv[])
   F = F_unique;
 
   init_patches();
-
   init_relative();
+  randomly_color(CC,s.C);
 
   // Init glut
   glutInit(&argc,argv);
@@ -715,7 +815,8 @@ int main(int argc, char * argv[])
     return 1;
   }
   // Create a tweak bar
-  rebar.TwNewBar("TweakBar");
+  rebar.TwNewBar("bar");
+  TwDefine("bar label='Patches' size='200 550' text=light alpha='200' color='68 68 68'");
   rebar.TwAddVarCB("camera_rotation", TW_TYPE_QUAT4D, set_camera_rotation,get_camera_rotation, NULL, "open readonly=true");
   TwEnumVal RotationTypesEV[NUM_ROTATION_TYPES] = 
   {
@@ -729,9 +830,29 @@ int main(int argc, char * argv[])
         NUM_ROTATION_TYPES);
   rebar.TwAddVarCB( "rotation_type", RotationTypeTW,
     set_rotation_type,get_rotation_type,NULL,"keyIncr=] keyDecr=[");
+  TwEnumVal OrientMethodEV[NUM_ORIENT_METHODS] = 
+  {
+    {ORIENT_METHOD_OUTWARD,"outward"},
+    {ORIENT_METHOD_AO,"ambient occlusion"}
+  };
+  TwType OrientMethodTW = 
+    ReTwDefineEnum(
+        "OrientMethod", 
+        OrientMethodEV, 
+        NUM_ROTATION_TYPES);
+  rebar.TwAddVarCB( "orient_method", OrientMethodTW,
+    set_orient_method,get_orient_method,NULL,"keyIncr=< keyDecr=>");
+
   rebar.TwAddVarRW("wireframe_visible",TW_TYPE_BOOLCPP,&wireframe_visible,"key=l");
   rebar.TwAddVarRW("fill_visible",TW_TYPE_BOOLCPP,&fill_visible,"key=f");
-  rebar.TwAddButton("randomize colors",randomize_colors,NULL,"key=c");
+  rebar.TwAddButton("randomize_colors",randomize_colors,NULL,"key=c");
+  if(out_filename != "")
+  {
+    rebar.TwAddButton("save",
+      saveCB,NULL,
+      C_STR("label='Save to `"<<out_filename<<"`' "<<
+      "key=s"));
+  }
   rebar.load(REBAR_NAME);
 
 

+ 20 - 0
examples/patches/example.sln

@@ -0,0 +1,20 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2012
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example", "example.vcxproj", "{7F5B7683-7531-481C-8997-6221D7170894}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Win32 = Debug|Win32
+		Release|Win32 = Release|Win32
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{7F5B7683-7531-481C-8997-6221D7170894}.Debug|Win32.ActiveCfg = Debug|Win32
+		{7F5B7683-7531-481C-8997-6221D7170894}.Debug|Win32.Build.0 = Debug|Win32
+		{7F5B7683-7531-481C-8997-6221D7170894}.Release|Win32.ActiveCfg = Release|Win32
+		{7F5B7683-7531-481C-8997-6221D7170894}.Release|Win32.Build.0 = Release|Win32
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal

+ 54 - 33
examples/patches/example.vcxproj

@@ -20,14 +20,14 @@
     <ConfigurationType>Application</ConfigurationType>
     <UseDebugLibraries>true</UseDebugLibraries>
     <PlatformToolset>v110</PlatformToolset>
-    <CharacterSet>Unicode</CharacterSet>
+    <CharacterSet>MultiByte</CharacterSet>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
     <UseDebugLibraries>false</UseDebugLibraries>
     <PlatformToolset>v110</PlatformToolset>
     <WholeProgramOptimization>true</WholeProgramOptimization>
-    <CharacterSet>Unicode</CharacterSet>
+    <CharacterSet>MultiByte</CharacterSet>
   </PropertyGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
   <ImportGroup Label="ExtensionSettings">
@@ -58,7 +58,7 @@
       <Optimization>Disabled</Optimization>
       <PreprocessorDefinitions>IGL_HEADER_ONLY;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
-      <AdditionalIncludeDirectories>C:\Users\kenshi\dev\igl_hg\ext_toolboxes\embree-1.1beta\rtcore;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>..\..\external\embree;..\..\external\embree\embree;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <OpenMPSupport>true</OpenMPSupport>
     </ClCompile>
     <Link>
@@ -71,49 +71,70 @@
       <WarningLevel>Level3</WarningLevel>
       <PrecompiledHeader>
       </PrecompiledHeader>
-      <Optimization>MaxSpeed</Optimization>
+      <Optimization>Disabled</Optimization>
       <FunctionLevelLinking>true</FunctionLevelLinking>
       <IntrinsicFunctions>true</IntrinsicFunctions>
       <PreprocessorDefinitions>IGL_HEADER_ONLY;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
-      <AdditionalIncludeDirectories>C:\Users\kenshi\dev\igl_hg\ext_toolboxes\embree-1.1beta\rtcore;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>..\..\external\embree;..\..\external\embree\embree;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
       <OpenMPSupport>true</OpenMPSupport>
     </ClCompile>
     <Link>
       <SubSystem>Console</SubSystem>
       <GenerateDebugInformation>true</GenerateDebugInformation>
       <EnableCOMDATFolding>true</EnableCOMDATFolding>
-      <OptimizeReferences>true</OptimizeReferences>
+      <OptimizeReferences>false</OptimizeReferences>
     </Link>
   </ItemDefinitionGroup>
   <ItemGroup>
-    <ClCompile Include="..\..\..\ext_toolboxes\embree-1.1beta\common\sys\filename.cpp" />
-    <ClCompile Include="..\..\..\ext_toolboxes\embree-1.1beta\common\sys\library.cpp" />
-    <ClCompile Include="..\..\..\ext_toolboxes\embree-1.1beta\common\sys\platform.cpp" />
-    <ClCompile Include="..\..\..\ext_toolboxes\embree-1.1beta\common\sys\stl\string.cpp" />
-    <ClCompile Include="..\..\..\ext_toolboxes\embree-1.1beta\common\sys\sync\condition.cpp" />
-    <ClCompile Include="..\..\..\ext_toolboxes\embree-1.1beta\common\sys\sync\mutex.cpp" />
-    <ClCompile Include="..\..\..\ext_toolboxes\embree-1.1beta\common\sys\sysinfo.cpp" />
-    <ClCompile Include="..\..\..\ext_toolboxes\embree-1.1beta\common\sys\taskscheduler_standard.cpp" />
-    <ClCompile Include="..\..\..\ext_toolboxes\embree-1.1beta\common\sys\thread.cpp" />
-    <ClCompile Include="..\..\..\ext_toolboxes\embree-1.1beta\rtcore\bvh2\bvh2.cpp" />
-    <ClCompile Include="..\..\..\ext_toolboxes\embree-1.1beta\rtcore\bvh2\bvh2_builder.cpp" />
-    <ClCompile Include="..\..\..\ext_toolboxes\embree-1.1beta\rtcore\bvh2\bvh2_intersector.cpp" />
-    <ClCompile Include="..\..\..\ext_toolboxes\embree-1.1beta\rtcore\bvh4mb\bvh4mb.cpp" />
-    <ClCompile Include="..\..\..\ext_toolboxes\embree-1.1beta\rtcore\bvh4mb\bvh4mb_builder.cpp" />
-    <ClCompile Include="..\..\..\ext_toolboxes\embree-1.1beta\rtcore\bvh4mb\bvh4mb_intersector.cpp" />
-    <ClCompile Include="..\..\..\ext_toolboxes\embree-1.1beta\rtcore\bvh4\bvh4.cpp" />
-    <ClCompile Include="..\..\..\ext_toolboxes\embree-1.1beta\rtcore\bvh4\bvh4_builder.cpp" />
-    <ClCompile Include="..\..\..\ext_toolboxes\embree-1.1beta\rtcore\bvh4\bvh4_intersector.cpp" />
-    <ClCompile Include="..\..\..\ext_toolboxes\embree-1.1beta\rtcore\common\accel.cpp" />
-    <ClCompile Include="..\..\..\ext_toolboxes\embree-1.1beta\rtcore\common\alloc.cpp" />
-    <ClCompile Include="..\..\..\ext_toolboxes\embree-1.1beta\rtcore\common\heuristic_binning.cpp" />
-    <ClCompile Include="..\..\..\ext_toolboxes\embree-1.1beta\rtcore\common\heuristic_spatial.cpp" />
-    <ClCompile Include="..\..\..\ext_toolboxes\embree-1.1beta\rtcore\common\primrefgen.cpp" />
-    <ClCompile Include="..\..\..\ext_toolboxes\embree-1.1beta\rtcore\common\splitter.cpp" />
-    <ClCompile Include="..\..\..\ext_toolboxes\embree-1.1beta\rtcore\common\splitter_fallback.cpp" />
-    <ClCompile Include="..\..\..\ext_toolboxes\embree-1.1beta\rtcore\common\splitter_parallel.cpp" />
-    <ClCompile Include="..\..\..\ext_toolboxes\embree-1.1beta\rtcore\common\stat.cpp" />
+    <ClCompile Include="..\..\..\kt84\dbg.cpp" />
+    <ClCompile Include="..\..\external\embree\embree\builders\heuristic_binning.cpp" />
+    <ClCompile Include="..\..\external\embree\embree\builders\heuristic_spatial.cpp" />
+    <ClCompile Include="..\..\external\embree\embree\builders\primrefgen.cpp" />
+    <ClCompile Include="..\..\external\embree\embree\builders\splitter.cpp" />
+    <ClCompile Include="..\..\external\embree\embree\builders\splitter_fallback.cpp" />
+    <ClCompile Include="..\..\external\embree\embree\builders\splitter_parallel.cpp" />
+    <ClCompile Include="..\..\external\embree\embree\bvh2\bvh2.cpp" />
+    <ClCompile Include="..\..\external\embree\embree\bvh2\bvh2_intersector1.cpp" />
+    <ClCompile Include="..\..\external\embree\embree\bvh2\bvh2_intersector4.cpp" />
+    <ClCompile Include="..\..\external\embree\embree\bvh2\bvh2_intersector8.cpp" />
+    <ClCompile Include="..\..\external\embree\embree\bvh4i\bvh4i.cpp" />
+    <ClCompile Include="..\..\external\embree\embree\bvh4i\bvh4i_intersector1.cpp" />
+    <ClCompile Include="..\..\external\embree\embree\bvh4mb\bvh4mb.cpp" />
+    <ClCompile Include="..\..\external\embree\embree\bvh4mb\bvh4mb_builder.cpp" />
+    <ClCompile Include="..\..\external\embree\embree\bvh4mb\bvh4mb_intersector1.cpp" />
+    <ClCompile Include="..\..\external\embree\embree\bvh4mb\bvh4mb_intersector4.cpp" />
+    <ClCompile Include="..\..\external\embree\embree\bvh4mb\bvh4mb_intersector8.cpp" />
+    <ClCompile Include="..\..\external\embree\embree\bvh4\bvh4.cpp" />
+    <ClCompile Include="..\..\external\embree\embree\bvh4\bvh4_intersector1.cpp" />
+    <ClCompile Include="..\..\external\embree\embree\bvh4\bvh4_intersector1_avx.cpp" />
+    <ClCompile Include="..\..\external\embree\embree\bvh4\bvh4_intersector4_chunk.cpp" />
+    <ClCompile Include="..\..\external\embree\embree\bvh4\bvh4_intersector4_hybrid.cpp" />
+    <ClCompile Include="..\..\external\embree\embree\bvh4\bvh4_intersector4_single.cpp" />
+    <ClCompile Include="..\..\external\embree\embree\bvh4\bvh4_intersector8_chunk.cpp" />
+    <ClCompile Include="..\..\external\embree\embree\bvh4\bvh4_intersector8_hybrid.cpp" />
+    <ClCompile Include="..\..\external\embree\embree\bvh4\bvh4_intersector8_single.cpp" />
+    <ClCompile Include="..\..\external\embree\embree\bvh8\bvh8.cpp" />
+    <ClCompile Include="..\..\external\embree\embree\bvh8\bvh8_intersector1.cpp" />
+    <ClCompile Include="..\..\external\embree\embree\common\accel.cpp" />
+    <ClCompile Include="..\..\external\embree\embree\common\alloc.cpp" />
+    <ClCompile Include="..\..\external\embree\embree\common\registry_accel.cpp" />
+    <ClCompile Include="..\..\external\embree\embree\common\registry_builder.cpp" />
+    <ClCompile Include="..\..\external\embree\embree\common\registry_intersector.cpp" />
+    <ClCompile Include="..\..\external\embree\embree\common\stat.cpp" />
+    <ClCompile Include="..\..\external\embree\embree\embree.cpp" />
+    <ClCompile Include="..\..\external\embree\embree\geometry\triangle_mesh.cpp" />
+    <ClCompile Include="..\..\external\embree\embree\geometry\virtual_scene.cpp" />
+    <ClCompile Include="..\..\external\embree\embree\sys\filename.cpp" />
+    <ClCompile Include="..\..\external\embree\embree\sys\platform.cpp" />
+    <ClCompile Include="..\..\external\embree\embree\sys\stl\string.cpp" />
+    <ClCompile Include="..\..\external\embree\embree\sys\sync\condition.cpp" />
+    <ClCompile Include="..\..\external\embree\embree\sys\sync\mutex.cpp" />
+    <ClCompile Include="..\..\external\embree\embree\sys\sysinfo.cpp" />
+    <ClCompile Include="..\..\external\embree\embree\sys\taskscheduler.cpp" />
+    <ClCompile Include="..\..\external\embree\embree\sys\taskscheduler_mic.cpp" />
+    <ClCompile Include="..\..\external\embree\embree\sys\taskscheduler_sys.cpp" />
+    <ClCompile Include="..\..\external\embree\embree\sys\thread.cpp" />
     <ClCompile Include="example.cpp" />
   </ItemGroup>
   <ItemGroup>

+ 117 - 62
examples/patches/example.vcxproj.filters

@@ -2,100 +2,155 @@
 <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <ItemGroup>
     <ClCompile Include="example.cpp" />
-    <ClCompile Include="..\..\..\ext_toolboxes\embree-1.1beta\rtcore\bvh2\bvh2_builder.cpp">
-      <Filter>embree-1.1beta\rtcore</Filter>
+    <ClCompile Include="..\..\external\embree\embree\builders\primrefgen.cpp">
+      <Filter>embree</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\..\ext_toolboxes\embree-1.1beta\rtcore\bvh2\bvh2_intersector.cpp">
-      <Filter>embree-1.1beta\rtcore</Filter>
+    <ClCompile Include="..\..\external\embree\embree\builders\splitter.cpp">
+      <Filter>embree</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\..\ext_toolboxes\embree-1.1beta\rtcore\bvh2\bvh2.cpp">
-      <Filter>embree-1.1beta\rtcore</Filter>
+    <ClCompile Include="..\..\external\embree\embree\builders\splitter_fallback.cpp">
+      <Filter>embree</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\..\ext_toolboxes\embree-1.1beta\rtcore\bvh4\bvh4_intersector.cpp">
-      <Filter>embree-1.1beta\rtcore</Filter>
+    <ClCompile Include="..\..\external\embree\embree\builders\splitter_parallel.cpp">
+      <Filter>embree</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\..\ext_toolboxes\embree-1.1beta\rtcore\bvh4\bvh4.cpp">
-      <Filter>embree-1.1beta\rtcore</Filter>
+    <ClCompile Include="..\..\external\embree\embree\builders\heuristic_binning.cpp">
+      <Filter>embree</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\..\ext_toolboxes\embree-1.1beta\rtcore\bvh4\bvh4_builder.cpp">
-      <Filter>embree-1.1beta\rtcore</Filter>
+    <ClCompile Include="..\..\external\embree\embree\builders\heuristic_spatial.cpp">
+      <Filter>embree</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\..\ext_toolboxes\embree-1.1beta\rtcore\bvh4mb\bvh4mb_intersector.cpp">
-      <Filter>embree-1.1beta\rtcore</Filter>
+    <ClCompile Include="..\..\external\embree\embree\bvh2\bvh2_intersector4.cpp">
+      <Filter>embree</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\..\ext_toolboxes\embree-1.1beta\rtcore\bvh4mb\bvh4mb.cpp">
-      <Filter>embree-1.1beta\rtcore</Filter>
+    <ClCompile Include="..\..\external\embree\embree\bvh2\bvh2_intersector8.cpp">
+      <Filter>embree</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\..\ext_toolboxes\embree-1.1beta\rtcore\bvh4mb\bvh4mb_builder.cpp">
-      <Filter>embree-1.1beta\rtcore</Filter>
+    <ClCompile Include="..\..\external\embree\embree\bvh2\bvh2.cpp">
+      <Filter>embree</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\..\ext_toolboxes\embree-1.1beta\rtcore\common\splitter_fallback.cpp">
-      <Filter>embree-1.1beta\rtcore</Filter>
+    <ClCompile Include="..\..\external\embree\embree\bvh2\bvh2_intersector1.cpp">
+      <Filter>embree</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\..\ext_toolboxes\embree-1.1beta\rtcore\common\splitter_parallel.cpp">
-      <Filter>embree-1.1beta\rtcore</Filter>
+    <ClCompile Include="..\..\external\embree\embree\bvh4\bvh4_intersector4_chunk.cpp">
+      <Filter>embree</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\..\ext_toolboxes\embree-1.1beta\rtcore\common\stat.cpp">
-      <Filter>embree-1.1beta\rtcore</Filter>
+    <ClCompile Include="..\..\external\embree\embree\bvh4\bvh4_intersector4_hybrid.cpp">
+      <Filter>embree</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\..\ext_toolboxes\embree-1.1beta\rtcore\common\accel.cpp">
-      <Filter>embree-1.1beta\rtcore</Filter>
+    <ClCompile Include="..\..\external\embree\embree\bvh4\bvh4_intersector4_single.cpp">
+      <Filter>embree</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\..\ext_toolboxes\embree-1.1beta\rtcore\common\alloc.cpp">
-      <Filter>embree-1.1beta\rtcore</Filter>
+    <ClCompile Include="..\..\external\embree\embree\bvh4\bvh4_intersector8_chunk.cpp">
+      <Filter>embree</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\..\ext_toolboxes\embree-1.1beta\rtcore\common\heuristic_binning.cpp">
-      <Filter>embree-1.1beta\rtcore</Filter>
+    <ClCompile Include="..\..\external\embree\embree\bvh4\bvh4_intersector8_hybrid.cpp">
+      <Filter>embree</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\..\ext_toolboxes\embree-1.1beta\rtcore\common\heuristic_spatial.cpp">
-      <Filter>embree-1.1beta\rtcore</Filter>
+    <ClCompile Include="..\..\external\embree\embree\bvh4\bvh4_intersector8_single.cpp">
+      <Filter>embree</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\..\ext_toolboxes\embree-1.1beta\rtcore\common\primrefgen.cpp">
-      <Filter>embree-1.1beta\rtcore</Filter>
+    <ClCompile Include="..\..\external\embree\embree\bvh4\bvh4.cpp">
+      <Filter>embree</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\..\ext_toolboxes\embree-1.1beta\rtcore\common\splitter.cpp">
-      <Filter>embree-1.1beta\rtcore</Filter>
+    <ClCompile Include="..\..\external\embree\embree\bvh4\bvh4_intersector1.cpp">
+      <Filter>embree</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\..\ext_toolboxes\embree-1.1beta\common\sys\platform.cpp">
-      <Filter>embree-1.1beta\common</Filter>
+    <ClCompile Include="..\..\external\embree\embree\bvh4\bvh4_intersector1_avx.cpp">
+      <Filter>embree</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\..\ext_toolboxes\embree-1.1beta\common\sys\sysinfo.cpp">
-      <Filter>embree-1.1beta\common</Filter>
+    <ClCompile Include="..\..\external\embree\embree\bvh4i\bvh4i.cpp">
+      <Filter>embree</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\..\ext_toolboxes\embree-1.1beta\common\sys\taskscheduler_standard.cpp">
-      <Filter>embree-1.1beta\common</Filter>
+    <ClCompile Include="..\..\external\embree\embree\bvh4i\bvh4i_intersector1.cpp">
+      <Filter>embree</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\..\ext_toolboxes\embree-1.1beta\common\sys\thread.cpp">
-      <Filter>embree-1.1beta\common</Filter>
+    <ClCompile Include="..\..\external\embree\embree\bvh4mb\bvh4mb_intersector1.cpp">
+      <Filter>embree</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\..\ext_toolboxes\embree-1.1beta\common\sys\filename.cpp">
-      <Filter>embree-1.1beta\common</Filter>
+    <ClCompile Include="..\..\external\embree\embree\bvh4mb\bvh4mb_intersector4.cpp">
+      <Filter>embree</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\..\ext_toolboxes\embree-1.1beta\common\sys\library.cpp">
-      <Filter>embree-1.1beta\common</Filter>
+    <ClCompile Include="..\..\external\embree\embree\bvh4mb\bvh4mb_intersector8.cpp">
+      <Filter>embree</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\..\ext_toolboxes\embree-1.1beta\common\sys\stl\string.cpp">
-      <Filter>embree-1.1beta\common</Filter>
+    <ClCompile Include="..\..\external\embree\embree\bvh4mb\bvh4mb.cpp">
+      <Filter>embree</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\..\ext_toolboxes\embree-1.1beta\common\sys\sync\mutex.cpp">
-      <Filter>embree-1.1beta\common</Filter>
+    <ClCompile Include="..\..\external\embree\embree\bvh4mb\bvh4mb_builder.cpp">
+      <Filter>embree</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\..\ext_toolboxes\embree-1.1beta\common\sys\sync\condition.cpp">
-      <Filter>embree-1.1beta\common</Filter>
+    <ClCompile Include="..\..\external\embree\embree\bvh8\bvh8.cpp">
+      <Filter>embree</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\external\embree\embree\bvh8\bvh8_intersector1.cpp">
+      <Filter>embree</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\external\embree\embree\common\registry_intersector.cpp">
+      <Filter>embree</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\external\embree\embree\common\stat.cpp">
+      <Filter>embree</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\external\embree\embree\common\accel.cpp">
+      <Filter>embree</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\external\embree\embree\common\alloc.cpp">
+      <Filter>embree</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\external\embree\embree\common\registry_accel.cpp">
+      <Filter>embree</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\external\embree\embree\common\registry_builder.cpp">
+      <Filter>embree</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\external\embree\embree\geometry\virtual_scene.cpp">
+      <Filter>embree</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\external\embree\embree\geometry\triangle_mesh.cpp">
+      <Filter>embree</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\external\embree\embree\sys\taskscheduler.cpp">
+      <Filter>embree</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\external\embree\embree\sys\taskscheduler_mic.cpp">
+      <Filter>embree</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\external\embree\embree\sys\taskscheduler_sys.cpp">
+      <Filter>embree</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\external\embree\embree\sys\thread.cpp">
+      <Filter>embree</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\external\embree\embree\sys\filename.cpp">
+      <Filter>embree</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\external\embree\embree\sys\platform.cpp">
+      <Filter>embree</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\external\embree\embree\sys\sysinfo.cpp">
+      <Filter>embree</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\external\embree\embree\sys\stl\string.cpp">
+      <Filter>embree</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\external\embree\embree\sys\sync\mutex.cpp">
+      <Filter>embree</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\external\embree\embree\sys\sync\condition.cpp">
+      <Filter>embree</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\external\embree\embree\embree.cpp">
+      <Filter>embree</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\..\kt84\dbg.cpp" />
   </ItemGroup>
   <ItemGroup>
     <Filter Include="igl">
       <UniqueIdentifier>{53eff656-6473-409c-9ad5-cac1983d91e1}</UniqueIdentifier>
     </Filter>
-    <Filter Include="embree-1.1beta">
-      <UniqueIdentifier>{6d281f01-62c5-4083-90e7-1e9d55cf793c}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="embree-1.1beta\rtcore">
-      <UniqueIdentifier>{ded8eb8e-e3c8-4405-9234-dd048cbb197d}</UniqueIdentifier>
-    </Filter>
-    <Filter Include="embree-1.1beta\common">
-      <UniqueIdentifier>{0c5327d6-c9c7-4e16-a8e3-d3ae7f7b42d9}</UniqueIdentifier>
+    <Filter Include="embree">
+      <UniqueIdentifier>{6a04be79-a793-4c4a-a5c0-5d40f1f2ca7f}</UniqueIdentifier>
     </Filter>
   </ItemGroup>
   <ItemGroup>

+ 4 - 3
examples/patches/temp.rbr

@@ -1,5 +1,6 @@
-wireframe_visible: TW_TYPE_BOOLCPP 1
+wireframe_visible: TW_TYPE_BOOLCPP 0
 fill_visible: TW_TYPE_BOOLCPP 1
-camera_rotation: TW_TYPE_QUAT4D 0.20801 0.244181 0.0537125 0.945633
-rotation_type: RotationType two axis fixed up
+camera_rotation: TW_TYPE_QUAT4D 0.416858 0.0264188 -0.0596578 0.906627
+rotation_type: RotationType igl trackball
+orient_method: OrientMethod ambient occlusion
 

+ 2 - 1
examples/quicklook-mesh/Makefile

@@ -16,7 +16,8 @@ LIBIGL_INC=-I $(LIBIGL)/include
 # http://www.alecjacobson.com/weblog/?p=2827
 GLU=/usr/local/
 GLU_INC=-I$(GLU)/include
-GLU_LIB=-L$(GLU)/lib -lGLU
+#GLU_LIB=-L$(GLU)/lib -lGLU
+GLU_LIB=$(GLU)/lib/libGLU.a
 
 MESA=/opt/local/
 MESA_INC=-I$(MESA)/include

+ 7 - 1
examples/quicklook-mesh/README

@@ -22,4 +22,10 @@ Install Mesa3D using macports.
 
     sudo port install mesa
 
-Then re-install mesa's GLU à la http://www.alecjacobson.com/weblog/?p=2827
+Then re-install GLU à la http://www.alecjacobson.com/weblog/?p=2827
+
+= Note about Mesa =
+
+If things look weird (too far away, blank, etc.) then maybe you should
+reinstall GLU. It seems that the version of GLU that comes with macports' mesa
+is buggy/corrupted.

+ 5 - 5
include/igl/Viewport.h

@@ -13,11 +13,11 @@ namespace igl
     Viewport():
       x(0),y(0),width(0),height(0),camera(){};
     Viewport(
-      const int x, 
-      const int y, 
-      const int width,
-      const int height, 
-      const igl::Camera & camera):
+      const int x=0, 
+      const int y=0, 
+      const int width=0,
+      const int height=0, 
+      const igl::Camera & camera = igl::Camera()):
       x(x),
       y(y),
       width(width),

+ 109 - 63
include/igl/embree/EmbreeIntersector.h

@@ -9,31 +9,52 @@
 
 #include "Hit.h"
 #include <Eigen/Core>
-#include <embree/include/embree.h>
-#include <embree/include/intersector1.h>
-#include <embree/common/ray.h>
+#include "Embree_convenience.h"
 #include <vector>
 
 namespace igl
 {
-  template <
-  typename Scalar,
-  typename Index>
   class EmbreeIntersector
   {
-    typedef Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic> PointMatrixType;
-    typedef Eigen::Matrix<Index,Eigen::Dynamic,Eigen::Dynamic>  FaceMatrixType;
-    typedef Eigen::Matrix<Scalar,1,3> RowVector3;
   public:
-    // V  #V by 3 list of vertex positions
-    // F  #F by 3 list of Oriented triangles
-    EmbreeIntersector(
-      const PointMatrixType & V = PointMatrixType(),
-      const FaceMatrixType & F = FaceMatrixType(),
+    // Initialize embree engine. This will be called on instance `init()`
+    // calls. If already inited then this function does nothing: it is harmless
+    // to call more than once.
+    static inline void global_init();
+  private:
+    // Deinitialize the embree engine. This should probably never be called by
+    // the user. Hence it's private. Do you really want to do this?
+    static inline void global_deinit();
+  public:
+    typedef Eigen::Matrix<float,Eigen::Dynamic,Eigen::Dynamic> PointMatrixType;
+    typedef Eigen::Matrix<int,Eigen::Dynamic,Eigen::Dynamic>  FaceMatrixType;
+    typedef Eigen::Matrix<float,1,3> RowVector3;
+  public:
+    inline EmbreeIntersector();
+  private:
+    // Copying and assignment are not allowed.
+    inline EmbreeIntersector(const EmbreeIntersector & that);
+    inline EmbreeIntersector operator=(const EmbreeIntersector &);
+  public:
+    virtual inline ~EmbreeIntersector();
+      
+    // Initialize with a given mesh.
+    //
+    // Inputs:
+    //   V  #V by 3 list of vertex positions
+    //   F  #F by 3 list of Oriented triangles
+    // Side effects:
+    //   The first time this is ever called the embree engine is initialized.
+    inline void init(
+      const PointMatrixType & V,
+      const FaceMatrixType & F,
       const char* structure = "default",
       const char* builder = "default",
       const char* traverser = "default");
-    virtual ~EmbreeIntersector();
+    // Deinitialize embree datasctructures for current mesh.  Also called on
+    // destruction: no need to call if you just want to init() once and
+    // destroy.
+    inline void deinit();
   
     // Given a ray find the first hit
     // 
@@ -43,7 +64,7 @@ namespace igl
     // Output:
     //   hit        information about hit
     // Returns true if and only if there was a hit
-    bool intersectRay(
+    inline bool intersectRay(
       const RowVector3& origin, 
       const RowVector3& direction,
       Hit& hit,
@@ -59,7 +80,7 @@ namespace igl
     //   hit        information about hit
     //   num_rays   number of rays shot (at least one)
     // Returns true if and only if there was a hit
-    bool intersectRay(
+    inline bool intersectRay(
       const RowVector3& origin,
       const RowVector3& direction,
       std::vector<Hit > &hits,
@@ -75,7 +96,7 @@ namespace igl
     // Output:
     //   hit  information about hit
     // Returns true if and only if there was a hit
-    bool intersectSegment(const RowVector3& a, const RowVector3& ab, Hit &hit) const;
+    inline bool intersectSegment(const RowVector3& a, const RowVector3& ab, Hit &hit) const;
     
   private:
     embree::RTCGeometry* mesh;
@@ -87,41 +108,78 @@ namespace igl
 
 // Implementation
 #include <igl/EPS.h>
+// This unfortunately cannot be a static field of EmbreeIntersector because it
+// would depend on the template and then we might end up with initializing
+// embree twice. If only there was a way to ask embree if it's already
+// initialized...
+namespace igl
+{
+  // Keeps track of whether the **Global** Embree intersector has been
+  // initialized. This should never been done at the global scope.
+  static bool EmbreeIntersector_inited = false;
+}
 
 template <typename RowVector3>
 inline embree::Vector3f toVector3f(const RowVector3 &p) { return embree::Vector3f((float)p[0], (float)p[1], (float)p[2]); }
 
-template <
-typename Scalar,
-typename Index>
-igl::EmbreeIntersector < Scalar, Index>
-::EmbreeIntersector(const PointMatrixType & V,
-                    const FaceMatrixType & F,
-                    const char* structure,
-                    const char* builder,
-                    const char* traverser)
-  :
-    mesh(NULL),
-    triangles(NULL),
-    vertices(NULL),
-    intersector(NULL)
+inline void igl::EmbreeIntersector::global_init()
 {
-  using namespace std;
-  static bool inited = false;
-  if(!inited)
+  if(!EmbreeIntersector_inited)
   {
     embree::rtcInit();
 #ifdef IGL_VERBOSE
     embree::rtcSetVerbose(3);
 #endif
     embree::rtcStartThreads();
-    inited = true;
+    EmbreeIntersector_inited = true;
   }
+}
+
+inline void igl::EmbreeIntersector::global_deinit()
+{
+  EmbreeIntersector_inited = false;
+  embree::rtcStopThreads();
+  embree::rtcExit();
+  embree::rtcFreeMemory();
+}
+
+inline igl::EmbreeIntersector::EmbreeIntersector()
+  :
+  mesh(NULL),
+  triangles(NULL),
+  vertices(NULL),
+  intersector(NULL)
+{
+}
+
+inline igl::EmbreeIntersector::EmbreeIntersector(
+  const EmbreeIntersector & that)
+{
+  assert(false && "Copying EmbreeIntersector is not allowed");
+}
+
+inline igl::EmbreeIntersector igl::EmbreeIntersector::operator=(
+  const EmbreeIntersector & that)
+{
+  assert(false && "Assigning an EmbreeIntersector is not allowed");
+  return *this;
+}
+
 
-   if(V.size() == 0 || F.size() == 0)
-   {
-     return;
-   }
+inline void igl::EmbreeIntersector::init(
+  const PointMatrixType & V,
+  const FaceMatrixType & F,
+  const char* structure,
+  const char* builder,
+  const char* traverser)
+{
+  using namespace std;
+  global_init();
+
+  if(V.size() == 0 || F.size() == 0)
+  {
+    return;
+  }
   
   mesh = embree::rtcNewTriangleMesh(F.rows(),V.rows(),structure);
 
@@ -147,25 +205,19 @@ igl::EmbreeIntersector < Scalar, Index>
   intersector = embree::rtcQueryIntersector1(mesh,traverser);
 }
 
-template <
-typename Scalar,
-typename Index>
-igl::EmbreeIntersector < Scalar, Index>
+igl::EmbreeIntersector
 ::~EmbreeIntersector()
+{
+  deinit();
+}
+
+void igl::EmbreeIntersector::deinit()
 {
   embree::rtcDeleteIntersector1(intersector);
   embree::rtcDeleteGeometry(mesh);
-//  embree::rtcStopThreads();
-//  embree::rtcExit();
-//  embree::rtcFreeMemory();
 }
 
-template <
-typename Scalar,
-typename Index>
-bool 
-igl::EmbreeIntersector< Scalar, Index>
-::intersectRay(
+inline bool igl::EmbreeIntersector::intersectRay(
   const RowVector3& origin,
   const RowVector3& direction,
   Hit& hit,
@@ -187,11 +239,8 @@ igl::EmbreeIntersector< Scalar, Index>
   return false;
 }
 
-template <
-typename Scalar,
-typename Index>
-bool 
-igl::EmbreeIntersector < Scalar, Index>
+inline bool 
+igl::EmbreeIntersector
 ::intersectRay(
   const RowVector3& origin, 
   const RowVector3& direction,
@@ -285,11 +334,8 @@ igl::EmbreeIntersector < Scalar, Index>
   return hits.empty();
 }
 
-template <
-typename Scalar,
-typename Index>
-bool 
-igl::EmbreeIntersector < Scalar, Index>
+inline bool 
+igl::EmbreeIntersector
 ::intersectSegment(const RowVector3& a, const RowVector3& ab, Hit &hit) const
 {
   embree::Ray ray(toVector3f(a), toVector3f(ab), embree::zero, embree::one);

+ 3 - 1
include/igl/embree/Embree_convenience.h

@@ -16,7 +16,9 @@
 // This is a hack
 #  pragma GCC system_header
 #endif
-#include <common/ray.h>
+#include <embree/include/embree.h>
+#include <embree/include/intersector1.h>
+#include <embree/common/ray.h>
 #ifdef __GNUC__
 #  if __GNUC__ >= 4
 #    if __GNUC_MINOR__ >= 6

+ 10 - 16
include/igl/embree/ambient_occlusion.cpp

@@ -4,13 +4,11 @@
 #include <igl/EPS.h>
 
 template <
-  typename Scalar,
-  typename Index,
   typename DerivedP,
   typename DerivedN,
   typename DerivedS >
 void igl::ambient_occlusion(
-  const igl::EmbreeIntersector<Scalar,Index> & ei,
+  const igl::EmbreeIntersector & ei,
   const Eigen::PlainObjectBase<DerivedP> & P,
   const Eigen::PlainObjectBase<DerivedN> & N,
   const int num_samples,
@@ -26,14 +24,14 @@ void igl::ambient_occlusion(
   // loop over mesh vertices
   for(int p = 0;p<n;p++)
   {
-    const Vector3d origin = P.row(p);
-    const Vector3d normal = N.row(p);
+    const Vector3f origin = P.row(p).template cast<float>();
+    const Vector3f normal = N.row(p).template cast<float>();
     int num_hits = 0;
-    MatrixXd D = random_dir_stratified(num_samples);
+    MatrixXf D = random_dir_stratified(num_samples).cast<float>();
     for(int s = 0;s<num_samples;s++)
     {
       //Vector3d d = random_dir();
-      Vector3d d = D.row(s);
+      Vector3f d = D.row(s);
       if(d.dot(normal) < 0)
       {
         // reverse ray
@@ -66,18 +64,14 @@ void igl::ambient_occlusion(
 {
   using namespace igl;
   using namespace Eigen;
-  EmbreeIntersector<
-    typename DerivedV::Scalar,
-    typename DerivedF::Scalar > * ei = new EmbreeIntersector<
-    typename DerivedV::Scalar,
-    typename DerivedF::Scalar >(V,F);
-  ambient_occlusion(*ei,P,N,num_samples,S);
-  delete ei;
+  EmbreeIntersector ei;
+  ei.init(V.template cast<float>(),F.template cast<int>());
+  ambient_occlusion(ei,P,N,num_samples,S);
 }
 
 #ifndef IGL_HEADER_ONLY
 // Explicit template instanciation
-template void igl::ambient_occlusion<double, int, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(igl::EmbreeIntersector<double, int> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
-template void igl::ambient_occlusion<double, int, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(igl::EmbreeIntersector<double, int> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+template void igl::ambient_occlusion<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(igl::EmbreeIntersector const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+template void igl::ambient_occlusion<Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(igl::EmbreeIntersector const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
 template void igl::ambient_occlusion<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
 #endif

+ 1 - 6
include/igl/embree/ambient_occlusion.h

@@ -5,9 +5,6 @@
 namespace igl
 {
   // Forward define
-  template <
-    typename Scalar,
-    typename Index>
   class EmbreeIntersector;
   // Compute ambient occlusion per given point
   //
@@ -20,13 +17,11 @@ namespace igl
   //      (not occluded)
   //
   template <
-    typename Scalar,
-    typename Index,
     typename DerivedP,
     typename DerivedN,
     typename DerivedS >
   void ambient_occlusion(
-    const igl::EmbreeIntersector<Scalar,Index> & ei,
+    const igl::EmbreeIntersector & ei,
     const Eigen::PlainObjectBase<DerivedP> & P,
     const Eigen::PlainObjectBase<DerivedN> & N,
     const int num_samples,

+ 6 - 3
include/igl/embree/bone_visible.cpp

@@ -26,8 +26,8 @@ IGL_INLINE void igl::bone_visible(
   FF.resize(F.rows()*2,F.cols());
   FF << F, F.rowwise().reverse();
   // Initialize intersector
-  const EmbreeIntersector<double,int> ei = 
-        EmbreeIntersector<double,int>(V,FF);
+  EmbreeIntersector ei;
+  ei.init(V.template cast<float>(),FF.template cast<int>());
   const double sd_norm = (s-d).norm();
   // Embree seems to be parallel when constructing but not when tracing rays
 #pragma omp parallel for
@@ -68,7 +68,10 @@ IGL_INLINE void igl::bone_visible(
     // perhaps 1.0 should be 1.0-epsilon, or actually since we checking the
     // incident face, perhaps 1.0 should be 1.0+eps
     const Vector3d dir = (Vv-projv)*1.0;
-    if(ei.intersectSegment(projv,dir, hit))
+    if(ei.intersectSegment(
+       projv.template cast<float>(),
+       dir.template cast<float>(), 
+       hit))
     {
       // mod for double sided lighting
       const int fi = hit.id % F.rows();

+ 126 - 70
include/igl/embree/orient_outward_ao.cpp

@@ -1,28 +1,23 @@
 #include "orient_outward_ao.h"
 #include "../per_face_normals.h"
-#include "../barycenter.h"
 #include "../doublearea.h"
-#include "../matlab_format.h"
-#include "ambient_occlusion.h"
+#include "../random_dir.h"
 #include "EmbreeIntersector.h"
 #include <iostream>
 #include <random>
-#include <omp.h>
 
 template <
   typename DerivedV, 
   typename DerivedF, 
   typename DerivedC, 
-  typename Scalar,
-  typename Index,
   typename DerivedFF, 
   typename DerivedI>
 IGL_INLINE void igl::orient_outward_ao(
   const Eigen::PlainObjectBase<DerivedV> & V,
   const Eigen::PlainObjectBase<DerivedF> & F,
   const Eigen::PlainObjectBase<DerivedC> & C,
-  const igl::EmbreeIntersector<Scalar,Index> & ei,
-  const int num_samples,
+  const int min_num_rays_per_component,
+  const int total_num_rays,
   Eigen::PlainObjectBase<DerivedFF> & FF,
   Eigen::PlainObjectBase<DerivedI> & I)
 {
@@ -32,6 +27,9 @@ IGL_INLINE void igl::orient_outward_ao(
   assert(F.cols() == 3);
   assert(V.cols() == 3);
   
+  EmbreeIntersector ei;
+  ei.init(V.template cast<float>(),F);
+  
   // number of faces
   const int m = F.rows();
   // number of patches
@@ -43,71 +41,138 @@ IGL_INLINE void igl::orient_outward_ao(
   }
   
   // face normal
-  PlainObjectBase<DerivedV> N;
+  MatrixXd N;
   per_face_normals(V,F,N);
   
-  // random number generator/distribution for each thread
-  int max_threads = omp_get_max_threads();
-  
-  // prng
-  vector<mt19937> engine(max_threads);
-  for (int i = 0; i < max_threads; ++i)
-      engine[i].seed(time(0) * (i + 1));
-  
-  // discrete distribution for random selection of faces with probability proportional to their areas
+  // face area
   Matrix<typename DerivedV::Scalar,Dynamic,1> A;
   doublearea(V,F,A);
-  double minarea = A.minCoeff();
-  Matrix<int, Dynamic, 1> A_int = (A * 100.0 / minarea).template cast<int>();       // only integer is allowed for weight
-  auto ddist_func = [&] (double i) { return A_int(static_cast<int>(i)); };
-  vector<discrete_distribution<int>> ddist(max_threads, discrete_distribution<int>(m, 0, m, ddist_func));      // simple ctor of (Iter, Iter) not provided by the stupid VC11 impl...
-  
-  // uniform real between in [0, 1]
-  vector<uniform_real_distribution<double>> rdist(max_threads);
+  double area_min = A.minCoeff();
+  double area_total = A.sum();
   
-  //// occlusion count per component: +1 when front ray is occluded, -1 when back ray is occluded
-  // occlussion count per component, per back/front: C(c,0) --> number of
-  // front-side rays occluded, C(c,1) --> number of back-side rays occluded
-  Matrix<int, Dynamic, 2> C_occlude_count;
-  C_occlude_count.setZero(num_cc, 2);
+  // determine number of rays per component according to its area
+  VectorXd area_per_component;
+  area_per_component.setZero(num_cc);
+  for (int f = 0; f < m; ++f)
+  {
+    area_per_component(C(f)) += A(f);
+  }
+  VectorXi num_rays_per_component;
+  num_rays_per_component.setZero(num_cc);
+  for (int c = 0; c < num_cc; ++c)
+  {
+    num_rays_per_component(c) = max<int>(min_num_rays_per_component, static_cast<int>(total_num_rays * area_per_component(c) / area_total));
+  }
   
-#pragma omp parallel for
-  for (int i = 0; i < num_samples; ++i)
+  // generate all the rays
+  cout << "generating rays... ";
+  uniform_real_distribution<float> rdist;
+  mt19937 prng;
+  prng.seed(0);
+  vector<int     > ray_face;
+  vector<Vector3f> ray_ori;
+  vector<Vector3f> ray_dir;
+  ray_face.reserve(total_num_rays);
+  ray_ori .reserve(total_num_rays);
+  ray_dir .reserve(total_num_rays);
+  for (int c = 0; c < num_cc; ++c)
   {
-    int thread_num = omp_get_thread_num();
-    int f     = ddist[thread_num](engine[thread_num]);   // select face with probability proportional to face area
-    double t0 = rdist[thread_num](engine[thread_num]);
-    double t1 = rdist[thread_num](engine[thread_num]);
-    double t2 = rdist[thread_num](engine[thread_num]);
-    double t_sum = t0 + t1 + t2;
-    t0 /= t_sum;
-    t1 /= t_sum;
-    t2 /= t_sum;
-    RowVector3d p = t0 * V.row(F(f,0)) + t1 * V.row(F(f,1)) + t1 * V.row(F(f,2));
-    RowVector3d n = N.row(f);
-    //bool is_backside = rdist[thread_num](engine[thread_num]) < 0.5;
-    // Loop over front or back side
-    for(int s = 0;s<2;s++)
+    vector<int> CF;     // set of faces per component
+    vector<int> CF_area;
+    for (int f = 0; f < m; ++f)
     {
-      if(s==1)
+      if (C(f)==c)
       {
-          n *= -1;
+        CF.push_back(f);
+        CF_area.push_back(static_cast<int>(100 * A(f) / area_min));
       }
-      Matrix<typename DerivedV::Scalar,Dynamic,1> S;
-      ambient_occlusion(ei, p, n, 1, S);
-      if (S(0) > 0)
-      {
-#pragma omp atomic
-        C_occlude_count(C(f),s)++;
+    }
+    // discrete distribution for random selection of faces with probability proportional to their areas
+    auto ddist_func = [&] (double i) { return CF_area[static_cast<int>(i)]; };
+    discrete_distribution<int> ddist(CF.size(), 0, CF.size(), ddist_func);      // simple ctor of (Iter, Iter) not provided by the stupid VC11 impl...
+    for (int i = 0; i < num_rays_per_component[c]; ++i)
+    {
+      int f     = CF[ddist(prng)];    // select face with probability proportional to face area
+      float t0 = rdist(prng);        // random barycentric coordinate
+      float t1 = rdist(prng);
+      float t2 = rdist(prng);
+      float t_sum = t0 + t1 + t2;
+      t0 /= t_sum;
+      t1 /= t_sum;
+      t2 /= t_sum;
+      Vector3f p = t0 * V.row(F(f,0)).template cast<float>().eval()       // be careful with the index!!!
+                 + t1 * V.row(F(f,1)).template cast<float>().eval()
+                 + t2 * V.row(F(f,2)).template cast<float>().eval();
+      Vector3f n = N.row(f).cast<float>();
+      assert(n != Vector3f::Zero());
+      // random direction in hemisphere around n (avoid too grazing angle)
+      Vector3f d;
+      while (true) {
+        d = random_dir().cast<float>();
+        float ndotd = n.dot(d);
+        if (fabsf(ndotd) < 0.1f)
+        {
+          continue;
+        }
+        if (ndotd < 0)
+        {
+          d *= -1.0f;
+        }
+        break;
       }
+      ray_face.push_back(f);
+      ray_ori .push_back(p);
+      ray_dir .push_back(d);
+    }
+  }
+  
+  // per component voting: first=front, second=back
+  vector<pair<float, float>> C_vote_distance(num_cc, make_pair(0, 0));     // sum of distance between ray origin and intersection
+  vector<pair<int  , int  >> C_vote_infinity(num_cc, make_pair(0, 0));     // number of rays reaching infinity
+  
+  cout << "shooting rays... ";
+#pragma omp parallel for
+  for (int i = 0; i < (int)ray_face.size(); ++i)
+  {
+    int      f = ray_face[i];
+    Vector3f o = ray_ori [i];
+    Vector3f d = ray_dir [i];
+    int c = C(f);
+    
+    // shoot ray toward front & back
+    vector<Hit> hits_front;
+    vector<Hit> hits_back;
+    int num_rays_front;
+    int num_rays_back;
+    ei.intersectRay(o,  d, hits_front, num_rays_front);
+    ei.intersectRay(o, -d, hits_back , num_rays_back );
+    if (!hits_front.empty() && hits_front[0].id == f) hits_front.erase(hits_front.begin());
+    if (!hits_back .empty() && hits_back [0].id == f) hits_back .erase(hits_back .begin());
+    
+    if (hits_front.empty())
+    {
+#pragma omp atomic
+      C_vote_infinity[c].first++;
+    } else {
+#pragma omp atomic
+      C_vote_distance[c].first += hits_front[0].t;
+    }
+    
+    if (hits_back.empty())
+    {
+#pragma omp atomic
+      C_vote_infinity[c].second++;
+    } else {
+#pragma omp atomic
+      C_vote_distance[c].second += hits_back[0].t;
     }
-
   }
   
   for(int c = 0;c<num_cc;c++)
   {
-    //I(c) = C_occlude_count(c) > 0;
-    I(c) = C_occlude_count(c,0) > C_occlude_count(c,1);
+    I(c) = C_vote_infinity[c].first == C_vote_infinity[c].second &&
+           C_vote_distance[c].first <  C_vote_distance[c].second ||
+           C_vote_infinity[c].first <  C_vote_infinity[c].second;
   }
   // flip according to I
   for(int f = 0;f<m;f++)
@@ -117,9 +182,10 @@ IGL_INLINE void igl::orient_outward_ao(
       FF.row(f) = FF.row(f).reverse().eval();
     }
   }
+  cout << "done!\n";
 }
 
-// EmbreeIntersector generated on the fly
+// Call with default parameters
 template <
   typename DerivedV, 
   typename DerivedF, 
@@ -130,23 +196,13 @@ IGL_INLINE void igl::orient_outward_ao(
   const Eigen::PlainObjectBase<DerivedV> & V,
   const Eigen::PlainObjectBase<DerivedF> & F,
   const Eigen::PlainObjectBase<DerivedC> & C,
-  const int num_samples,
   Eigen::PlainObjectBase<DerivedFF> & FF,
   Eigen::PlainObjectBase<DerivedI> & I)
 {
-  using namespace igl;
-  using namespace Eigen;
-  // Both sides
-  MatrixXi F2;
-  F2.resize(F.rows()*2,F.cols());
-  F2 << F, F.rowwise().reverse().eval();
-  EmbreeIntersector<
-    typename DerivedV::Scalar,
-    typename DerivedF::Scalar > ei(V,F2);
-  return orient_outward_ao(V, F, C, ei, num_samples, FF, I);
+  return orient_outward_ao(V, F, C, 100, F.rows() * 100, FF, I);
 }
 
 #ifndef IGL_HEADER_ONLY
 // Explicit template specialization
-template void igl::orient_outward_ao<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::orient_outward_ao<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int, int, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
 #endif

+ 8 - 16
include/igl/embree/orient_outward_ao.h

@@ -4,20 +4,15 @@
 #include <Eigen/Core>
 namespace igl
 {
-  // Forward define
-  template <
-    typename Scalar,
-    typename Index>
-  class EmbreeIntersector;
   // Orient each component (identified by C) of a mesh (V,F) using ambient occlusion 
   // such that the front side is less occluded than back side
   //
   // Inputs:
-  //   V            #V by 3 list of vertex positions
-  //   F            #F by 3 list of triangle indices
-  //   C            #F list of components
-  //   ei           EmbreeIntersector containing (V,F)
-  //   num_samples  total number of rays to be shot
+  //   V                            #V by 3 list of vertex positions
+  //   F                            #F by 3 list of triangle indices
+  //   C                            #F list of components
+  //   min_num_rays_per_component   Each component receives at least this number of rays
+  //   total_num_rays               Total number of rays that will be shot
   // Outputs:
   //   FF  #F by 3 list of new triangle indices such that FF(~I,:) = F(~I,:) and
   //     FF(I,:) = fliplr(F(I,:)) (OK if &FF = &F)
@@ -26,20 +21,18 @@ namespace igl
     typename DerivedV, 
     typename DerivedF, 
     typename DerivedC, 
-    typename Scalar,
-    typename Index,
     typename DerivedFF, 
     typename DerivedI>
   IGL_INLINE void orient_outward_ao(
     const Eigen::PlainObjectBase<DerivedV> & V,
     const Eigen::PlainObjectBase<DerivedF> & F,
     const Eigen::PlainObjectBase<DerivedC> & C,
-    const igl::EmbreeIntersector<Scalar,Index> & ei,
-    const int num_samples,
+    const int min_num_rays_per_component,
+    const int total_num_rays,
     Eigen::PlainObjectBase<DerivedFF> & FF,
     Eigen::PlainObjectBase<DerivedI> & I);
   
-  // EmbreeIntersector generated on the fly
+  // Call with default number of rays
   template <
     typename DerivedV, 
     typename DerivedF, 
@@ -50,7 +43,6 @@ namespace igl
     const Eigen::PlainObjectBase<DerivedV> & V,
     const Eigen::PlainObjectBase<DerivedF> & F,
     const Eigen::PlainObjectBase<DerivedC> & C,
-    const int num_samples,
     Eigen::PlainObjectBase<DerivedFF> & FF,
     Eigen::PlainObjectBase<DerivedI> & I);
 };

+ 8 - 11
include/igl/embree/unproject_in_mesh.cpp

@@ -4,13 +4,11 @@
 #include <vector>
 
 template <
-  typename Scalar,
-  typename Index,
   typename Derivedobj>
 int igl::unproject_in_mesh(
   const int x,
   const int y,
-  const igl::EmbreeIntersector<Scalar,Index> & ei,
+  const igl::EmbreeIntersector & ei,
   Eigen::PlainObjectBase<Derivedobj> & obj)
 {
   std::vector<igl::Hit> hits;
@@ -18,13 +16,11 @@ int igl::unproject_in_mesh(
 }
 
 template <
-  typename Scalar,
-  typename Index,
   typename Derivedobj>
 int igl::unproject_in_mesh(
   const int x,
   const int y,
-  const igl::EmbreeIntersector<Scalar,Index> & ei,
+  const igl::EmbreeIntersector & ei,
   Eigen::PlainObjectBase<Derivedobj> & obj,
   std::vector<igl::Hit > & hits)
 {
@@ -32,10 +28,10 @@ int igl::unproject_in_mesh(
   using namespace std;
   using namespace Eigen;
   // Source and direction on screen
-  Vector3d win_s = Vector3d(x,y,0);
-  Vector3d win_d(x,y,1);
+  Vector3f win_s = Vector3f(x,y,0);
+  Vector3f win_d(x,y,1);
   // Source, destination and direction in world
-  Vector3d s,d,dir;
+  Vector3f s,d,dir;
   unproject(win_s,s);
   unproject(win_d,d);
   dir = d-s;
@@ -49,13 +45,13 @@ int igl::unproject_in_mesh(
       break;
     case 1:
     {
-      obj = s + dir*hits[0].t;
+      obj = (s + dir*hits[0].t).cast<typename Derivedobj::Scalar>();
       break;
     }
     case 2:
     default:
     {
-      obj = 0.5*((s + dir*hits[0].t) + (s + dir*hits[1].t));
+      obj = 0.5*((s + dir*hits[0].t) + (s + dir*hits[1].t)).cast<typename Derivedobj::Scalar>();
       break;
     }
   }
@@ -63,4 +59,5 @@ int igl::unproject_in_mesh(
 }
 
 #ifndef IGL_HEADER_ONLY
+template int igl::unproject_in_mesh<Eigen::Matrix<double, 3, 1, 0, 3, 1> >(int, int, igl::EmbreeIntersector const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> >&, std::vector<igl::Hit, std::allocator<igl::Hit> >&);
 #endif

+ 2 - 9
include/igl/embree/unproject_in_mesh.h

@@ -9,9 +9,6 @@
 namespace igl
 {
   // Forward define
-  template <
-    typename Scalar,
-    typename Index>
   class EmbreeIntersector;
   // Unproject a screen location (using current opengl viewport, projection, and
   // model view) to a 3D position 
@@ -25,23 +22,19 @@ namespace igl
   // Returns number of hits
   //
   template <
-    typename Scalar,
-    typename Index,
     typename Derivedobj>
   int unproject_in_mesh(
     const int x,
     const int y,
-    const igl::EmbreeIntersector<Scalar,Index> & ei,
+    const igl::EmbreeIntersector & ei,
     Eigen::PlainObjectBase<Derivedobj> & obj);
 
   template <
-    typename Scalar,
-    typename Index,
     typename Derivedobj>
   int unproject_in_mesh(
     const int x,
     const int y,
-    const igl::EmbreeIntersector<Scalar,Index> & ei,
+    const igl::EmbreeIntersector & ei,
     Eigen::PlainObjectBase<Derivedobj> & obj,
     std::vector<igl::Hit > & hits);
 }

+ 2 - 1
include/igl/orient_outward.cpp

@@ -36,7 +36,8 @@ IGL_INLINE void igl::orient_outward(
   PlainObjectBase<DerivedV> N,BC,BCmean;
   Matrix<typename DerivedV::Scalar,Dynamic,1> A;
   VectorXd totA(num_cc), dot(num_cc);
-  per_face_normals(V,F,N);
+  Matrix<typename DerivedV::Scalar,3,1> Z(1,1,1);
+  per_face_normals(V,F,Z.normalized(),N);
   barycenter(V,F,BC);
   doublearea(V,F,A);
   BCmean.setConstant(num_cc,3,0);

+ 20 - 9
include/igl/per_face_normals.cpp

@@ -2,11 +2,12 @@
 #include <Eigen/Geometry>
 
 #define SQRT_ONE_OVER_THREE 0.57735026918962573
-template <typename DerivedV, typename DerivedF>
+template <typename DerivedV, typename DerivedF, typename DerivedZ, typename DerivedN>
 IGL_INLINE void igl::per_face_normals(
   const Eigen::PlainObjectBase<DerivedV>& V,
   const Eigen::PlainObjectBase<DerivedF>& F,
-  Eigen::PlainObjectBase<DerivedV> & N)
+  const Eigen::PlainObjectBase<DerivedZ> & Z,
+  Eigen::PlainObjectBase<DerivedN> & N)
 {
   N.resize(F.rows(),3);
   // loop over faces
@@ -17,20 +18,30 @@ IGL_INLINE void igl::per_face_normals(
     Eigen::Matrix<typename DerivedV::Scalar, 1, 3> v1 = V.row(F(i,1)) - V.row(F(i,0));
     Eigen::Matrix<typename DerivedV::Scalar, 1, 3> v2 = V.row(F(i,2)) - V.row(F(i,0));
     N.row(i) = v1.cross(v2);//.normalized();
-    if(N.row(i).sum() == 0)
+    typename DerivedV::Scalar r = N.row(i).norm();
+    if(r == 0)
     {
-      N(i,0) = SQRT_ONE_OVER_THREE;
-      N(i,1) = SQRT_ONE_OVER_THREE;
-      N(i,2) = SQRT_ONE_OVER_THREE;
+      N.row(i) = Z;
     }else
     {
-      N.row(i) = N.row(i).normalized().eval();
+      N.row(i) /= r;
     }
   }
 }
+
+template <typename DerivedV, typename DerivedF, typename DerivedN>
+IGL_INLINE void igl::per_face_normals(
+  const Eigen::PlainObjectBase<DerivedV>& V,
+  const Eigen::PlainObjectBase<DerivedF>& F,
+  Eigen::PlainObjectBase<DerivedN> & N)
+{
+  using namespace Eigen;
+  Matrix<typename DerivedN::Scalar,3,1> Z(0,0,0);
+  return per_face_normals(V,F,Z,N);
+}
+
 #ifndef IGL_HEADER_ONLY
 // Explicit template specialization
-// generated by autoexplicit.sh
 template void igl::per_face_normals<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
-template void igl::per_face_normals<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> >&);
+template void igl::per_face_normals<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, 3, 1, 0, 3, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
 #endif

+ 16 - 3
include/igl/per_face_normals.h

@@ -7,14 +7,27 @@ namespace igl
   // Compute face normals via vertex position list, face list
   // Inputs:
   //   V  #V by 3 eigen Matrix of mesh vertex 3D positions
-  //   F  #F by 3 eigne Matrix of face (triangle) indices
+  //   F  #F by 3 eigen Matrix of face (triangle) indices
+  //   Z  3 vector normal given to faces with degenerate normal.
   // Output:
   //   N  #F by 3 eigen Matrix of mesh face (triangle) 3D normals
-  template <typename DerivedV, typename DerivedF>
+  //
+  // Example:
+  //   // Give degenerate faces (1/3,1/3,1/3)^0.5
+  //   per_face_normals(V,F,Vector3d(1,1,1).normalized(),N);
+  template <typename DerivedV, typename DerivedF, typename DerivedZ, typename DerivedN>
   IGL_INLINE void per_face_normals(
     const Eigen::PlainObjectBase<DerivedV>& V,
     const Eigen::PlainObjectBase<DerivedF>& F,
-    Eigen::PlainObjectBase<DerivedV> & N);
+    const Eigen::PlainObjectBase<DerivedZ> & Z,
+    Eigen::PlainObjectBase<DerivedN> & N);
+  // Wrapper with Z = (0,0,0). Note that this means that row norms will be zero
+  // (i.e. not 1) for degenerate normals.
+  template <typename DerivedV, typename DerivedF, typename DerivedN>
+  IGL_INLINE void per_face_normals(
+    const Eigen::PlainObjectBase<DerivedV>& V,
+    const Eigen::PlainObjectBase<DerivedF>& F,
+    Eigen::PlainObjectBase<DerivedN> & N);
 }
 
 #ifdef IGL_HEADER_ONLY

+ 1 - 0
include/igl/unproject.cpp

@@ -53,6 +53,7 @@ IGL_INLINE Eigen::PlainObjectBase<Derivedwin> igl::unproject(
 template int igl::unproject<Eigen::Matrix<double, 3, 1, 0, 3, 1>, Eigen::Matrix<double, 3, 1, 0, 3, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> >&);
 template int igl::unproject<Eigen::Matrix<float, 3, 1, 0, 3, 1>, Eigen::Matrix<float, 3, 1, 0, 3, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<float, 3, 1, 0, 3, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, 3, 1, 0, 3, 1> >&);
 template Eigen::PlainObjectBase<Eigen::Matrix<float, 3, 1, 0, 3, 1> > igl::unproject<Eigen::Matrix<float, 3, 1, 0, 3, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<float, 3, 1, 0, 3, 1> > const&);
+template int igl::unproject<Eigen::Matrix<double, 3, 1, 0, 3, 1>, Eigen::Matrix<float, 3, 1, 0, 3, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, 3, 1, 0, 3, 1> >&);
 #endif
 
 #endif