Эх сурвалжийг харах

lens flares

Former-commit-id: 03cc2263e892edb5bdf6a5b3ff84545a31546424
Alec Jacobson (jalec 11 жил өмнө
parent
commit
1ab13ff6cf

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

@@ -6,14 +6,19 @@
 #include <igl/draw_floor.h>
 #include <igl/quat_to_mat.h>
 #include <igl/report_gl_error.h>
-#include <igl/read.h>
+#include <igl/readOBJ.h>
+#include <igl/readOFF.h>
+#include <igl/readWRL.h>
 #include <igl/trackball.h>
+#include <igl/list_to_matrix.h>
+#include <igl/triangulate.h>
 #include <igl/material_colors.h>
 #include <igl/barycenter.h>
 #include <igl/matlab_format.h>
 #include <igl/embree/EmbreeIntersector.h>
 #include <igl/embree/ambient_occlusion.h>
 #include <igl/ReAntTweakBar.h>
+#include <igl/pathinfo.h>
 
 #ifdef __APPLE__
 #  include <GLUT/glut.h>
@@ -25,6 +30,7 @@
 
 #include <vector>
 #include <iostream>
+#include <algorithm>
 
 // Width and height of window
 int width,height;
@@ -300,10 +306,67 @@ int main(int argc, char * argv[])
   using namespace std;
 
   // init mesh
-  if(!read("../shared/beast.obj",V,F))
+  string filename = "../shared/beast.obj";
+  if(argc < 2)
   {
-    return 1;
+    cerr<<"Usage:"<<endl<<"    ./example input.obj"<<endl;
+    cout<<endl<<"Opening default mesh..."<<endl;
+  }else
+  {
+    // Read and prepare mesh
+    filename = argv[1];
   }
+
+  // dirname, basename, extension and filename
+  string d,b,ext,f;
+  pathinfo(filename,d,b,ext,f);
+  // Convert extension to lower case
+  transform(ext.begin(), ext.end(), ext.begin(), ::tolower);
+  vector<vector<double > > vV,vN,vTC;
+  vector<vector<int > > vF,vFTC,vFN;
+  if(ext == "obj")
+  {
+    // Convert extension to lower case
+    if(!igl::readOBJ(filename,vV,vTC,vN,vF,vFTC,vFN))
+    {
+      return 1;
+    }
+  }else if(ext == "off")
+  {
+    // Convert extension to lower case
+    if(!igl::readOFF(filename,vV,vF,vN))
+    {
+      return 1;
+    }
+  }else if(ext == "wrl")
+  {
+    // Convert extension to lower case
+    if(!igl::readWRL(filename,vV,vF))
+    {
+      return 1;
+    }
+  //}else
+  //{
+  //  // Convert extension to lower case
+  //  MatrixXi T;
+  //  if(!igl::readMESH(filename,V,T,F))
+  //  {
+  //    return 1;
+  //  }
+  //  //if(F.size() > T.size() || F.size() == 0)
+  //  {
+  //    boundary_faces(T,F);
+  //  }
+  }
+  if(vV.size() > 0)
+  {
+    if(!list_to_matrix(vV,V))
+    {
+      return 1;
+    }
+    triangulate(vF,F);
+  }
+
   // Compute normals, centroid, colors, bounding box diagonal
   per_vertex_normals(V,F,N);
   mid = 0.5*(V.colwise().maxCoeff() + V.colwise().minCoeff());

+ 52 - 0
examples/flare-eyes/Makefile

@@ -0,0 +1,52 @@
+
+.PHONY: all
+
+# Shared flags etc.
+include ../../Makefile.conf
+
+all: obj example
+
+.PHONY: example
+
+LIBIGL=../../
+LIBIGL_INC=-I$(LIBIGL)/include
+LIBIGL_LIB=-L$(LIBIGL)/lib -ligl -liglmatlab -liglembree
+
+EIGEN3_INC=-I/opt/local/include/eigen3 -I/opt/local/include/eigen3/unsupported
+
+ANTTWEAKBAR_INC=-I$(LIBIGL)/external/AntTweakBar/include
+ANTTWEAKBAR_LIB=-L$(LIBIGL)/external/AntTweakBar/lib -lAntTweakBar -framework AppKit
+
+MATLAB_INC=-I$(MATLAB)/extern/include/
+MATLAB_LIB=-L$(MATLAB)/bin/maci64 -lmx -lmat -lmex -lstdc++
+
+CARBON_LIB=-framework Carbon
+
+# Use free glut for mouse scrolling
+FREE_GLUT=/opt/local/
+FREE_GLUT_INC=-I$(FREE_GLUT)/include
+FREE_GLUT_LIB=-L$(FREE_GLUT)/lib -lglut
+GLUT_LIB=$(FREE_GLUT_LIB)
+GLUT_INC=$(FREE_GLUT_INC)
+
+INC=$(LIBIGL_INC) $(ANTTWEAKBAR_INC) $(EIGEN3_INC) $(MATLAB_INC) $(GLUT_INC)
+LIB=$(OPENGL_LIB) $(GLUT_LIB) $(ANTTWEAKBAR_LIB) $(LIBIGL_LIB) $(MATLAB_LIB) $(CARBON_LIB)
+
+CPP_FILES=$(wildcard ./*.cpp)
+OBJ_FILES=$(addprefix obj/,$(notdir $(CPP_FILES:.cpp=.o))) 
+
+example: obj $(OBJ_FILES)
+	g++ $(OPENMP) $(AFLAGS) $(CFLAGS) -o example $(OBJ_FILES) $(LIB)
+
+obj:
+	mkdir -p obj
+
+obj/%.o: %.cpp
+	g++ $(OPENMP) $(AFLAGS) $(CFLAGS) -c $< -o $@ $(INC)
+
+obj/%.o: %.cpp %.h
+	g++ $(OPENMP) $(AFLAGS) $(CFLAGS) -c $< -o $@ $(INC)
+
+clean:
+	rm -f example.o
+	rm -f example

+ 700 - 0
examples/flare-eyes/example.cpp

@@ -0,0 +1,700 @@
+// Small GLUT application to test different scene rotation paradigms 
+//
+
+#include <igl/readOBJ.h>
+#include <igl/writeOBJ.h>
+#include <igl/writeOFF.h>
+#include <igl/readWRL.h>
+#include <igl/report_gl_error.h>
+#include <igl/triangulate.h>
+#include <igl/readOFF.h>
+#include <igl/readMESH.h>
+#include <igl/draw_mesh.h>
+#include <igl/draw_floor.h>
+#include <igl/pathinfo.h>
+#include <igl/list_to_matrix.h>
+#include <igl/quat_to_mat.h>
+#include <igl/per_face_normals.h>
+#include <igl/material_colors.h>
+#include <igl/trackball.h>
+#include <igl/snap_to_canonical_view_quat.h>
+#include <igl/REDRUM.h>
+#include <igl/Camera.h>
+#include <igl/ReAntTweakBar.h>
+#include <igl/PI.h>
+#define IGL_HEADER_ONLY
+#include <igl/lens_flare.h>
+
+#include <Eigen/Core>
+#include <Eigen/Geometry>
+
+#include <GLUT/glut.h>
+
+#include <Carbon/Carbon.h>
+
+#include <string>
+#include <vector>
+#include <stack>
+#include <iostream>
+
+bool eyes_visible = true;
+double x=6,y=232,z=61;
+
+std::vector<igl::Flare> flares;
+std::vector<GLuint> shine_ids;
+std::vector<GLuint> flare_ids;
+int shine_tic;
+
+Eigen::MatrixXd V,N;
+Eigen::VectorXd Vmid,Vmin,Vmax;
+double bbd = 1.0;
+Eigen::MatrixXi F;
+struct State
+{
+  igl::Camera camera;
+} s;
+
+// See README for descriptions
+enum ROTATION_TYPE
+{
+  ROTATION_TYPE_IGL_TRACKBALL = 0,
+  ROTATION_TYPE_TWO_AXIS_VALUATOR_FIXED_UP = 1,
+  NUM_ROTATION_TYPES = 2,
+} rotation_type;
+
+std::stack<State> undo_stack;
+std::stack<State> redo_stack;
+
+bool is_rotating = false;
+int down_x,down_y;
+igl::Camera down_camera;
+
+int width,height;
+Eigen::Vector4f light_pos(-0.1,-0.1,0.9,0);
+
+#define REBAR_NAME "temp.rbr"
+igl::ReTwBar rebar;
+
+// No-op setter, does nothing
+void TW_CALL no_op(const void * /*value*/, void * /*clientData*/)
+{
+}
+
+void TW_CALL get_camera_rotation(void * value, void *clientData)
+{
+  using namespace std;
+  // case current value to double
+  double * quat = (double *)(value);
+  std::copy(s.camera.rotation,s.camera.rotation+4,quat);
+}
+
+void push_undo()
+{
+  undo_stack.push(s);
+  // Clear
+  redo_stack = std::stack<State>();
+}
+
+void reshape(int width, int height)
+{
+  ::width = width;
+  ::height = height;
+  glViewport(0,0,width,height);
+  // Send the new window size to AntTweakBar
+  TwWindowSize(width, height);
+}
+
+void push_scene()
+{
+  using namespace igl;
+  using namespace std;
+  const double angle = s.camera.angle;
+  glMatrixMode(GL_PROJECTION);
+  glPushMatrix();
+  glLoadIdentity();
+  double zNear = 1e-2;
+  double zFar = 100;
+  double aspect = ((double)width)/((double)height);
+  // Amount of scaling needed to "fix" perspective z-shift
+  double z_fix = 1.0;
+  // 5 is far enough to see unit "things" well
+  const double camera_z = 2;
+  // Test if should be using true orthographic projection
+  if(angle == 0)
+  {
+    glOrtho(
+      -0.5*camera_z*aspect,
+      0.5*camera_z*aspect,
+      -0.5*camera_z,
+      0.5*camera_z,
+      zNear,
+      zFar);
+  }else
+  {
+    // Make sure aspect is sane
+    aspect = aspect < 0.01 ? 0.01 : aspect;
+    gluPerspective(angle,aspect,zNear,zFar);
+    z_fix = 2.*tan(angle/2./360.*2.*M_PI);
+  }
+
+  glMatrixMode(GL_MODELVIEW);
+  glPushMatrix();
+  glLoadIdentity();
+  gluLookAt(0,0,camera_z,0,0,0,0,1,0);
+  // Adjust scale to correct perspective
+  glScaled(z_fix,z_fix,z_fix);
+  // scale, pan
+  glScaled( s.camera.zoom, s.camera.zoom, s.camera.zoom);
+  double mat[4*4];
+  quat_to_mat(s.camera.rotation,mat);
+  glMultMatrixd(mat);
+}
+
+void push_object()
+{
+  using namespace igl;
+  glPushMatrix();
+  glScaled(2./bbd,2./bbd,2./bbd);
+  glTranslated(-Vmid(0),-Vmid(1),-Vmid(2));
+}
+
+void pop_object()
+{
+  glPopMatrix();
+}
+
+void pop_scene()
+{
+  glMatrixMode(GL_PROJECTION);
+  glPopMatrix();
+  glMatrixMode(GL_MODELVIEW);
+  glPopMatrix();
+}
+
+// Set up double-sided lights
+void lights()
+{
+  using namespace std;
+  using namespace Eigen;
+  glEnable(GL_LIGHTING);
+  glLightModelf(GL_LIGHT_MODEL_TWO_SIDE,GL_TRUE);
+  glEnable(GL_LIGHT0);
+  glEnable(GL_LIGHT1);
+  float WHITE[4] =  {0.8,0.8,0.8,1.};
+  float GREY[4] =  {0.4,0.4,0.4,1.};
+  float BLACK[4] =  {0.,0.,0.,1.};
+  Vector4f pos = light_pos;
+  glLightfv(GL_LIGHT0,GL_AMBIENT,GREY);
+  glLightfv(GL_LIGHT0,GL_DIFFUSE,WHITE);
+  glLightfv(GL_LIGHT0,GL_SPECULAR,BLACK);
+  glLightfv(GL_LIGHT0,GL_POSITION,pos.data());
+  pos(0) *= -1;
+  pos(1) *= -1;
+  pos(2) *= -1;
+  glLightfv(GL_LIGHT1,GL_AMBIENT,GREY);
+  glLightfv(GL_LIGHT1,GL_DIFFUSE,WHITE);
+  glLightfv(GL_LIGHT1,GL_SPECULAR,BLACK);
+  glLightfv(GL_LIGHT1,GL_POSITION,pos.data());
+}
+
+void init_flare()
+{
+}
+
+void draw_flare()
+{
+  using namespace igl;
+  using namespace Eigen;
+  glPushMatrix();
+  glScaled(bbd*0.5,bbd*0.5,bbd*0.5);
+  Vector3f light(0,0.1,0);
+  lens_flare_draw(flares,shine_ids,flare_ids,light,1.0,shine_tic);
+  glPopMatrix();
+}
+
+void draw_eyes()
+{
+  using namespace Eigen;
+  using namespace std;
+  using namespace igl;
+#define NUM_LEDS 2
+  Vector3d LED_pos[NUM_LEDS];
+  LED_pos[0] = Vector3d( x,y,z);
+  LED_pos[1] = Vector3d(-x,y,z);
+  enum LEDMethod
+  {
+    LED_METHOD_COLORED_CIRCLE = 0,
+    LED_METHOD_OUTLINED_CIRCLE = 1,
+    LED_METHOD_TEXTURE_FLARE = 2
+  } method = LED_METHOD_TEXTURE_FLARE;
+
+  
+  for(int l = 0;l<NUM_LEDS;l++)
+  {
+    glPushMatrix();
+    glTranslated(LED_pos[l](0), LED_pos[l](1), LED_pos[l](2));
+    const double r = 2.0;
+    const float color[4] = {1,0,0,1};
+    glScaled(r,r,r);
+    switch(method)
+    {
+      case LED_METHOD_COLORED_CIRCLE:
+      {
+        glEnable(GL_COLOR_MATERIAL);
+        glColorMaterial(GL_FRONT,GL_AMBIENT);
+        glColor4fv(color);
+        glBegin(GL_TRIANGLE_FAN);
+        glVertex3d(0,0,0);
+        for(double theta = 0;theta<2.*PI;theta+=2.*PI/15.)
+        {
+          glVertex3d(cos(theta),sin(theta),0);
+        }
+        glEnd();
+        break;
+      }
+      case LED_METHOD_OUTLINED_CIRCLE:
+      {
+        glEnable(GL_COLOR_MATERIAL);
+        glDisable(GL_LIGHTING);
+        glColorMaterial(GL_FRONT,GL_DIFFUSE);
+        glBegin(GL_TRIANGLE_FAN);
+        glColor4fv(color);
+        glVertex3d(0,0,0);
+        glColor4f(0,0,0,1);
+        for(double theta = 0;theta<2.*PI;theta+=2.*PI/15.)
+        {
+          glVertex3d(cos(theta),sin(theta),0);
+        }
+        glEnd();
+        break;
+      }
+      case LED_METHOD_TEXTURE_FLARE:
+      {
+        draw_flare();
+        break;
+      }
+    }
+    glPopMatrix();
+  }
+}
+
+void display()
+{
+  using namespace igl;
+  using namespace std;
+  glClearColor(0,0,0,0);
+  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+  glEnable(GL_DEPTH_TEST);
+  glEnable(GL_BLEND);
+  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+  glEnable(GL_NORMALIZE);
+  lights();
+  push_scene();
+  push_object();
+
+  // Set material properties
+  glDisable(GL_COLOR_MATERIAL);
+  const float NEAR_BLACK[4] = {0.1,0.1,0.1,1.0};
+  glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT,  NEAR_BLACK);
+  glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,  MIDNIGHT_BLUE_DIFFUSE);
+  glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, SILVER_SPECULAR);
+  glMaterialf (GL_FRONT_AND_BACK, GL_SHININESS, 128);
+
+  
+  draw_mesh(V,F,N);
+  if(eyes_visible)
+  {
+    draw_eyes();
+  }
+  pop_object();
+
+  // Draw a nice floor
+  glPushMatrix();
+  const double floor_offset =
+    -2./bbd*(V.col(1).maxCoeff()-Vmid(1));
+  glTranslated(0,floor_offset,0);
+  const float GREY[4] = {0.5,0.5,0.6,1.0};
+  const float DARK_GREY[4] = {0.2,0.2,0.3,1.0};
+  draw_floor(GREY,DARK_GREY);
+  glPopMatrix();
+
+  pop_scene();
+
+  report_gl_error();
+
+  TwDraw();
+  glutSwapBuffers();
+  glutPostRedisplay();
+}
+
+void mouse_wheel(int wheel, int direction, int mouse_x, int mouse_y)
+{
+  using namespace std;
+  push_undo();
+  if(wheel == 0)
+  {
+    static double mouse_scroll_y = 0;
+    const double delta_y = 0.125*direction;
+    mouse_scroll_y += delta_y;
+    // absolute scale difference when changing zooms (+1)
+    const double z_diff = 0.01;
+    GLint viewport[4];
+    glGetIntegerv(GL_VIEWPORT,viewport);
+    if(TwMouseMotion(mouse_x, viewport[3] - mouse_y))
+    {
+      TwMouseWheel(mouse_scroll_y);
+    }else
+    {
+      s.camera.zoom *= (1.0+double(direction)*z_diff);
+      const double min_zoom = 0.01;
+      const double max_zoom = 10.0;
+      s.camera.zoom = min(max_zoom,max(min_zoom,s.camera.zoom));
+    }
+  }else
+  {
+    if(!is_rotating)
+    {
+      // Change viewing angle (reshape will take care of adjust zoom)
+      const double a_diff = 1.0;
+      s.camera.angle += double(direction)*a_diff;
+      const double min_angle = 15.0;
+      s.camera.angle = 
+        min(90.0,max(min_angle,s.camera.angle));
+    }
+  }
+}
+
+void mouse(int glutButton, int glutState, int mouse_x, int mouse_y)
+{
+  using namespace std;
+  using namespace Eigen;
+  using namespace igl;
+  bool tw_using = TwEventMouseButtonGLUT(glutButton,glutState,mouse_x,mouse_y);
+  switch(glutButton)
+  {
+    case GLUT_RIGHT_BUTTON:
+    case GLUT_LEFT_BUTTON:
+    {
+      switch(glutState)
+      {
+        case 1:
+          // up
+          glutSetCursor(GLUT_CURSOR_INHERIT);
+          is_rotating = false;
+          break;
+        case 0:
+          if(!tw_using)
+          {
+            push_undo();
+            glutSetCursor(GLUT_CURSOR_CYCLE);
+            // collect information for trackball
+            is_rotating = true;
+            down_camera = s.camera;
+            down_x = mouse_x;
+            down_y = mouse_y;
+          }
+        break;
+      }
+      break;
+    }
+    // Scroll down
+    case 3:
+    {
+      mouse_wheel(0,-1,mouse_x,mouse_y);
+      break;
+    }
+    // Scroll up
+    case 4:
+    {
+      mouse_wheel(0,1,mouse_x,mouse_y);
+      break;
+    }
+    // Scroll left
+    case 5:
+    {
+      mouse_wheel(1,-1,mouse_x,mouse_y);
+      break;
+    }
+    // Scroll right
+    case 6:
+    {
+      mouse_wheel(1,1,mouse_x,mouse_y);
+      break;
+    }
+  }
+}
+
+void mouse_drag(int mouse_x, int mouse_y)
+{
+  using namespace igl;
+  using namespace std;
+  using namespace Eigen;
+
+  if(is_rotating)
+  {
+    glutSetCursor(GLUT_CURSOR_CYCLE);
+    switch(rotation_type)
+    {
+      case ROTATION_TYPE_IGL_TRACKBALL:
+      {
+        // Rotate according to trackball
+        igl::trackball<double>(
+          width,
+          height,
+          2.0,
+          down_camera.rotation,
+          down_x,
+          down_y,
+          mouse_x,
+          mouse_y,
+          s.camera.rotation);
+          break;
+      }
+      case ROTATION_TYPE_TWO_AXIS_VALUATOR_FIXED_UP:
+      {
+        Quaterniond down_q;
+        copy(down_camera.rotation,down_camera.rotation+4,down_q.coeffs().data());
+        Vector3d axis(0,1,0);
+        const double speed = 2.0;
+        Quaterniond q;
+        q = down_q * 
+          Quaterniond(
+            AngleAxisd(
+              M_PI*((double)(mouse_x-down_x))/(double)width*speed/2.0,
+              axis.normalized()));
+        q.normalize();
+        {
+          Vector3d axis(1,0,0);
+          const double speed = 2.0;
+          if(axis.norm() != 0)
+          {
+            q = 
+              Quaterniond(
+                AngleAxisd(
+                  M_PI*(mouse_y-down_y)/(double)width*speed/2.0,
+                  axis.normalized())) * q;
+            q.normalize();
+          }
+        }
+        copy(q.coeffs().data(),q.coeffs().data()+4,s.camera.rotation);
+        break;
+      }
+      default:
+        break;
+    }
+  }
+}
+
+void init_relative()
+{
+  using namespace Eigen;
+  using namespace igl;
+  using namespace std;
+  per_face_normals(V,F,N);
+  Vmax = V.colwise().maxCoeff();
+  Vmin = V.colwise().minCoeff();
+  Vmid = 0.5*(Vmax + Vmin);
+  bbd = (Vmax-Vmin).norm();
+}
+
+
+KeyMap keyStates ;
+bool IS_KEYDOWN( uint16_t vKey )
+{
+  uint8_t index = vKey / 32 ;
+  uint8_t shift = vKey % 32 ;
+  return keyStates[index].bigEndianValue & (1 << shift) ;
+}
+
+void undo()
+{
+  using namespace std;
+  if(!undo_stack.empty())
+  {
+    redo_stack.push(s);
+    s = undo_stack.top();
+    undo_stack.pop();
+  }
+}
+
+void redo()
+{
+  using namespace std;
+  if(!redo_stack.empty())
+  {
+    undo_stack.push(s);
+    s = redo_stack.top();
+    redo_stack.pop();
+  }
+}
+
+void key(unsigned char key, int mouse_x, int mouse_y)
+{
+  using namespace std;
+  GetKeys(keyStates);
+  const bool command_down = IS_KEYDOWN(kVK_Command);
+  const bool shift_down = IS_KEYDOWN(kVK_Shift);
+  switch(key)
+  {
+    // ESC
+    case char(27):
+      rebar.save(REBAR_NAME);
+    // ^C
+    case char(3):
+      exit(0);
+    case 'z':
+    case 'Z':
+      if(command_down)
+      {
+        if(shift_down)
+        {
+          redo();
+        }else
+        {
+          undo();
+        }
+        break;
+      }else
+      {
+        push_undo();
+        igl::snap_to_canonical_view_quat<double>(
+          s.camera.rotation,
+          1.0,
+          s.camera.rotation);
+        break;
+      }
+    default:
+      if(!TwEventKeyboardGLUT(key,mouse_x,mouse_y))
+      {
+        cout<<"Unknown key command: "<<key<<" "<<int(key)<<endl;
+      }
+  }
+  
+}
+
+int main(int argc, char * argv[])
+{
+  using namespace std;
+  using namespace Eigen;
+  using namespace igl;
+  string filename = "../shared/beast.obj";
+  if(argc < 2)
+  {
+    cerr<<"Usage:"<<endl<<"    ./example input.obj"<<endl;
+    cout<<endl<<"Opening default mesh..."<<endl;
+  }else
+  {
+    // Read and prepare mesh
+    filename = argv[1];
+  }
+
+  // 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<<"[^C,ESC]            Exit."<<endl;
+
+  // dirname, basename, extension and filename
+  string d,b,ext,f;
+  pathinfo(filename,d,b,ext,f);
+  // Convert extension to lower case
+  transform(ext.begin(), ext.end(), ext.begin(), ::tolower);
+  vector<vector<double > > vV,vN,vTC;
+  vector<vector<int > > vF,vFTC,vFN;
+  if(ext == "obj")
+  {
+    // Convert extension to lower case
+    if(!igl::readOBJ(filename,vV,vTC,vN,vF,vFTC,vFN))
+    {
+      return 1;
+    }
+  }else if(ext == "off")
+  {
+    // Convert extension to lower case
+    if(!igl::readOFF(filename,vV,vF,vN))
+    {
+      return 1;
+    }
+  }else if(ext == "wrl")
+  {
+    // Convert extension to lower case
+    if(!igl::readWRL(filename,vV,vF))
+    {
+      return 1;
+    }
+  //}else
+  //{
+  //  // Convert extension to lower case
+  //  MatrixXi T;
+  //  if(!igl::readMESH(filename,V,T,F))
+  //  {
+  //    return 1;
+  //  }
+  //  //if(F.size() > T.size() || F.size() == 0)
+  //  {
+  //    boundary_faces(T,F);
+  //  }
+  }
+  if(vV.size() > 0)
+  {
+    if(!list_to_matrix(vV,V))
+    {
+      return 1;
+    }
+    triangulate(vF,F);
+  }
+
+  init_relative();
+
+  // Init glut
+  glutInit(&argc,argv);
+  if( !TwInit(TW_OPENGL, NULL) )
+  {
+    // A fatal error occured
+    fprintf(stderr, "AntTweakBar initialization failed: %s\n", TwGetLastError());
+    return 1;
+  }
+  // Create a tweak bar
+  rebar.TwNewBar("TweakBar");
+  rebar.TwAddVarCB("camera_rotation", TW_TYPE_QUAT4D, no_op,get_camera_rotation, NULL, "open readonly=true");
+  TwEnumVal RotationTypesEV[NUM_ROTATION_TYPES] = 
+  {
+    {ROTATION_TYPE_IGL_TRACKBALL,"igl trackball"},
+    {ROTATION_TYPE_TWO_AXIS_VALUATOR_FIXED_UP,"two a... fixed up"},
+  };
+  TwType RotationTypeTW = 
+    ReTwDefineEnum(
+        "RotationType", 
+        RotationTypesEV, 
+        NUM_ROTATION_TYPES);
+  rebar.TwAddVarRW( "rotation_type", RotationTypeTW, &rotation_type,"keyIncr=] keyDecr=[");
+  rebar.TwAddVarRW( "x",TW_TYPE_DOUBLE, &x,"");
+  rebar.TwAddVarRW( "y",TW_TYPE_DOUBLE, &y,"");
+  rebar.TwAddVarRW( "z",TW_TYPE_DOUBLE, &z,"");
+  rebar.TwAddVarRW( "eyes_visible",TW_TYPE_BOOLCPP, &eyes_visible,"key=e");
+  rebar.load(REBAR_NAME);
+
+
+  // Init antweakbar
+  glutInitDisplayString( "rgba depth double samples>=8 ");
+  glutInitWindowSize(glutGet(GLUT_SCREEN_WIDTH)/2.0,glutGet(GLUT_SCREEN_HEIGHT)/2.0);
+  glutCreateWindow("upright");
+  glutDisplayFunc(display);
+  glutReshapeFunc(reshape);
+  glutKeyboardFunc(key);
+  glutMouseFunc(mouse);
+  glutMotionFunc(mouse_drag);
+  glutPassiveMotionFunc((GLUTmousemotionfun)TwEventMouseMotionGLUT);
+  // Init flares
+  lens_flare_load_textures(shine_ids,flare_ids);
+  const float RED[3] = {1,0,0};
+  const float GREEN[3] = {0,1,0};
+  const float BLUE[3] = {0,0,1};
+  lens_flare_create(RED,GREEN,BLUE,flares);
+
+  glutMainLoop();
+
+  return 0;
+}

+ 1 - 0
include/igl/flare_textures.h.REMOVED.git-id

@@ -0,0 +1 @@
+7520cadcea34fea08b0f43f8d6d74e1f51fa94cb

+ 184 - 0
include/igl/lens_flare.cpp

@@ -0,0 +1,184 @@
+#include "lens_flare.h"
+
+#include "C_STR.h"
+#include "unproject.h"
+#include "project.h"
+#include "shine_textures.h"
+#include "flare_textures.h"
+
+// http://www.opengl.org/archives/resources/features/KilgardTechniques/LensFlare/glflare.c
+
+static void setup_texture(
+  const uint8_t * texture, 
+  const int width,
+  const int height,
+  GLuint texobj,
+  GLenum minFilter, GLenum maxFilter)
+{
+  glBindTexture(GL_TEXTURE_2D, texobj);
+  glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter);
+  glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, maxFilter);
+  glTexImage2D(GL_TEXTURE_2D, 0, 1, width, height, 0,
+    GL_LUMINANCE, GL_UNSIGNED_BYTE, texture);
+}
+
+void igl::lens_flare_load_textures(
+  std::vector<GLuint> & shine_id,
+  std::vector<GLuint> & flare_id)
+{
+  glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+  shine_id.resize(10);
+  glGenTextures(10,&shine_id[0]);
+  for (int i = 0; i < (int)shine_id.size(); i++) {
+    setup_texture(
+      SHINE_TEXTURES[i],
+      SHINE_TEXTURE_WIDTHS[i],
+      SHINE_TEXTURE_HEIGHTS[i],
+      shine_id[i], GL_LINEAR, GL_LINEAR);
+  }
+  flare_id.resize(6);
+  glGenTextures(6,&flare_id[0]);
+  for (int i = 0; i < (int)flare_id.size(); i++) {
+    setup_texture(
+      FLARE_TEXTURES[i],
+      FLARE_TEXTURE_WIDTHS[i],
+      FLARE_TEXTURE_HEIGHTS[i],
+      flare_id[i], GL_LINEAR, GL_LINEAR);
+  }
+}
+
+void igl::lens_flare_create(
+  const float * A,
+  const float * B,
+  const float * C,
+  std::vector<igl::Flare> & flares)
+{
+  using namespace igl;
+  flares.resize(12);
+  /* Shines */
+  flares[0] = Flare(-1, 1.0f, 0.1f, C, 1.0);
+  flares[1] = Flare(-1, 1.0f, 0.15f, B, 1.0);
+  flares[2] = Flare(-1, 1.0f, 0.35f, A, 1.0);
+
+  /* Flares */
+  flares[3] =  Flare(2, 1.3f, 0.04f, A, 0.6);
+  flares[4] =  Flare(3, 1.0f, 0.1f, A, 0.4);
+  flares[5] =  Flare(1, 0.5f, 0.2f, A, 0.3);
+  flares[6] =  Flare(3, 0.2f, 0.05f, A, 0.3);
+  flares[7] =  Flare(0, 0.0f, 0.04f, A, 0.3);
+  flares[8] =  Flare(5, -0.25f, 0.07f, A, 0.5);
+  flares[9] =  Flare(5, -0.4f, 0.02f, A, 0.6);
+  flares[10] = Flare(5, -0.6f, 0.04f, A, 0.4);
+  flares[11] = Flare(5, -1.0f, 0.03f, A, 0.2);
+}
+
+void igl::lens_flare_draw(
+  const std::vector<igl::Flare> & flares,
+  const std::vector<GLuint> & shine_ids,
+  const std::vector<GLuint> & flare_ids,
+  const Eigen::Vector3f & light,
+  const float near_clip,
+  int & shine_tic)
+{
+  bool ot2,ob,odt;
+  int obsa,obda;
+  ot2 = glIsEnabled(GL_TEXTURE_2D);
+  ob = glIsEnabled(GL_BLEND);
+  odt = glIsEnabled(GL_DEPTH_TEST);
+  glGetIntegerv(GL_BLEND_SRC_ALPHA,&obsa);
+  glGetIntegerv(GL_BLEND_DST_ALPHA,&obda);
+
+  glEnable(GL_TEXTURE_2D);
+  glDisable(GL_DEPTH_TEST);
+  glEnable(GL_BLEND);
+  glBlendFunc(GL_ONE, GL_ONE);
+
+  using namespace Eigen;
+  using namespace igl;
+
+  // Assuming scene is pushed
+  Vector3f win_o,from,at;
+  project(Vector3f(0,0,0),win_o);
+  win_o(2) = -1e26;
+  unproject(win_o,from);
+  win_o(2) = 1;
+  unproject(win_o,at);
+
+  Vector3f view_dir, tmp, light0, light_dir, position, dx, dy,
+    center, axis, sx, sy;
+  GLfloat dot, global_scale = 1.0;
+  int i;
+
+  /* view_dir = normalize(at-from) */
+  view_dir =  at -  from;
+  view_dir.normalize();
+
+  /* center = from + near_clip * view_dir */
+  tmp =  near_clip* view_dir;
+  center =  from +  tmp;
+
+  /* light_dir = normalize(light-from) */
+  light_dir =  light -  from;
+  light_dir.normalize();
+
+  /* light0 = from + dot(light,view_dir)*near_clip*light_dir */
+  dot = light_dir.dot( view_dir);
+  tmp =  near_clip / dot* light_dir;
+  light0 =  from + light_dir;
+
+  /* axis = light - center */
+  axis =  light0 -  center;
+  dx =  axis;
+
+  /* dx = normalize(axis) */
+  dx.normalize();
+
+  /* dy = cross(dx,view_dir) */
+  dy =  dx.cross( view_dir);
+
+
+  for (i = 0; i < (int)flares.size(); i++)
+  {
+    sx =  flares[i].scale * global_scale* dx;
+    sy =  flares[i].scale * global_scale* dy;
+
+    glColor3fv(flares[i].color);
+    if (flares[i].type < 0) {
+      glBindTexture(GL_TEXTURE_2D, shine_ids[shine_tic]);
+      shine_tic = (shine_tic + 1) % shine_ids.size();
+    } else {
+      glBindTexture(GL_TEXTURE_2D, flare_ids[flares[i].type]);
+    }
+
+    /* position = center + flare[i].loc * axis */
+    tmp =  flares[i].loc* axis;
+    position =  center +  tmp;
+
+    glBegin(GL_QUADS);
+    glTexCoord2f(0.0, 0.0);
+    tmp =  position +  sx;
+    tmp =  tmp +  sy;
+    glVertex3fv(tmp.data());
+
+    glTexCoord2f(1.0, 0.0);
+    tmp =  position -  sx;
+    tmp =  tmp +  sy;
+    glVertex3fv(tmp.data());
+
+    glTexCoord2f(1.0, 1.0);
+    tmp =  position -  sx;
+    tmp =  tmp -  sy;
+    glVertex3fv(tmp.data());
+
+    glTexCoord2f(0.0, 1.0);
+    tmp =  position +  sx;
+    tmp =  tmp -  sy;
+    glVertex3fv(tmp.data());
+    glEnd();
+  }
+  ot2?glEnable(GL_TEXTURE_2D):glDisable(GL_TEXTURE_2D);
+  ob?glEnable(GL_BLEND):glDisable(GL_BLEND);
+  odt?glEnable(GL_DEPTH_TEST):glDisable(GL_DEPTH_TEST);
+  glBlendFunc(obsa,obda);
+}

+ 78 - 0
include/igl/lens_flare.h

@@ -0,0 +1,78 @@
+#ifndef IGL_LENS_FLARE_H
+#define IGL_LENS_FLARE_H
+
+#include <igl/OpenGL_convenience.h>
+#include <Eigen/Core>
+
+#include <vector>
+
+namespace igl
+{
+  struct Flare{
+    int type;             /* flare texture index, 0..5 */
+    float scale;
+    float loc;            /* postion on axis */
+    float color[3];
+    Flare(){}
+    Flare(int type, float location, float scale, const float color[3], float colorScale) :
+      type(type),
+      scale(scale),
+      loc(location)
+    {
+      this->color[0] = color[0] * colorScale;
+      this->color[1] = color[1] * colorScale;
+      this->color[2] = color[2] * colorScale;
+    }
+  };
+  
+  
+  // Initialize shared data for lens flates
+  //
+  // Inputs:
+  //   start_id   starting texture id location (should have at least id:id+16 free)
+  // Outputs:
+  //   shine  list of texture ids for shines
+  //   flare  list of texture ids for flares
+  void lens_flare_load_textures(
+    std::vector<GLuint> & shine_ids,
+    std::vector<GLuint> & flare_ids);
+  
+  // Create a set of lens flares
+  //
+  // Inputs:
+  //   A  primary color
+  //   B  secondary color
+  //   C  secondary color
+  // Outputs:
+  //   flares  list of flare objects
+  void lens_flare_create(
+    const float * A,
+    const float * B,
+    const float * C,
+    std::vector<Flare> & flares);
+  
+  // Draw lens flares
+  //
+  // Inputs:
+  //   flares  list of Flare objects
+  //   shine_ids  list of shine textures
+  //   flare_ids  list of flare texture ids
+  //   light  position of light
+  //   near_clip  near clipping plane
+  //   shine_tic  current "tic" in shine textures
+  // Outputs:
+  //   shine_tic  current "tic" in shine textures
+  void lens_flare_draw(
+    const std::vector<Flare> & flares,
+    const std::vector<GLuint> & shine_ids,
+    const std::vector<GLuint> & flare_ids,
+    const Eigen::Vector3f & light,
+    const float near_clip,
+    int & shine_tic);
+};
+
+#ifdef IGL_HEADER_ONLY
+#  include "lens_flare.cpp"
+#endif
+
+#endif

+ 11 - 2
include/igl/project.cpp

@@ -68,8 +68,16 @@ IGL_INLINE int igl::project(
   const Eigen::PlainObjectBase<Derivedobj> & obj,
   Eigen::PlainObjectBase<Derivedwin> & win)
 {
-  return igl::project(obj(0),obj(1),obj(2),
-      &win(0),&win(1),&win(2));
+  Eigen::Vector3d dobj(obj(0),obj(1),obj(2));
+  Eigen::Vector3d dwin;
+  int ret = project(dobj(0),dobj(1),dobj(2),
+      &dwin.data()[0],
+      &dwin.data()[1],
+      &dwin.data()[2]);
+  win(0) = dwin(0);
+  win(1) = dwin(1);
+  win(2) = dwin(2);
+  return ret;
 }
 
 template <typename Derivedobj>
@@ -85,6 +93,7 @@ IGL_INLINE Eigen::PlainObjectBase<Derivedobj> igl::project(
 // Explicit template instanciations
 template int igl::project<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 Eigen::PlainObjectBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> > igl::project<Eigen::Matrix<double, 3, 1, 0, 3, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> > const&);
+template int igl::project<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> >&);
 #endif
 
 #endif

+ 1 - 0
include/igl/shine_textures.h.REMOVED.git-id

@@ -0,0 +1 @@
+defe9e744e9608a42c2e93b5a416ed5c55a7ae76

+ 11 - 4
include/igl/unproject.cpp

@@ -26,15 +26,22 @@ IGL_INLINE int igl::unproject(
   const Eigen::PlainObjectBase<Derivedwin> & win,
   Eigen::PlainObjectBase<Derivedobj> & obj)
 {
-  return unproject(win(0),win(1),win(2),
-      &obj.data()[0],
-      &obj.data()[1],
-      &obj.data()[2]);
+  Eigen::Vector3d dwin(win(0),win(1),win(2));
+  Eigen::Vector3d dobj;
+  int ret = unproject(dwin(0),dwin(1),dwin(2),
+      &dobj.data()[0],
+      &dobj.data()[1],
+      &dobj.data()[2]);
+  obj(0) = dobj(0);
+  obj(1) = dobj(1);
+  obj(2) = dobj(2);
+  return ret;
 }
 
 #ifndef IGL_HEADER_ONLY
 // Explicit template instanciation
 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> >&);
 #endif
 
 #endif