diff --git a/CMakeLists.txt b/CMakeLists.txt
index 3baa3075e59b1fe20916b6b72f1a71d5d3076b86..f32171826d6aecf9a9c59a9ef28ba2103388e1ef 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -88,6 +88,7 @@ opt(SOLVER "Enable built-in finite element solvers (required for compounds)" ${D
 opt(TAUCS "Enable Taucs linear solver" ${DEFAULT})
 opt(TCMALLOC "Enable libtcmalloc, a fast malloc implementation but that does not release memory" OFF)
 opt(TETGEN "Enable Tetgen 3D initial mesh generator" ${DEFAULT})
+opt(VISUDEV "Enable additional visualization capabilities for development purpose" OFF)
 opt(VORO3D "Enable Voro3D (for hex meshing, experimental)" ${DEFAULT})
 opt(WRAP_JAVA "Enable generation of Java wrappers" OFF)
 opt(WRAP_PYTHON "Enable generation of Python wrappers" OFF)
@@ -488,6 +489,10 @@ if(ENABLE_PARSER)
   set_config_option(HAVE_PARSER "Parser")
 endif(ENABLE_PARSER)
 
+if(ENABLE_VISUDEV)
+  set_config_option(HAVE_VISUDEV "VisuDev")
+endif(ENABLE_VISUDEV)
+
 if(ENABLE_FLTK)
   # first, try to use fltk-config for fltk >= 1.3 (FindFLTK is buggy on Unix,
   # where e.g. xft and xinerama options are not dealt with)
diff --git a/Common/Context.h b/Common/Context.h
index c5c361aebb8d519c56f0eac3fa43161c1c74135b..8b43003b95de128629e48eda5a5f908615779484 100644
--- a/Common/Context.h
+++ b/Common/Context.h
@@ -236,6 +236,8 @@ class CTX {
   int mouseSelection, mouseHoverMeshes, pickElements;
   // disable some warnings for expert users?
   int expertMode;
+  // Enable heavy visualization capabilities (for development purpose)
+  int heavyVisu;
   // dynamic: equal to 1 while gmsh is printing
   int printing;
   // hide all unselected entities?
diff --git a/Common/GmshConfig.h.in b/Common/GmshConfig.h.in
index ed5a2758328ffcf4616d068440ae3fb2f3da478a..2b6d92121c5142fcc56c909d1acb962bd0f38376 100644
--- a/Common/GmshConfig.h.in
+++ b/Common/GmshConfig.h.in
@@ -67,6 +67,7 @@
 #cmakedefine HAVE_SOLVER
 #cmakedefine HAVE_TAUCS
 #cmakedefine HAVE_TETGEN
+#cmakedefine HAVE_VISUDEV
 #cmakedefine HAVE_VORO3D
 #cmakedefine HAVE_ZIPPER
 
diff --git a/Common/Options.cpp b/Common/Options.cpp
index a99ba9bdec715dec004cb7d33e4e380f4f8bbfcb..ad0e613df34e6960c02cabb27d6c7af608f69af5 100644
--- a/Common/Options.cpp
+++ b/Common/Options.cpp
@@ -3627,6 +3627,23 @@ double opt_general_expert_mode(OPT_ARGS_NUM)
   return CTX::instance()->expertMode;
 }
 
+#if defined(HAVE_VISUDEV)
+double opt_general_heavy_visualization(OPT_ARGS_NUM)
+{
+  if(action & GMSH_SET){
+    if(CTX::instance()->heavyVisu != val)
+      CTX::instance()->mesh.changed |= (ENT_LINE | ENT_SURFACE | ENT_VOLUME);
+    CTX::instance()->heavyVisu = (int)val;
+  }
+#if defined(HAVE_FLTK)
+  if(FlGui::available() && (action & GMSH_GUI))
+    FlGui::instance()->options->general.butt[22]->value
+        (CTX::instance()->heavyVisu);
+#endif
+  return CTX::instance()->heavyVisu;
+}
+#endif
+
 double opt_general_stereo_mode(OPT_ARGS_NUM)
 {
   if(action & GMSH_SET)
diff --git a/Common/Options.h b/Common/Options.h
index 5cb13d5a000c53e076a3003fc84248fa5721898a..53a35ad8bb72b56ac60a329035d6ee7f62334b34 100644
--- a/Common/Options.h
+++ b/Common/Options.h
@@ -285,6 +285,7 @@ double opt_general_zoom_factor(OPT_ARGS_NUM);
 double opt_general_expert_mode(OPT_ARGS_NUM);
 double opt_general_stereo_mode(OPT_ARGS_NUM);
 double opt_general_camera_mode(OPT_ARGS_NUM);
+double opt_general_heavy_visualization(OPT_ARGS_NUM);
 double opt_general_eye_sep_ratio(OPT_ARGS_NUM);
 double opt_general_focallength_ratio(OPT_ARGS_NUM);
 double opt_general_camera_aperture(OPT_ARGS_NUM);
diff --git a/Common/VertexArray.cpp b/Common/VertexArray.cpp
index ee329bf7e39b5f2ba7d2f6902b7b0242e0e9306b..c6a0524b080d294537df86a59b4bf230c48b5686 100644
--- a/Common/VertexArray.cpp
+++ b/Common/VertexArray.cpp
@@ -31,6 +31,11 @@ void VertexArray::_addVertex(float x, float y, float z)
 
 void VertexArray::_addNormal(float nx, float ny, float nz)
 {
+#if defined(HAVE_VISUDEV)
+  _normals.push_back(nx);
+  _normals.push_back(ny);
+  _normals.push_back(nz);
+#else
   // storing the normals as bytes hurts rendering performance, but it
   // significantly reduces the memory footprint
   char cx = float2char(nx);
@@ -39,6 +44,7 @@ void VertexArray::_addNormal(float nx, float ny, float nz)
   _normals.push_back(cx);
   _normals.push_back(cy);
   _normals.push_back(cz);
+#endif
 }
 
 void VertexArray::_addColor(unsigned char r, unsigned char g, unsigned char b,
@@ -131,9 +137,9 @@ void VertexArray::finalize()
 
 class AlphaElement {
  public:
-  AlphaElement(float *vp, char *np, unsigned char *cp) : v(vp), n(np), c(cp) {}
+  AlphaElement(float *vp, normal_type *np, unsigned char *cp) : v(vp), n(np), c(cp) {}
   float *v;
-  char *n;
+  normal_type *n;
   unsigned char *c;
 };
 
@@ -182,14 +188,14 @@ void VertexArray::sort(double x, double y, double z)
   elements.reserve(n);
   for(int i = 0; i < n; i++){
     float *vp = &_vertices[3 * npe * i];
-    char *np = _normals.empty() ? 0 : &_normals[3 * npe * i];
+    normal_type *np = _normals.empty() ? 0 : &_normals[3 * npe * i];
     unsigned char *cp = _colors.empty() ? 0 : &_colors[4 * npe * i];
     elements.push_back(AlphaElement(vp, np, cp));
   }
   std::sort(elements.begin(), elements.end(), AlphaElementLessThan());
 
   std::vector<float> sortedVertices;
-  std::vector<char> sortedNormals;
+  std::vector<normal_type> sortedNormals;
   std::vector<unsigned char> sortedColors;
   sortedVertices.reserve(_vertices.size());
   sortedNormals.reserve(_normals.size());
@@ -215,8 +221,9 @@ void VertexArray::sort(double x, double y, double z)
 
 double VertexArray::getMemoryInMb()
 {
-  int bytes = _vertices.size() * sizeof(float) + _normals.size() * sizeof(char) +
-    _colors.size() * sizeof(unsigned char);
+  int bytes = _vertices.size() * sizeof(float) +
+              _normals.size() * sizeof(normal_type) +
+              _colors.size() * sizeof(unsigned char);
   return (double)bytes / 1024. / 1024.;
 }
 
@@ -224,7 +231,9 @@ char *VertexArray::toChar(int num, std::string name, int type, double min, doubl
                           int numsteps, double time, SBoundingBox3d bbox, int &len)
 {
   int vn = _vertices.size(), nn = _normals.size(), cn = _colors.size();
-  int vs = vn * sizeof(float), ns = nn * sizeof(char), cs = cn * sizeof(unsigned char);
+  int vs = vn * sizeof(float),
+      ns = nn * sizeof(normal_type),
+      cs = cn * sizeof(unsigned char);
   int is = sizeof(int), ds = sizeof(double);
   int ss = name.size();
   double xmin = bbox.min().x(), ymin = bbox.min().y(), zmin = bbox.min().z();
@@ -314,7 +323,8 @@ void VertexArray::fromChar(int length, const char *bytes, int swap)
 
   int nn; memcpy(&nn, &bytes[index], is); index += is;
   if(nn){
-    _normals.resize(nn); int ns = nn * sizeof(char);
+    _normals.resize(nn);
+    int ns = nn * sizeof(normal_type);
     memcpy(&_normals[0], &bytes[index], ns); index += ns;
   }
 
diff --git a/Common/VertexArray.h b/Common/VertexArray.h
index 0bb0f8e56506c502c45c012f27ffd42430c249a0..73ebef79886ddede8375b68abad019e62d3e8c4a 100644
--- a/Common/VertexArray.h
+++ b/Common/VertexArray.h
@@ -11,6 +11,12 @@
 #include "SVector3.h"
 #include "SBoundingBox3d.h"
 
+#if defined(HAVE_VISUDEV)
+typedef float normal_type;
+#else
+typedef char normal_type;
+#endif
+
 class MElement;
 
 template<int N>
@@ -138,7 +144,7 @@ class VertexArray{
  private:
   int _numVerticesPerElement;
   std::vector<float> _vertices;
-  std::vector<char> _normals;
+  std::vector<normal_type> _normals;
   std::vector<unsigned char> _colors;
   std::vector<MElement*> _elements;
   std::set<ElementData<3>, ElementDataLessThan<3> > _data3;
@@ -168,9 +174,9 @@ class VertexArray{
   std::vector<float>::iterator lastVertex(){return _vertices.end();}
 
   // return a pointer to the raw normal array
-  char *getNormalArray(int i=0){ return &_normals[i]; }
-  std::vector<char>::iterator firstNormal(){return _normals.begin();}
-  std::vector<char>::iterator lastNormal(){return _normals.end();}
+  normal_type *getNormalArray(int i=0){ return &_normals[i]; }
+  std::vector<normal_type>::iterator firstNormal(){return _normals.begin();}
+  std::vector<normal_type>::iterator lastNormal(){return _normals.end();}
 
   // return a pointer to the raw color array
   unsigned char *getColorArray(int i=0){ return &_colors[i]; }
diff --git a/Fltk/contextWindow.cpp b/Fltk/contextWindow.cpp
index 0530366e2faa1015b7a26f539d84f3cca5392178..c583198b91b4e22b2078235b2daafad283ba992e 100644
--- a/Fltk/contextWindow.cpp
+++ b/Fltk/contextWindow.cpp
@@ -82,7 +82,7 @@ static void draw_stl(std::vector<SPoint3> &vertices, std::vector<SVector3> &norm
 
   glVertexPointer(3, GL_FLOAT, 0, va.getVertexArray());
   glEnableClientState(GL_VERTEX_ARRAY);
-  glNormalPointer(GL_BYTE, 0, va.getNormalArray());
+  glNormalPointer(NORMAL_GLTYPE, 0, va.getNormalArray());
   glEnableClientState(GL_NORMAL_ARRAY);
   glDisableClientState(GL_COLOR_ARRAY);
   glDrawArrays(GL_TRIANGLES, 0, va.getNumVertices());
diff --git a/Fltk/optionWindow.cpp b/Fltk/optionWindow.cpp
index 7c0d6e920567ad62e2adab546f0cd5caad74419a..7de8a0610c2eb6b91eb0f447b82e9e2f20b28dfd 100644
--- a/Fltk/optionWindow.cpp
+++ b/Fltk/optionWindow.cpp
@@ -296,6 +296,9 @@ static void general_options_ok_cb(Fl_Widget *w, void *data)
                  (CTX::instance()->homeDir + CTX::instance()->sessionFileName).c_str());
   opt_general_options_save(0, GMSH_SET, o->general.butt[9]->value());
   opt_general_expert_mode(0, GMSH_SET, o->general.butt[10]->value());
+#if defined(HAVE_VISUDEV)
+  opt_general_heavy_visualization(0, GMSH_SET, o->general.butt[22]->value());
+#endif
 
   if(opt_general_gui_color_scheme(0, GMSH_GET, 0) != o->general.butt[21]->value()){
     opt_general_gui_color_scheme(0, GMSH_SET, o->general.butt[21]->value());
@@ -1475,12 +1478,19 @@ optionWindow::optionWindow(int deltaFontSize)
       general.butt[9]->type(FL_TOGGLE_BUTTON);
       general.butt[9]->callback(general_options_ok_cb);
 
+#if defined(HAVE_VISUDEV)
+      general.butt[22] = new Fl_Check_Button
+        (L + 2 * WB, 2 * WB + 8 * BH, BW/2-WB, BH, "Enable heavy visualization capabilities");
+      general.butt[22]->type(FL_TOGGLE_BUTTON);
+      general.butt[22]->callback(general_options_ok_cb);
+#endif
+
       Fl_Button *b1 = new Fl_Button
         (L + width - 2 * WB - BW/3, 2 * WB + 7 * BH, BW/3, BH, "Show file path");
       b1->callback(options_show_file_cb, (void*)"option");
 
       Fl_Button *b2 = new Fl_Button
-        (L + 2 * WB, 2 * WB + 9 * BH, BW, BH, "Restore all options to default settings");
+        (L + 2 * WB, 2 * WB + 10 * BH, BW, BH, "Restore all options to default settings");
       b2->callback(options_restore_defaults_cb);
       if(CTX::instance()->guiColorScheme)
         b2->color(FL_DARK_RED);
diff --git a/Fltk/optionWindow.h b/Fltk/optionWindow.h
index f00cbfada2424c4487ae74814b49275b402631fa..9119d8808b60fc4213ad8ae2dedd8fc8cc21f2ca 100644
--- a/Fltk/optionWindow.h
+++ b/Fltk/optionWindow.h
@@ -33,7 +33,11 @@ class optionWindow{
 
   struct{
     Fl_Group *group;
+#if defined(HAVE_VISUDEV)
+    Fl_Check_Button *butt[23];
+#else
     Fl_Check_Button *butt[22];
+#endif
     Fl_Button *push[20];
     Fl_Value_Input *value[50];
     Fl_Button *color[50];
diff --git a/Geo/MElement.cpp b/Geo/MElement.cpp
index 4914775dd8b4b36cbc797055e4c4ae0f1564349f..50e4f519c9edd127ce0f2fdd49ef3036380c7673 100644
--- a/Geo/MElement.cpp
+++ b/Geo/MElement.cpp
@@ -77,6 +77,21 @@ void MElement::_getEdgeRep(MVertex *v0, MVertex *v1,
   }
 }
 
+#if defined(HAVE_VISUDEV)
+void MElement::_getFaceRepQuad(MVertex *v0, MVertex *v1, MVertex *v2, MVertex *v3,
+                               double *x, double *y, double *z, SVector3 *n)
+{
+  x[0] = v0->x(); x[1] = v1->x(); x[2] = (x[0]+x[1]+v2->x()+v3->x())/4;
+  y[0] = v0->y(); y[1] = v1->y(); y[2] = (y[0]+y[1]+v2->y()+v3->y())/4;
+  z[0] = v0->z(); z[1] = v1->z(); z[2] = (z[0]+z[1]+v2->z()+v3->z())/4;;
+  SVector3 t1(x[1] - x[0], y[1] - y[0], z[1] - z[0]);
+  SVector3 t2(x[2] - x[0], y[2] - y[0], z[2] - z[0]);
+  SVector3 normal = crossprod(t1, t2);
+  normal.normalize();
+  for(int i = 0; i < 3; i++) n[i] = normal;
+}
+#endif
+
 void MElement::_getFaceRep(MVertex *v0, MVertex *v1, MVertex *v2,
                            double *x, double *y, double *z, SVector3 *n)
 {
diff --git a/Geo/MElement.h b/Geo/MElement.h
index cf86a181b4c360fc157a8623725ac20c5c056599..f9e20c25ce9964a0b6524f4f87c4f5da4f082199 100644
--- a/Geo/MElement.h
+++ b/Geo/MElement.h
@@ -43,6 +43,10 @@ class MElement
                    int faceIndex=-1);
   void _getFaceRep(MVertex *v0, MVertex *v1, MVertex *v2,
                    double *x, double *y, double *z, SVector3 *n);
+#if defined(HAVE_VISUDEV)
+  void _getFaceRepQuad(MVertex *v0, MVertex *v1, MVertex *v2, MVertex *v3,
+                       double *x, double *y, double *z, SVector3 *n);
+#endif
  public :
   MElement(int num=0, int part=0);
   virtual ~MElement(){}
diff --git a/Geo/MHexahedron.cpp b/Geo/MHexahedron.cpp
index 27fa10fb212d19a6f0e508e349e661d55de9d17a..3f73d503eef00f37e87341480415f9dadd791984 100644
--- a/Geo/MHexahedron.cpp
+++ b/Geo/MHexahedron.cpp
@@ -370,6 +370,39 @@ void _myGetFaceRep(MHexahedron *hex, int num, double *x, double *y, double *z,
   n[2] = n[0];
 }
 
+void MHexahedron::getFaceRep(bool curved, int num,
+                             double *x, double *y, double *z, SVector3 *n)
+{
+#if defined(HAVE_VISUDEV)
+  static const int fquad[24][4] = {
+      {0, 3, 2, 1}, {3, 2, 1, 0}, {2, 1, 0, 3}, {1, 0, 3, 2},
+      {0, 1, 5, 4}, {1, 5, 4, 0}, {5, 4, 0, 1}, {4, 0, 1, 5},
+      {0, 4, 7, 3}, {4, 7, 3, 0}, {7, 3, 0, 4}, {3, 0, 4, 7},
+      {1, 2, 6, 5}, {2, 6, 5, 1}, {6, 5, 1, 2}, {5, 1, 2, 6},
+      {2, 3, 7, 6}, {3, 7, 6, 2}, {7, 6, 2, 3}, {6, 2, 3, 7},
+      {4, 5, 6, 7}, {5, 6, 7, 4}, {6, 7, 4, 5}, {7, 4, 5, 6}
+  };
+  if (CTX::instance()->heavyVisu) {
+    if (CTX::instance()->mesh.numSubEdges > 1) {
+      _myGetFaceRep(this, num, x, y, z, n, CTX::instance()->mesh.numSubEdges);
+      return;
+    }
+    _getFaceRepQuad(getVertex(fquad[num][0]), getVertex(fquad[num][1]),
+                    getVertex(fquad[num][2]), getVertex(fquad[num][3]),
+                    x, y, z, n);
+    return;
+  }
+#endif
+  static const int f[12][3] = {
+    {0, 3, 2}, {0, 2, 1},
+    {0, 1, 5}, {0, 5, 4},
+    {0, 4, 7}, {0, 7, 3},
+    {1, 2, 6}, {1, 6, 5},
+    {2, 3, 7}, {2, 7, 6},
+    {4, 5, 6}, {4, 6, 7}
+  };
+  _getFaceRep(_v[f[num][0]], _v[f[num][1]], _v[f[num][2]], x, y, z, n);
+}
 
 void MHexahedron20::getFaceRep(bool curved, int num,
                                double *x, double *y, double *z, SVector3 *n)
@@ -392,13 +425,23 @@ void MHexahedronN::getFaceRep(bool curved, int num,
   else MHexahedron::getFaceRep(false, num, x, y, z, n);
 }
 
+int MHexahedron::getNumFacesRep(bool curved)
+{
+#if defined(HAVE_VISUDEV)
+  if (CTX::instance()->heavyVisu) {
+    if (CTX::instance()->mesh.numSubEdges == 1) return 24;
+    return 12 * gmsh_SQU(CTX::instance()->mesh.numSubEdges);
+  }
+#endif
+  return 12;
+}
+
 int MHexahedron20::getNumFacesRep(bool curved)
 {
   return curved ? 6 * (CTX::instance()->mesh.numSubEdges *
                        CTX::instance()->mesh.numSubEdges * 2) : 12;
 }
 
-
 int MHexahedron27::getNumFacesRep(bool curved)
 {
   return curved ? 6 * (CTX::instance()->mesh.numSubEdges *
diff --git a/Geo/MHexahedron.h b/Geo/MHexahedron.h
index ba874743441510d1c514e54555af6fd464da08d6..d65e80ad108d387ccb6bad14c156051c3aba053d 100644
--- a/Geo/MHexahedron.h
+++ b/Geo/MHexahedron.h
@@ -87,19 +87,8 @@ class MHexahedron : public MElement {
   virtual double getInnerRadius();
   virtual double angleShapeMeasure();
   virtual void getFaceInfo(const MFace & face, int &ithFace, int &sign, int &rot) const;
-  virtual int getNumFacesRep(bool curved){ return 12; }
-  virtual void getFaceRep(bool curved, int num, double *x, double *y, double *z, SVector3 *n)
-  {
-    static const int f[12][3] = {
-      {0, 3, 2}, {0, 2, 1},
-      {0, 1, 5}, {0, 5, 4},
-      {0, 4, 7}, {0, 7, 3},
-      {1, 2, 6}, {1, 6, 5},
-      {2, 3, 7}, {2, 7, 6},
-      {4, 5, 6}, {4, 6, 7}
-    };
-    _getFaceRep(_v[f[num][0]], _v[f[num][1]], _v[f[num][2]], x, y, z, n);
-  }
+  virtual int getNumFacesRep(bool curved);
+  virtual void getFaceRep(bool curved, int num, double *x, double *y, double *z, SVector3 *n);
   virtual void getFaceVertices(const int num, std::vector<MVertex*> &v) const
   {
     v.resize(4);
diff --git a/Geo/MPrism.cpp b/Geo/MPrism.cpp
index 4fecdf8d752e9bd7659fbc3d97dcf34f7fa8e20a..caa99c36c6889dfa1d7463fa7605052a222a686e 100644
--- a/Geo/MPrism.cpp
+++ b/Geo/MPrism.cpp
@@ -428,6 +428,39 @@ static void _myGetFaceRep(MPrism *pri, int num, double *x, double *y, double *z,
   n[2] = n[0];
 }
 
+void MPrism::getFaceRep(bool curved, int num,
+                        double *x, double *y, double *z, SVector3 *n)
+{
+#if defined(HAVE_VISUDEV)
+  static const int fquad[12][4] = {
+      {0, 1, 4, 3}, {1, 4, 3, 0}, {4, 3, 0, 1}, {3, 0, 1, 4},
+      {1, 2, 5, 4}, {2, 5, 4, 1}, {5, 4, 1, 2}, {4, 1, 2, 5},
+      {2, 0, 3, 5}, {0, 3, 5, 2}, {3, 5, 2, 0}, {5, 2, 0, 3}
+  };
+  if (CTX::instance()->heavyVisu) {
+    if (CTX::instance()->mesh.numSubEdges > 1) {
+      _myGetFaceRep(this, num, x, y, z, n, CTX::instance()->mesh.numSubEdges);
+      return;
+    }
+    if (num > 1) {
+      int i = num - 2;
+      _getFaceRepQuad(getVertex(fquad[i][0]), getVertex(fquad[i][1]),
+                      getVertex(fquad[i][2]), getVertex(fquad[i][3]),
+                      x, y, z, n);
+      return;
+    }
+  }
+#endif
+  static const int f[8][3] = {
+      {0, 2, 1},
+      {3, 4, 5},
+      {0, 1, 4}, {0, 4, 3},
+      {0, 3, 5}, {0, 5, 2},
+      {1, 2, 5}, {1, 5, 4}
+  };
+  _getFaceRep(_v[f[num][0]], _v[f[num][1]], _v[f[num][2]], x, y, z, n);
+}
+
 void MPrism15::getFaceRep(bool curved, int num,
                           double *x, double *y, double *z, SVector3 *n)
 {
@@ -449,6 +482,18 @@ void MPrismN::getFaceRep(bool curved, int num,
   else MPrism::getFaceRep(false, num, x, y, z, n);
 }
 
+int MPrism::getNumFacesRep(bool curved)
+{
+#if defined(HAVE_VISUDEV)
+  if (CTX::instance()->heavyVisu) {
+    if (CTX::instance()->mesh.numSubEdges == 1) return 14;
+    return 8 * gmsh_SQU(CTX::instance()->mesh.numSubEdges);
+  }
+  if (CTX::instance()->heavyVisu) return 14;
+#endif
+  return 8;
+}
+
 int MPrism15::getNumFacesRep(bool curved)
 {
   return curved ? 4 * (CTX::instance()->mesh.numSubEdges *
diff --git a/Geo/MPrism.h b/Geo/MPrism.h
index bfbde23d5f91855236ff49859fce46ff2cf96a9c..68dbd947094a278c1800cf41cfd2b9600cf0d2b3 100644
--- a/Geo/MPrism.h
+++ b/Geo/MPrism.h
@@ -92,18 +92,8 @@ class MPrism : public MElement {
                    _v[faces_prism(num, 2)],
                    _v[faces_prism(num, 3)]);
   }
-  virtual int getNumFacesRep(bool curved){ return 8; }
-  virtual void getFaceRep(bool curved, int num, double *x, double *y, double *z, SVector3 *n)
-  {
-    static const int f[8][3] = {
-      {0, 2, 1},
-      {3, 4, 5},
-      {0, 1, 4}, {0, 4, 3},
-      {0, 3, 5}, {0, 5, 2},
-      {1, 2, 5}, {1, 5, 4}
-    };
-    _getFaceRep(_v[f[num][0]], _v[f[num][1]], _v[f[num][2]], x, y, z, n);
-  }
+  virtual int getNumFacesRep(bool curved);
+  virtual void getFaceRep(bool curved, int num, double *x, double *y, double *z, SVector3 *n);
   virtual void getFaceVertices(const int num, std::vector<MVertex*> &v) const
   {
     v.resize((num < 2) ? 3 : 4);
diff --git a/Geo/MPyramid.cpp b/Geo/MPyramid.cpp
index 6679dc8111644df62ab7d32ba374ab75fdffb419..457a7f952a21aa7e4e333f5e8523f026331035e9 100644
--- a/Geo/MPyramid.cpp
+++ b/Geo/MPyramid.cpp
@@ -82,6 +82,16 @@ void MPyramidN::getEdgeRep(bool curved, int num,
   else MPyramid::getEdgeRep(false, num, x, y, z, n);
 }
 
+int MPyramid::getNumFacesRep(bool curved)
+{
+#if defined(HAVE_VISUDEV)
+  if (CTX::instance()->heavyVisu) {
+    if (CTX::instance()->mesh.numSubEdges == 1) return 8;
+    return 6 * gmsh_SQU(CTX::instance()->mesh.numSubEdges);
+  }
+#endif
+  return 6;
+}
 
 int MPyramidN::getNumFacesRep(bool curved)
 {
@@ -121,6 +131,8 @@ static void _myGetFaceRep(MPyramid *pyr, int num, double *x, double *y, double *
     iVertex4 = 3;
   }
 
+  SPoint3 pnt1, pnt2, pnt3;
+
   if (iFace < 4) {
 
     int ix = 0, iy = 0;
@@ -137,7 +149,6 @@ static void _myGetFaceRep(MPyramid *pyr, int num, double *x, double *y, double *
 
     const double d = 1. / numSubEdges;
 
-    SPoint3 pnt1, pnt2, pnt3;
     double u1, v1, u2, v2, u3, v3;
     if (ix % 2 == 0){
       u1 = ix / 2 * d; v1= iy*d;
@@ -165,21 +176,8 @@ static void _myGetFaceRep(MPyramid *pyr, int num, double *x, double *y, double *
     pyr->pnt(U1, V1, W1, pnt1);
     pyr->pnt(U2, V2, W2, pnt2);
     pyr->pnt(U3, V3, W3, pnt3);
-
-    x[0] = pnt1.x(); x[1] = pnt2.x(); x[2] = pnt3.x();
-    y[0] = pnt1.y(); y[1] = pnt2.y(); y[2] = pnt3.y();
-    z[0] = pnt1.z(); z[1] = pnt2.z(); z[2] = pnt3.z();
-
-    SVector3 d1(x[1] - x[0], y[1] - y[0], z[1] - z[0]);
-    SVector3 d2(x[2] - x[0], y[2] - y[0], z[2] - z[0]);
-    n[0] = crossprod(d1, d2);
-    n[0].normalize();
-    n[1] = n[0];
-    n[2] = n[0];
-
   }
   else {
-    SPoint3 pnt1, pnt2, pnt3;
 
     /*
     0
@@ -316,14 +314,50 @@ static void _myGetFaceRep(MPyramid *pyr, int num, double *x, double *y, double *
     pyr->pnt(U2,V2,W2, pnt2);
     pyr->pnt(U3,V3,W3, pnt3);
     }
+  }
 
-    n[0] = 1;
-    n[1] = 1;
-    n[2] = 1;
-    x[0] = pnt1.x(); x[1] = pnt2.x(); x[2] = pnt3.x();
-    y[0] = pnt1.y(); y[1] = pnt2.y(); y[2] = pnt3.y();
-    z[0] = pnt1.z(); z[1] = pnt2.z(); z[2] = pnt3.z();
+  x[0] = pnt1.x(); x[1] = pnt2.x(); x[2] = pnt3.x();
+  y[0] = pnt1.y(); y[1] = pnt2.y(); y[2] = pnt3.y();
+  z[0] = pnt1.z(); z[1] = pnt2.z(); z[2] = pnt3.z();
+
+  SVector3 d1(x[1] - x[0], y[1] - y[0], z[1] - z[0]);
+  SVector3 d2(x[2] - x[0], y[2] - y[0], z[2] - z[0]);
+  n[0] = crossprod(d1, d2);
+  n[0].normalize();
+  n[1] = n[0];
+  n[2] = n[0];
+}
+
+void MPyramid::getFaceRep(bool curved, int num,
+                          double *x, double *y, double *z, SVector3 *n)
+{
+#if defined(HAVE_VISUDEV)
+  static const int fquad[4][4] = {
+      {0, 3, 2, 1}, {3, 2, 1, 0}, {2, 1, 0, 3}, {1, 0, 3, 2}
+  };
+  if (CTX::instance()->heavyVisu) {
+    if (CTX::instance()->mesh.numSubEdges > 1) {
+      _myGetFaceRep(this, num, x, y, z, n, CTX::instance()->mesh.numSubEdges);
+      return;
+    }
+    if (num > 3) {
+      int i = num - 4;
+      _getFaceRepQuad(getVertex(fquad[i][0]), getVertex(fquad[i][1]),
+                      getVertex(fquad[i][2]), getVertex(fquad[i][3]),
+                      x, y, z, n);
+      return;
+    }
   }
+#endif
+  static const int f[6][3] = {
+      {0, 1, 4},
+      {3, 0, 4},
+      {1, 2, 4},
+      {2, 3, 4},
+      {0, 3, 2}, {0, 2, 1}
+  };
+  _getFaceRep(getVertex(f[num][0]), getVertex(f[num][1]), getVertex(f[num][2]),
+              x, y, z, n);
 }
 
 void MPyramidN::getFaceRep(bool curved, int num,
diff --git a/Geo/MPyramid.h b/Geo/MPyramid.h
index 3bfe80a329da5966e1172e7cc5ea4de2663a76f0..1a0a7f55bc45281d36e2955f130d21de87d3e20f 100644
--- a/Geo/MPyramid.h
+++ b/Geo/MPyramid.h
@@ -97,20 +97,9 @@ class MPyramid : public MElement {
     else
       return MFace(_v[0], _v[3], _v[2], _v[1]);
   }
-  virtual int getNumFacesRep(bool curved){ return 6; }
+  virtual int getNumFacesRep(bool curved);
   virtual void getFaceRep(bool curved, int num, double *x, double *y, double *z,
-                          SVector3 *n)
-  {
-    static const int f[6][3] = {
-      {0, 1, 4},
-      {3, 0, 4},
-      {1, 2, 4},
-      {2, 3, 4},
-      {0, 3, 2}, {0, 2, 1}
-    };
-    _getFaceRep(getVertex(f[num][0]), getVertex(f[num][1]), getVertex(f[num][2]),
-                x, y, z, n);
-  }
+                          SVector3 *n);
   virtual void getFaceVertices(const int num, std::vector<MVertex*> &v) const
   {
     v.resize((num < 4) ? 3 : 4);
diff --git a/Geo/MQuadrangle.cpp b/Geo/MQuadrangle.cpp
index e3c56f5144d0c984e5ef899a6cddc6b0d8f00d2a..9a2d1f07239b51fab31cc5eb0ffcb46e434ef283 100644
--- a/Geo/MQuadrangle.cpp
+++ b/Geo/MQuadrangle.cpp
@@ -124,6 +124,17 @@ void MQuadrangle9::getEdgeRep(bool curved, int num,
   else MQuadrangle::getEdgeRep(false, num, x, y, z, n);
 }
 
+int MQuadrangle::getNumFacesRep(bool curved)
+{
+#if defined(HAVE_VISUDEV)
+  if (CTX::instance()->heavyVisu) {
+    if (CTX::instance()->mesh.numSubEdges == 1) return 4;
+    return 2 * gmsh_SQU(CTX::instance()->mesh.numSubEdges);
+  }
+#endif
+  return 2;
+}
+
 int MQuadrangleN::getNumFacesRep(bool curved)
 {
   return curved ? 2*SQU(CTX::instance()->mesh.numSubEdges) : 2;
@@ -191,6 +202,30 @@ static void _myGetFaceRep(MQuadrangle *t, int num, double *x, double *y, double
   z[0] = pnt1.z(); z[1] = pnt2.z(); z[2] = pnt3.z();
 }
 
+void MQuadrangle::getFaceRep(bool curved, int num,
+                             double *x, double *y, double *z, SVector3 *n)
+{
+#if defined(HAVE_VISUDEV)
+  static const int fquad[4][4] = {
+      {0, 1, 2, 3}, {1, 2, 3, 0}, {2, 3, 0, 1}, {3, 0, 1, 2}
+  };
+  if (CTX::instance()->heavyVisu) {
+    if (CTX::instance()->mesh.numSubEdges > 1) {
+      _myGetFaceRep(this, num, x, y, z, n, CTX::instance()->mesh.numSubEdges);
+      return;
+    }
+    _getFaceRepQuad(getVertex(fquad[num][0]), getVertex(fquad[num][1]),
+                    getVertex(fquad[num][2]), getVertex(fquad[num][3]),
+                    x, y, z, n);
+    return;
+  }
+#endif
+  static const int f[2][3] = {
+      {0, 1, 2}, {0, 2, 3}
+  };
+  _getFaceRep(_v[f[num][0]], _v[f[num][1]], _v[f[num][2]], x, y, z, n);
+}
+
 void MQuadrangleN::getFaceRep(bool curved, int num,
                               double *x, double *y, double *z, SVector3 *n)
 {
diff --git a/Geo/MQuadrangle.h b/Geo/MQuadrangle.h
index 15cb09446efdc2fdf675c7d849e84a9403fadfc1..2a4b6ef9854aec94f596f59a411101eedde94ba5 100644
--- a/Geo/MQuadrangle.h
+++ b/Geo/MQuadrangle.h
@@ -91,14 +91,8 @@ class MQuadrangle : public MElement {
   }
   virtual int getNumFaces(){ return 1; }
   virtual MFace getFace(int num){ return MFace(_v[0], _v[1], _v[2], _v[3]); }
-  virtual int getNumFacesRep(bool curved){ return 2; }
-  virtual void getFaceRep(bool curved, int num, double *x, double *y, double *z, SVector3 *n)
-  {
-    static const int f[2][3] = {
-      {0, 1, 2}, {0, 2, 3}
-    };
-    _getFaceRep(_v[f[num][0]], _v[f[num][1]], _v[f[num][2]], x, y, z, n);
-  }
+  virtual int getNumFacesRep(bool curved);
+  virtual void getFaceRep(bool curved, int num, double *x, double *y, double *z, SVector3 *n);
   virtual void getFaceVertices(const int num, std::vector<MVertex*> &v) const
   {
     v.resize(4);
diff --git a/Graphics/drawContext.h b/Graphics/drawContext.h
index 122caf2f61944b0103fd2f3f7e9fd31a05efb668..2e95d0ca541ac8b7a1ced69c210adbb36fe45161 100644
--- a/Graphics/drawContext.h
+++ b/Graphics/drawContext.h
@@ -27,6 +27,12 @@
 #include <GL/glu.h>
 #endif
 
+#if defined(HAVE_VISUDEV)
+#define NORMAL_GLTYPE GL_FLOAT
+#else
+#define NORMAL_GLTYPE GL_BYTE
+#endif
+
 class PView;
 class GModel;
 class GVertex;
diff --git a/Graphics/drawGeom.cpp b/Graphics/drawGeom.cpp
index 59b1eef9c0ee4f8814ce4cbc0f28779ef3772d38..8f65c6bf2d7148e54cd78696cc44051ccca16517 100644
--- a/Graphics/drawGeom.cpp
+++ b/Graphics/drawGeom.cpp
@@ -230,7 +230,7 @@ class drawGFace {
     glEnableClientState(GL_VERTEX_ARRAY);
     if(useNormalArray){
       glEnable(GL_LIGHTING);
-      glNormalPointer(GL_BYTE, 0, va->getNormalArray());
+      glNormalPointer(NORMAL_GLTYPE, 0, va->getNormalArray());
       glEnableClientState(GL_NORMAL_ARRAY);
     }
     else{
diff --git a/Graphics/drawMesh.cpp b/Graphics/drawMesh.cpp
index 41d34f3dd3a2263e9c3c70936c1a61277d63ae58..0fbe91a26fa71ee4cc4e5d2c70bb435d3db51e5f 100644
--- a/Graphics/drawMesh.cpp
+++ b/Graphics/drawMesh.cpp
@@ -359,7 +359,7 @@ static void drawArrays(drawContext *ctx, GEntity *e, VertexArray *va, GLint type
 
   if(useNormalArray){
     glEnable(GL_LIGHTING);
-    glNormalPointer(GL_BYTE, 0, va->getNormalArray());
+    glNormalPointer(NORMAL_GLTYPE, 0, va->getNormalArray());
     glEnableClientState(GL_NORMAL_ARRAY);
   }
   else
diff --git a/Graphics/drawPost.cpp b/Graphics/drawPost.cpp
index 9c960352cceaca4f6ce003ad7903b5c2c7d2caaa..fa62dc231d3ddd9a5d5d54bc8e3052dc02e5059d 100644
--- a/Graphics/drawPost.cpp
+++ b/Graphics/drawPost.cpp
@@ -39,8 +39,12 @@ static void drawArrays(drawContext *ctx, PView *p, VertexArray *va, GLint type,
       glColor4ubv((GLubyte *)va->getColorArray(4 * i));
       double f = 1.;
       if(opt->pointType > 1){
+#if defined(HAVE_VISUDEV)
+        f = *va->getNormalArray(3 * i);
+#else
         char *n = va->getNormalArray(3 * i);
         f = char2float(*n);
+#endif
       }
       if(opt->pointType == 2){
         int s = (int)(opt->pointSize * f);
@@ -62,26 +66,36 @@ static void drawArrays(drawContext *ctx, PView *p, VertexArray *va, GLint type,
       float *p1 = va->getVertexArray(3 * (i + 1));
       double x[2] = {p0[0], p1[0]}, y[2] = {p0[1], p1[1]}, z[2] = {p0[2], p1[2]};
       glColor4ubv((GLubyte *)va->getColorArray(4 * i));
-      if(opt->lineType == 2){
+      if (opt->lineType == 2){
+#if defined(HAVE_VISUDEV)
+        double v0 = *va->getNormalArray(3 * i);
+        double v1 = *va->getNormalArray(3 * (i + 1));
+#else
         char *n0 = va->getNormalArray(3 * i);
         char *n1 = va->getNormalArray(3 * (i + 1));
         double v0 = char2float(*n0), v1 = char2float(*n1);
+#endif
         ctx->drawTaperedCylinder(opt->lineWidth, v0, v1, 0., 1., x, y, z, opt->light);
       }
       else if (opt->lineType == 1)
         ctx->drawCylinder(opt->lineWidth, x, y, z, opt->light);
       else { // 2D (for now) MNT diagrams for frames
-	float l = sqrt ((p0[0] - p1[0]) * (p0[0] - p1[0]) +
+        float l = sqrt ((p0[0] - p1[0]) * (p0[0] - p1[0]) +
                         (p0[1] - p1[1]) * (p0[1] - p1[1]) +
                         (p0[2] - p1[2]) * (p0[2] - p1[2]) );
+#if defined(HAVE_VISUDEV)
+        double v0 = *va->getNormalArray(3 * i);
+        double v1 = *va->getNormalArray(3 * (i + 1));
+#else
         char *n0 = va->getNormalArray(3 * i);
         char *n1 = va->getNormalArray(3 * (i + 1));
         double v0 = char2float(*n0), v1 = char2float(*n1);
-	float dir [3] = {(p1[0] - p0[0]) / l , (p1[1] - p0[1]) / l , (p1[2] - p0[2]) / l};
-	printf("%g %g %g %g %g %g\n", v0, v1, p0[0], p0[1], p1[0], p1[1]);
-	ctx->drawVector(1, 0,
-			p0[0] - dir[1] * v0 , p0[1] + dir[0] * v0 , 0.0,
-			p1[0] - dir[1] * v1 , p1[1] + dir[0] * v1 , 0.0,opt->light);
+#endif
+        float dir [3] = {(p1[0] - p0[0]) / l , (p1[1] - p0[1]) / l , (p1[2] - p0[2]) / l};
+        printf("%g %g %g %g %g %g\n", v0, v1, p0[0], p0[1], p1[0], p1[1]);
+        ctx->drawVector(1, 0,
+                        p0[0] - dir[1] * v0 , p0[1] + dir[0] * v0 , 0.0,
+                        p1[0] - dir[1] * v1 , p1[1] + dir[0] * v1 , 0.0,opt->light);
       }
     }
   }
@@ -90,7 +104,7 @@ static void drawArrays(drawContext *ctx, PView *p, VertexArray *va, GLint type,
     glEnableClientState(GL_VERTEX_ARRAY);
     if(useNormalArray){
       glEnable(GL_LIGHTING);
-      glNormalPointer(GL_BYTE, 0, va->getNormalArray());
+      glNormalPointer(NORMAL_GLTYPE, 0, va->getNormalArray());
       glEnableClientState(GL_NORMAL_ARRAY);
     }
     else