changeset 22331:b81b08cc4c83

maint: Indent namespaces in more files.
author John W. Eaton <jwe@octave.org>
date Wed, 17 Aug 2016 11:43:27 -0400
parents 53e246fd8124
children 1d85005fc6b7
files libinterp/corefcn/base-text-renderer.h libinterp/corefcn/ft-text-renderer.cc libinterp/corefcn/gl-render.cc libinterp/corefcn/gl-render.h libinterp/corefcn/gl2ps-print.cc libinterp/corefcn/text-renderer.cc libinterp/corefcn/text-renderer.h libinterp/octave-value/ov-java.cc
diffstat 8 files changed, 5652 insertions(+), 5670 deletions(-) [+]
line wrap: on
line diff
--- a/libinterp/corefcn/base-text-renderer.h	Wed Aug 17 08:20:26 2016 -0700
+++ b/libinterp/corefcn/base-text-renderer.h	Wed Aug 17 11:43:27 2016 -0400
@@ -37,50 +37,48 @@
 
 namespace octave
 {
+  class
+  base_text_renderer : public text_processor
+  {
+  public:
 
-class
-base_text_renderer : public text_processor
-{
-public:
+    base_text_renderer (void) : text_processor () { }
 
-  base_text_renderer (void) : text_processor () { }
-
-  virtual ~base_text_renderer (void) { }
+    virtual ~base_text_renderer (void) { }
 
-  virtual Matrix
-  get_extent (text_element *elt, double rotation) = 0;
+    virtual Matrix
+    get_extent (text_element *elt, double rotation) = 0;
 
-  virtual Matrix
-  get_extent (const std::string& txt, double rotation,
-              const caseless_str& interpreter) = 0;
+    virtual Matrix
+    get_extent (const std::string& txt, double rotation,
+                const caseless_str& interpreter) = 0;
 
-  virtual void
-  set_font (const std::string& name, const std::string& weight,
-            const std::string& angle, double size) = 0;
+    virtual void
+    set_font (const std::string& name, const std::string& weight,
+              const std::string& angle, double size) = 0;
 
-  virtual void set_color (const Matrix& c) = 0;
+    virtual void set_color (const Matrix& c) = 0;
 
-  virtual void
-  text_to_pixels (const std::string& txt, uint8NDArray& pxls,
-                  Matrix& bbox, int halign, int valign, double rotation,
-                  const caseless_str& interpreter,
-                  bool handle_rotation) = 0;
+    virtual void
+    text_to_pixels (const std::string& txt, uint8NDArray& pxls,
+                    Matrix& bbox, int halign, int valign, double rotation,
+                    const caseless_str& interpreter,
+                    bool handle_rotation) = 0;
 
-  virtual void
-  text_to_strlist (const std::string& txt,
-                   std::list<text_renderer::string>& lst,
-                   Matrix& box, int halign, int valign, double rotation,
-                   const caseless_str& interpreter = "tex") = 0;
-
-private:
+    virtual void
+    text_to_strlist (const std::string& txt,
+                     std::list<text_renderer::string>& lst,
+                     Matrix& box, int halign, int valign, double rotation,
+                     const caseless_str& interpreter = "tex") = 0;
 
-  // No copying!
+  private:
 
-  base_text_renderer (const base_text_renderer&);
+    // No copying!
 
-  base_text_renderer& operator = (const base_text_renderer&);
-};
+    base_text_renderer (const base_text_renderer&);
 
+    base_text_renderer& operator = (const base_text_renderer&);
+  };
 }
 
 #endif
--- a/libinterp/corefcn/ft-text-renderer.cc	Wed Aug 17 08:20:26 2016 -0700
+++ b/libinterp/corefcn/ft-text-renderer.cc	Wed Aug 17 11:43:27 2016 -0400
@@ -89,7 +89,6 @@
 
 namespace octave
 {
-
 class
 ft_manager
 {
@@ -324,1053 +323,1051 @@
 
 namespace octave
 {
-
-class
-OCTINTERP_API
-ft_text_renderer : public base_text_renderer
-{
-public:
-
-  enum
-  {
-    MODE_BBOX   = 0,
-    MODE_RENDER = 1
-  };
-
-  enum
-  {
-    ROTATION_0   = 0,
-    ROTATION_90  = 1,
-    ROTATION_180 = 2,
-    ROTATION_270 = 3
-  };
-
-public:
-
-  ft_text_renderer (void)
-    : base_text_renderer (), font (), bbox (1, 4, 0.0), halign (0),
-      xoffset (0), line_yoffset (0), yoffset (0), mode (MODE_BBOX),
-      color (dim_vector (1, 3), 0)
-  { }
-
-  ~ft_text_renderer (void) { }
-
-  void visit (text_element_string& e);
-
-  void visit (text_element_list& e);
-
-  void visit (text_element_subscript& e);
-
-  void visit (text_element_superscript& e);
-
-  void visit (text_element_color& e);
-
-  void visit (text_element_fontsize& e);
-
-  void visit (text_element_fontname& e);
-
-  void visit (text_element_fontstyle& e);
-
-  void visit (text_element_symbol& e);
-
-  void visit (text_element_combined& e);
-
-  void reset (void);
-
-  uint8NDArray get_pixels (void) const { return pixels; }
-
-  Matrix get_boundingbox (void) const { return bbox; }
-
-  uint8NDArray render (text_element *elt, Matrix& box,
-                       int rotation = ROTATION_0);
-
-  Matrix get_extent (text_element *elt, double rotation = 0.0);
-  Matrix get_extent (const std::string& txt, double rotation,
-                     const caseless_str& interpreter);
-
-  void set_font (const std::string& name, const std::string& weight,
-                 const std::string& angle, double size);
-
-  void set_color (const Matrix& c);
-
-  void set_mode (int m);
-
-  void text_to_pixels (const std::string& txt,
-                       uint8NDArray& pxls, Matrix& bbox,
-                       int halign, int valign, double rotation,
-                       const caseless_str& interpreter,
-                       bool handle_rotation);
-
-private:
-
-  int rotation_to_mode (double rotation) const;
-
-  // No copying!
-
-  ft_text_renderer (const ft_text_renderer&);
-
-  ft_text_renderer& operator = (const ft_text_renderer&);
-
-  // Class to hold information about fonts and a strong
-  // reference to the font objects loaded by FreeType.
-
-  class ft_font : public text_renderer::font
+  class
+  OCTINTERP_API
+  ft_text_renderer : public base_text_renderer
   {
   public:
 
-    ft_font (void)
-      : text_renderer::font (), face (0) { }
+    enum
+    {
+      MODE_BBOX   = 0,
+      MODE_RENDER = 1
+    };
+
+    enum
+    {
+      ROTATION_0   = 0,
+      ROTATION_90  = 1,
+      ROTATION_180 = 2,
+      ROTATION_270 = 3
+    };
+
+  public:
+
+    ft_text_renderer (void)
+      : base_text_renderer (), font (), bbox (1, 4, 0.0), halign (0),
+      xoffset (0), line_yoffset (0), yoffset (0), mode (MODE_BBOX),
+      color (dim_vector (1, 3), 0)
+        { }
+
+    ~ft_text_renderer (void) { }
+
+    void visit (text_element_string& e);
+
+    void visit (text_element_list& e);
+
+    void visit (text_element_subscript& e);
+
+    void visit (text_element_superscript& e);
 
-    ft_font (const std::string& nm, const std::string& wt,
-             const std::string& ang, double sz, FT_Face f = 0)
-      : text_renderer::font (nm, wt, ang, sz), face (f)
-    { }
+    void visit (text_element_color& e);
+
+    void visit (text_element_fontsize& e);
+
+    void visit (text_element_fontname& e);
+
+    void visit (text_element_fontstyle& e);
+
+    void visit (text_element_symbol& e);
+
+    void visit (text_element_combined& e);
+
+    void reset (void);
+
+    uint8NDArray get_pixels (void) const { return pixels; }
 
-    ft_font (const ft_font& ft);
+    Matrix get_boundingbox (void) const { return bbox; }
+
+    uint8NDArray render (text_element *elt, Matrix& box,
+                         int rotation = ROTATION_0);
+
+    Matrix get_extent (text_element *elt, double rotation = 0.0);
+    Matrix get_extent (const std::string& txt, double rotation,
+                       const caseless_str& interpreter);
+
+    void set_font (const std::string& name, const std::string& weight,
+                   const std::string& angle, double size);
+
+    void set_color (const Matrix& c);
+
+    void set_mode (int m);
 
-    ~ft_font (void)
+    void text_to_pixels (const std::string& txt,
+                         uint8NDArray& pxls, Matrix& bbox,
+                         int halign, int valign, double rotation,
+                         const caseless_str& interpreter,
+                         bool handle_rotation);
+
+  private:
+
+    int rotation_to_mode (double rotation) const;
+
+    // No copying!
+
+    ft_text_renderer (const ft_text_renderer&);
+
+    ft_text_renderer& operator = (const ft_text_renderer&);
+
+    // Class to hold information about fonts and a strong
+    // reference to the font objects loaded by FreeType.
+
+    class ft_font : public text_renderer::font
     {
-      if (face)
-        FT_Done_Face (face);
-    }
+    public:
+
+      ft_font (void)
+        : text_renderer::font (), face (0) { }
+
+      ft_font (const std::string& nm, const std::string& wt,
+               const std::string& ang, double sz, FT_Face f = 0)
+        : text_renderer::font (nm, wt, ang, sz), face (f)
+      { }
+
+      ft_font (const ft_font& ft);
 
-    ft_font& operator = (const ft_font& ft);
+      ~ft_font (void)
+      {
+        if (face)
+          FT_Done_Face (face);
+      }
+
+      ft_font& operator = (const ft_font& ft);
+
+      bool is_valid (void) const { return get_face (); }
+
+      FT_Face get_face (void) const;
+
+    private:
+
+      mutable FT_Face face;
+    };
 
-    bool is_valid (void) const { return get_face (); }
+    void push_new_line (void);
+
+    void update_line_bbox (void);
+
+    void compute_bbox (void);
+
+    int compute_line_xoffset (const Matrix& lb) const;
 
-    FT_Face get_face (void) const;
+    FT_UInt process_character (FT_ULong code, FT_UInt previous = 0);
+
+  public:
+
+    void text_to_strlist (const std::string& txt,
+                          std::list<text_renderer::string>& lst, Matrix& bbox,
+                          int halign, int valign, double rotation,
+                          const caseless_str& interp);
 
   private:
 
-    mutable FT_Face face;
+    // The current font used by the renderer.
+    ft_font font;
+
+    // Used to stored the bounding box corresponding to the rendered text.
+    // The bounding box has the form [x, y, w, h] where x and y represent the
+    // coordinates of the bottom left corner relative to the anchor point of
+    // the text (== start of text on the baseline).  Due to font descent or
+    // multiple lines, the value y is usually negative.
+    Matrix bbox;
+
+    // Used to stored the rendered text.  It's a 3D matrix with size MxNx4
+    // where M and N are the width and height of the bounding box.
+    uint8NDArray pixels;
+
+    // Used to store the bounding box of each line.  This is used to layout
+    // multiline text properly.
+    std::list<Matrix> line_bbox;
+
+    // The current horizontal alignment.  This is used to align multi-line text.
+    int halign;
+
+    // The X offset for the next glyph.
+    int xoffset;
+
+    // The Y offset of the baseline for the current line.
+    int line_yoffset;
+
+    // The Y offset of the baseline for the next glyph.  The offset is relative
+    // to line_yoffset.  The total Y offset is computed with:
+    // line_yoffset + yoffset.
+    int yoffset;
+
+    // The current mode of the rendering process (box computing or rendering).
+    int mode;
+
+    // The base color of the rendered text.
+    uint8NDArray color;
+
+    // A list of parsed strings to be used for printing.
+    std::list<text_renderer::string> strlist;
+
+    // The X offset of the baseline for the current line.
+    int line_xoffset;
+
   };
 
-  void push_new_line (void);
+  void
+  ft_text_renderer::set_font (const std::string& name, const std::string& weight,
+                              const std::string& angle, double size)
+  {
+    // FIXME: take "fontunits" into account
+
+    font = ft_font (name, weight, angle, size, 0);
+  }
+
+  void
+  ft_text_renderer::push_new_line (void)
+  {
+    switch (mode)
+      {
+      case MODE_BBOX:
+        {
+          // Create a new bbox entry based on the current font.
+
+          FT_Face face = font.get_face ();
 
-  void update_line_bbox (void);
+          if (face)
+            {
+              int asc = face->size->metrics.ascender >> 6;
+              int desc = face->size->metrics.descender >> 6;
+              int h = face->size->metrics.height >> 6;
+
+              Matrix bb (1, 5, 0.0);
+
+              bb(1) = desc;
+              bb(3) = asc - desc;
+              bb(4) = h;
+
+              line_bbox.push_back (bb);
+
+              xoffset = yoffset = 0;
+            }
+        }
+        break;
+
+      case MODE_RENDER:
+        {
+          // Move to the next line bbox, adjust xoffset based on alignment
+          // and yoffset based on the old and new line bbox.
 
-  void compute_bbox (void);
+          Matrix old_bbox = line_bbox.front ();
+          line_bbox.pop_front ();
+          Matrix new_bbox = line_bbox.front ();
+
+          xoffset = line_xoffset = compute_line_xoffset (new_bbox);
+          line_yoffset += (old_bbox(1) - (new_bbox(1) + new_bbox(3)));
+          yoffset = 0;
+        }
+        break;
+      }
+  }
 
-  int compute_line_xoffset (const Matrix& lb) const;
+  int
+  ft_text_renderer::compute_line_xoffset (const Matrix& lb) const
+  {
+    if (! bbox.is_empty ())
+      {
+        switch (halign)
+          {
+          case 0:
+            return 0;
+          case 1:
+            return (bbox(2) - lb(2)) / 2;
+          case 2:
+            return (bbox(2) - lb(2));
+          }
+      }
+
+    return 0;
+  }
+
+  void
+  ft_text_renderer::compute_bbox (void)
+  {
+    // Stack the various line bbox together and compute the final
+    // bounding box for the entire text string.
+
+    bbox = Matrix ();
+
+    switch (line_bbox.size ())
+      {
+      case 0:
+        break;
+
+      case 1:
+        bbox = line_bbox.front ().extract (0, 0, 0, 3);
+        break;
 
-  FT_UInt process_character (FT_ULong code, FT_UInt previous = 0);
+      default:
+        for (std::list<Matrix>::const_iterator it = line_bbox.begin ();
+             it != line_bbox.end (); ++it)
+          {
+            if (bbox.is_empty ())
+              bbox = it->extract (0, 0, 0, 3);
+            else
+              {
+                bbox(1) -= (*it)(3);
+                bbox(3) += (*it)(3);
+                bbox(2) = octave::math::max (bbox(2), (*it)(2));
+              }
+          }
+        break;
+      }
+  }
 
-public:
+  void
+  ft_text_renderer::update_line_bbox (void)
+  {
+    // Called after a font change, when in MODE_BBOX mode, to update the
+    // current line bbox with the new font metrics.  This also includes the
+    // current yoffset, that is the offset of the current glyph's baseline
+    // the line's baseline.
+
+    if (mode == MODE_BBOX)
+      {
+        int asc = font.get_face ()->size->metrics.ascender >> 6;
+        int desc = font.get_face ()->size->metrics.descender >> 6;
+
+        Matrix& bb = line_bbox.back ();
+
+        if ((yoffset + desc) < bb(1))
+          {
+            // The new font goes below the bottom of the current bbox.
+
+            int delta = bb(1) - (yoffset + desc);
+
+            bb(1) -= delta;
+            bb(3) += delta;
+          }
+
+        if ((yoffset + asc) > (bb(1) + bb(3)))
+          {
+            // The new font goes above the top of the current bbox.
+
+            int delta = (yoffset + asc) - (bb(1) + bb(3));
 
-  void text_to_strlist (const std::string& txt,
-                        std::list<text_renderer::string>& lst, Matrix& bbox,
-                        int halign, int valign, double rotation,
-                        const caseless_str& interp);
+            bb(3) += delta;
+          }
+      }
+  }
+
+  void
+  ft_text_renderer::set_mode (int m)
+  {
+    mode = m;
+
+    switch (mode)
+      {
+      case MODE_BBOX:
+        xoffset = line_yoffset = yoffset = 0;
+        bbox = Matrix (1, 4, 0.0);
+        line_bbox.clear ();
+        push_new_line ();
+        break;
+
+      case MODE_RENDER:
+        if (bbox.numel () != 4)
+          {
+            ::warning ("ft_text_renderer: invalid bounding box, cannot render");
 
-private:
+            xoffset = line_yoffset = yoffset = 0;
+            pixels = uint8NDArray ();
+          }
+        else
+          {
+            dim_vector d (4, octave_idx_type (bbox(2)),
+                          octave_idx_type (bbox(3)));
+            pixels = uint8NDArray (d, static_cast<uint8_t> (0));
+            xoffset = compute_line_xoffset (line_bbox.front ());
+            line_yoffset = -bbox(1)-1;
+            yoffset = 0;
+          }
+        break;
+
+      default:
+        error ("ft_text_renderer: invalid mode '%d'", mode);
+        break;
+      }
+  }
+
+  FT_UInt
+  ft_text_renderer::process_character (FT_ULong code, FT_UInt previous)
+  {
+    FT_Face face = font.get_face ();
+    FT_UInt glyph_index = 0;
+
+    if (face)
+      {
+        glyph_index = FT_Get_Char_Index (face, code);
 
-  // The current font used by the renderer.
-  ft_font font;
+        if (code != '\n'
+            && (! glyph_index
+                || FT_Load_Glyph (face, glyph_index, FT_LOAD_DEFAULT)))
+          {
+            glyph_index = 0;
+            warn_missing_glyph (code);
+          }
+        else
+          {
+            switch (mode)
+              {
+              case MODE_RENDER:
+                if (code == '\n')
+                  {
+                    glyph_index = FT_Get_Char_Index (face, ' ');
+                    if (! glyph_index
+                        || FT_Load_Glyph (face, glyph_index, FT_LOAD_DEFAULT))
+                      {
+                        glyph_index = 0;
+                        warn_missing_glyph (' ');
+                      }
+                    else
+                      push_new_line ();
+                  }
+                else if (FT_Render_Glyph (face->glyph, FT_RENDER_MODE_NORMAL))
+                  {
+                    glyph_index = 0;
+                    warn_glyph_render (code);
+                  }
+                else
+                  {
+                    FT_Bitmap& bitmap = face->glyph->bitmap;
+                    int x0, y0;
+
+                    if (previous)
+                      {
+                        FT_Vector delta;
+
+                        FT_Get_Kerning (face, previous, glyph_index,
+                                        FT_KERNING_DEFAULT, &delta);
+                        xoffset += (delta.x >> 6);
+                      }
+
+                    x0 = xoffset + face->glyph->bitmap_left;
+                    y0 = line_yoffset + yoffset + face->glyph->bitmap_top;
+
+                    // 'w' seems to have a negative -1
+                    // face->glyph->bitmap_left, this is so we don't
+                    // index out of bound, and assumes we've allocated
+                    // the right amount of horizontal space in the bbox.
+                    if (x0 < 0)
+                      x0 = 0;
 
-  // Used to stored the bounding box corresponding to the rendered text.
-  // The bounding box has the form [x, y, w, h] where x and y represent the
-  // coordinates of the bottom left corner relative to the anchor point of
-  // the text (== start of text on the baseline).  Due to font descent or
-  // multiple lines, the value y is usually negative.
-  Matrix bbox;
+                    for (int r = 0; static_cast<unsigned int> (r) < bitmap.rows; r++)
+                      for (int c = 0; static_cast<unsigned int> (c) < bitmap.width; c++)
+                        {
+                          unsigned char pix = bitmap.buffer[r*bitmap.width+c];
+                          if (x0+c < 0 || x0+c >= pixels.dim2 ()
+                              || y0-r < 0 || y0-r >= pixels.dim3 ())
+                            {
+                              //::warning ("ft_text_renderer: pixel out of bound (char=%d, (x,y)=(%d,%d), (w,h)=(%d,%d)",
+                              //           str[i], x0+c, y0-r, pixels.dim2 (), pixels.dim3 ());
+                            }
+                          else if (pixels(3, x0+c, y0-r).value () == 0)
+                            {
+                              pixels(0, x0+c, y0-r) = color(0);
+                              pixels(1, x0+c, y0-r) = color(1);
+                              pixels(2, x0+c, y0-r) = color(2);
+                              pixels(3, x0+c, y0-r) = pix;
+                            }
+                        }
+
+                    xoffset += (face->glyph->advance.x >> 6);
+                  }
+                break;
+
+              case MODE_BBOX:
+                if (code == '\n')
+                  {
+                    glyph_index = FT_Get_Char_Index (face, ' ');
+                    if (! glyph_index
+                        || FT_Load_Glyph (face, glyph_index, FT_LOAD_DEFAULT))
+                      {
+                        glyph_index = 0;
+                        warn_missing_glyph (' ');
+                      }
+                    else
+                      push_new_line ();
+                  }
+                else
+                  {
+                    Matrix& bb = line_bbox.back ();
+
+                    // If we have a previous glyph, use kerning information.
+                    // This usually means moving a bit backward before adding
+                    // the next glyph.  That is, "delta.x" is usually < 0.
+                    if (previous)
+                      {
+                        FT_Vector delta;
+
+                        FT_Get_Kerning (face, previous, glyph_index,
+                                        FT_KERNING_DEFAULT, &delta);
+
+                        xoffset += (delta.x >> 6);
+                      }
 
-  // Used to stored the rendered text.  It's a 3D matrix with size MxNx4
-  // where M and N are the width and height of the bounding box.
-  uint8NDArray pixels;
+                    // Extend current X offset box by the width of the current
+                    // glyph.  Then extend the line bounding box if necessary.
+
+                    xoffset += (face->glyph->advance.x >> 6);
+                    bb(2) = octave::math::max (bb(2), xoffset);
+                  }
+                break;
+              }
+          }
+      }
+
+    return glyph_index;
+  }
+
+  void
+  ft_text_renderer::text_to_strlist (const std::string& txt,
+                                     std::list<text_renderer::string>& lst,
+                                     Matrix& box,
+                                     int ha, int va, double rot,
+                                     const caseless_str& interp)
+  {
+    uint8NDArray pxls;
+
+    // First run text_to_pixels which will also build the string list
+
+    text_to_pixels (txt, pxls, box, ha, va, rot, interp, false);
+
+    lst = strlist;
+  }
+
+  void
+  ft_text_renderer::visit (text_element_string& e)
+  {
+    if (font.is_valid ())
+      {
+        FT_UInt glyph_index, previous = 0;
+
+        std::string str = e.string_value ();
+        size_t n = str.length ();
+        size_t curr = 0;
+        size_t idx = 0;
+        mbstate_t ps;
+        memset (&ps, 0, sizeof (ps));  // Initialize state to 0.
+        wchar_t wc;
+
+        text_renderer::string fs (str, font, xoffset, yoffset);
+
+        while (n > 0)
+          {
+            size_t r = std::mbrtowc (&wc, str.data () + curr, n, &ps);
 
-  // Used to store the bounding box of each line.  This is used to layout
-  // multiline text properly.
-  std::list<Matrix> line_bbox;
+            if (r > 0
+                && r != static_cast<size_t> (-1)
+                && r != static_cast<size_t> (-2))
+              {
+                n -= r;
+                curr += r;
+
+                if (wc == L'\n')
+                  {
+                    // Finish previous string in srtlist before processing
+                    // the newline character
+                    fs.set_y (line_yoffset + yoffset);
+                    fs.set_color (color);
+                    std::string s = str.substr (idx, curr - idx - 1);
+                    if (! s.empty ())
+                      {
+                        fs.set_string (s);
+                        strlist.push_back (fs);
+                      }
+                  }
+
+                glyph_index = process_character (wc, previous);
 
-  // The current horizontal alignment.  This is used to align multi-line text.
-  int halign;
+                if (wc == L'\n')
+                  {
+                    previous = 0;
+                    // Start a new string in strlist
+                    idx = curr;
+                    fs = text_renderer::string (str.substr (idx), font,
+                                                line_xoffset, yoffset);
+
+                  }
+                else
+                  previous = glyph_index;
+              }
+            else
+              {
+                if (r != 0)
+                  ::warning ("ft_text_renderer: failed to decode string `%s' with "
+                             "locale `%s'", str.c_str (),
+                             std::setlocale (LC_CTYPE, 0));
+                break;
+              }
+          }
+
+        if (! fs.get_string ().empty ())
+          {
+            fs.set_y (line_yoffset + yoffset);
+            fs.set_color (color);
+            strlist.push_back (fs);
+          }
+      }
+  }
+
+  void
+  ft_text_renderer::visit (text_element_list& e)
+  {
+    // Save and restore (after processing the list) the current font and color.
 
-  // The X offset for the next glyph.
-  int xoffset;
+    ft_font saved_font (font);
+    uint8NDArray saved_color (color);
+
+    text_processor::visit (e);
+
+    font = saved_font;
+    color = saved_color;
+  }
+
+  void
+  ft_text_renderer::visit (text_element_subscript& e)
+  {
+    ft_font saved_font (font);
+    int saved_line_yoffset = line_yoffset;
+    int saved_yoffset = yoffset;
+
+    set_font (font.get_name (), font.get_weight (), font.get_angle (),
+              font.get_size () - 2);
+
+    if (font.is_valid ())
+      {
+        int h = font.get_face ()->size->metrics.height >> 6;
+
+        // Shifting the baseline by 2/3 the font height seems to produce
+        // decent result.
+        yoffset -= (h * 2) / 3;
+
+        if (mode == MODE_BBOX)
+          update_line_bbox ();
+      }
+
+    text_processor::visit (e);
+
+    font = saved_font;
+    // If line_yoffset changed, this means we moved to a new line; hence yoffset
+    // cannot be restored, because the saved value is not relevant anymore.
+    if (line_yoffset == saved_line_yoffset)
+      yoffset = saved_yoffset;
+  }
+
+  void
+  ft_text_renderer::visit (text_element_superscript& e)
+  {
+    ft_font saved_font (font);
+    int saved_line_yoffset = line_yoffset;
+    int saved_yoffset = yoffset;
 
-  // The Y offset of the baseline for the current line.
-  int line_yoffset;
+    set_font (font.get_name (), font.get_weight (), font.get_angle (),
+              font.get_size () - 2);
+
+    if (saved_font.is_valid ())
+      {
+        int s_asc = saved_font.get_face ()->size->metrics.ascender >> 6;
+
+        // Shifting the baseline by 2/3 base font ascender seems to produce
+        // decent result.
+        yoffset += (s_asc * 2) / 3;
+
+        if (mode == MODE_BBOX)
+          update_line_bbox ();
+      }
+
+    text_processor::visit (e);
+
+    font = saved_font;
+    // If line_yoffset changed, this means we moved to a new line; hence yoffset
+    // cannot be restored, because the saved value is not relevant anymore.
+    if (line_yoffset == saved_line_yoffset)
+      yoffset = saved_yoffset;
+  }
+
+  void
+  ft_text_renderer::visit (text_element_color& e)
+  {
+    if (mode == MODE_RENDER)
+      set_color (e.get_color ());
+  }
+
+  void
+  ft_text_renderer::visit (text_element_fontsize& e)
+  {
+    double sz = e.get_fontsize ();
+
+    // FIXME: Matlab documentation says that the font size is expressed
+    //        in the text object FontUnit.
+
+    set_font (font.get_name (), font.get_weight (), font.get_angle (), sz);
+
+    if (mode == MODE_BBOX)
+      update_line_bbox ();
+  }
+
+  void
+  ft_text_renderer::visit (text_element_fontname& e)
+  {
+    set_font (e.get_fontname (), font.get_weight (), font.get_angle (),
+              font.get_size ());
 
-  // The Y offset of the baseline for the next glyph.  The offset is relative
-  // to line_yoffset.  The total Y offset is computed with:
-  // line_yoffset + yoffset.
-  int yoffset;
+    if (mode == MODE_BBOX)
+      update_line_bbox ();
+  }
+
+  void
+  ft_text_renderer::visit (text_element_fontstyle& e)
+  {
+    switch (e.get_fontstyle ())
+      {
+      case text_element_fontstyle::normal:
+        set_font (font.get_name (), "normal", "normal", font.get_size ());
+        break;
+
+      case text_element_fontstyle::bold:
+        set_font (font.get_name (), "bold", "normal", font.get_size ());
+        break;
+
+      case text_element_fontstyle::italic:
+        set_font (font.get_name (), "normal", "italic", font.get_size ());
+        break;
+
+      case text_element_fontstyle::oblique:
+        set_font (font.get_name (), "normal", "oblique", font.get_size ());
+        break;
+      }
+
+    if (mode == MODE_BBOX)
+      update_line_bbox ();
+  }
+
+  void
+  ft_text_renderer::visit (text_element_symbol& e)
+  {
+    uint32_t code = e.get_symbol_code ();
+
+    text_renderer::string fs (std::string ("-"), font, xoffset, yoffset);
+
+    if (code != text_element_symbol::invalid_code && font.is_valid ())
+      {
+        process_character (code);
+        fs.set_code (code);
+      }
+    else if (font.is_valid ())
+      ::warning ("ignoring unknown symbol: %d", e.get_symbol ());
 
-  // The current mode of the rendering process (box computing or rendering).
-  int mode;
+    if (fs.get_code ())
+      {
+        fs.set_y (line_yoffset + yoffset);
+        fs.set_color (color);
+        strlist.push_back (fs);
+      }
+  }
+
+  void
+  ft_text_renderer::visit (text_element_combined& e)
+  {
+    int saved_xoffset = xoffset;
+    int max_xoffset = xoffset;
+
+    for (text_element_combined::iterator it = e.begin (); it != e.end (); ++it)
+      {
+        xoffset = saved_xoffset;
+        (*it)->accept (*this);
+        max_xoffset = octave::math::max (xoffset, max_xoffset);
+      }
+
+    xoffset = max_xoffset;
+  }
 
-  // The base color of the rendered text.
-  uint8NDArray color;
+  void
+  ft_text_renderer::reset (void)
+  {
+    set_mode (MODE_BBOX);
+    set_color (Matrix (1, 3, 0.0));
+  }
 
-  // A list of parsed strings to be used for printing.
-  std::list<text_renderer::string> strlist;
+  void
+  ft_text_renderer::set_color (const Matrix& c)
+  {
+    if (c.numel () == 3)
+      {
+        color(0) = static_cast<uint8_t> (c(0)*255);
+        color(1) = static_cast<uint8_t> (c(1)*255);
+        color(2) = static_cast<uint8_t> (c(2)*255);
+      }
+    else
+      ::warning ("ft_text_renderer::set_color: invalid color");
+  }
+
+  uint8NDArray
+  ft_text_renderer::render (text_element *elt, Matrix& box, int rotation)
+  {
+    set_mode (MODE_BBOX);
+    elt->accept (*this);
+    compute_bbox ();
+    box = bbox;
+
+    set_mode (MODE_RENDER);
+    // Clear the list of parsed strings
+    strlist.clear ();
+
+    if (pixels.numel () > 0)
+      {
+        elt->accept (*this);
 
-  // The X offset of the baseline for the current line.
-  int line_xoffset;
+        switch (rotation)
+          {
+          case ROTATION_0:
+            break;
+
+          case ROTATION_90:
+            {
+              Array<octave_idx_type> perm (dim_vector (3, 1));
+              perm(0) = 0;
+              perm(1) = 2;
+              perm(2) = 1;
+              pixels = pixels.permute (perm);
+
+              Array<idx_vector> idx (dim_vector (3, 1));
+              idx(0) = idx_vector (':');
+              idx(1) = idx_vector (pixels.dim2 ()-1, -1, -1);
+              idx(2) = idx_vector (':');
+              pixels = uint8NDArray (pixels.index (idx));
+            }
+            break;
 
-};
+          case ROTATION_180:
+            {
+              Array<idx_vector> idx (dim_vector (3, 1));
+              idx(0) = idx_vector (':');
+              idx(1) = idx_vector (pixels.dim2 ()-1, -1, -1);
+              idx(2) = idx_vector (pixels.dim3 ()-1, -1, -1);
+              pixels = uint8NDArray (pixels.index (idx));
+            }
+            break;
+
+          case ROTATION_270:
+            {
+              Array<octave_idx_type> perm (dim_vector (3, 1));
+              perm(0) = 0;
+              perm(1) = 2;
+              perm(2) = 1;
+              pixels = pixels.permute (perm);
+
+              Array<idx_vector> idx (dim_vector (3, 1));
+              idx(0) = idx_vector (':');
+              idx(1) = idx_vector (':');
+              idx(2) = idx_vector (pixels.dim3 ()-1, -1, -1);
+              pixels = uint8NDArray (pixels.index (idx));
+            }
+            break;
+          }
+      }
 
-void
-ft_text_renderer::set_font (const std::string& name, const std::string& weight,
-                     const std::string& angle, double size)
-{
-  // FIXME: take "fontunits" into account
+    return pixels;
+  }
+
+  // Note:
+  // x-extent accurately measures width of glyphs.
+  // y-extent is overly large because it is measured from baseline-to-baseline.
+  // Calling routines, such as ylabel, may need to account for this mismatch.
+
+  Matrix
+  ft_text_renderer::get_extent (text_element *elt, double rotation)
+  {
+    set_mode (MODE_BBOX);
+    elt->accept (*this);
+    compute_bbox ();
+
+    Matrix extent (1, 2, 0.0);
+
+    switch (rotation_to_mode (rotation))
+      {
+      case ROTATION_0:
+      case ROTATION_180:
+        extent(0) = bbox(2);
+        extent(1) = bbox(3);
+        break;
+
+      case ROTATION_90:
+      case ROTATION_270:
+        extent(0) = bbox(3);
+        extent(1) = bbox(2);
+      }
+
+    return extent;
+  }
+
+  Matrix
+  ft_text_renderer::get_extent (const std::string& txt, double rotation,
+                                const caseless_str& interpreter)
+  {
+    text_element *elt = text_parser::parse (txt, interpreter);
+    Matrix extent = get_extent (elt, rotation);
+    delete elt;
+
+    return extent;
+  }
+
+  int
+  ft_text_renderer::rotation_to_mode (double rotation) const
+  {
+    // Clip rotation to range [0, 360]
+    while (rotation < 0)
+      rotation += 360.0;
+    while (rotation > 360.0)
+      rotation -= 360.0;
 
-  font = ft_font (name, weight, angle, size, 0);
-}
+    if (rotation == 0.0)
+      return ROTATION_0;
+    else if (rotation == 90.0)
+      return ROTATION_90;
+    else if (rotation == 180.0)
+      return ROTATION_180;
+    else if (rotation == 270.0)
+      return ROTATION_270;
+    else
+      return ROTATION_0;
+  }
+
+  void
+  ft_text_renderer::text_to_pixels (const std::string& txt,
+                                    uint8NDArray& pxls, Matrix& box,
+                                    int _halign, int valign, double rotation,
+                                    const caseless_str& interpreter,
+                                    bool handle_rotation)
+  {
+    int rot_mode = rotation_to_mode (rotation);
+
+    halign = _halign;
+
+    text_element *elt = text_parser::parse (txt, interpreter);
+    pxls = render (elt, box, rot_mode);
+    delete elt;
+
+    if (pxls.is_empty ())
+      return;  // nothing to render
+
+    switch (halign)
+      {
+      case 1:
+        box(0) = -box(2)/2;
+        break;
+
+      case 2:
+        box(0) = -box(2);
+        break;
+
+      default:
+        box(0) = 0;
+        break;
+      }
+
+    switch (valign)
+      {
+      case 1:
+        box(1) = -box(3)/2;
+        break;
 
-void
-ft_text_renderer::push_new_line (void)
-{
-  switch (mode)
-    {
-    case MODE_BBOX:
+      case 2:
+        box(1) = -box(3);
+        break;
+
+      case 3:
+        break;
+
+      case 4:
+        box(1) = -box(3)-box(1);
+        break;
+
+      default:
+        box(1) = 0;
+        break;
+      }
+
+    if (handle_rotation)
       {
-        // Create a new bbox entry based on the current font.
+        switch (rot_mode)
+          {
+          case ROTATION_90:
+            std::swap (box(0), box(1));
+            std::swap (box(2), box(3));
+            box(0) = -box(0)-box(2);
+            break;
+
+          case ROTATION_180:
+            box(0) = -box(0)-box(2);
+            box(1) = -box(1)-box(3);
+            break;
 
-        FT_Face face = font.get_face ();
+          case ROTATION_270:
+            std::swap (box(0), box(1));
+            std::swap (box(2), box(3));
+            box(1) = -box(1)-box(3);
+            break;
+          }
+      }
+  }
+
+  ft_text_renderer::ft_font::ft_font (const ft_font& ft)
+    : text_renderer::font (ft), face (0)
+  {
+#if defined (HAVE_FT_REFERENCE_FACE)
+    FT_Face ft_face = ft.get_face ();
+
+    if (ft_face && FT_Reference_Face (ft_face) == 0)
+      face = ft_face;
+#endif
+  }
+
+  ft_text_renderer::ft_font&
+  ft_text_renderer::ft_font::operator = (const ft_font& ft)
+  {
+    if (&ft != this)
+      {
+        text_renderer::font::operator = (ft);
 
         if (face)
           {
-            int asc = face->size->metrics.ascender >> 6;
-            int desc = face->size->metrics.descender >> 6;
-            int h = face->size->metrics.height >> 6;
-
-            Matrix bb (1, 5, 0.0);
-
-            bb(1) = desc;
-            bb(3) = asc - desc;
-            bb(4) = h;
-
-            line_bbox.push_back (bb);
-
-            xoffset = yoffset = 0;
+            FT_Done_Face (face);
+            face = 0;
           }
-      }
-      break;
-
-    case MODE_RENDER:
-      {
-        // Move to the next line bbox, adjust xoffset based on alignment
-        // and yoffset based on the old and new line bbox.
-
-        Matrix old_bbox = line_bbox.front ();
-        line_bbox.pop_front ();
-        Matrix new_bbox = line_bbox.front ();
-
-        xoffset = line_xoffset = compute_line_xoffset (new_bbox);
-        line_yoffset += (old_bbox(1) - (new_bbox(1) + new_bbox(3)));
-        yoffset = 0;
-      }
-      break;
-    }
-}
-
-int
-ft_text_renderer::compute_line_xoffset (const Matrix& lb) const
-{
-  if (! bbox.is_empty ())
-    {
-      switch (halign)
-        {
-        case 0:
-          return 0;
-        case 1:
-          return (bbox(2) - lb(2)) / 2;
-        case 2:
-          return (bbox(2) - lb(2));
-        }
-    }
-
-  return 0;
-}
-
-void
-ft_text_renderer::compute_bbox (void)
-{
-  // Stack the various line bbox together and compute the final
-  // bounding box for the entire text string.
-
-  bbox = Matrix ();
-
-  switch (line_bbox.size ())
-    {
-    case 0:
-      break;
-
-    case 1:
-      bbox = line_bbox.front ().extract (0, 0, 0, 3);
-      break;
-
-    default:
-      for (std::list<Matrix>::const_iterator it = line_bbox.begin ();
-           it != line_bbox.end (); ++it)
-        {
-          if (bbox.is_empty ())
-            bbox = it->extract (0, 0, 0, 3);
-          else
-            {
-              bbox(1) -= (*it)(3);
-              bbox(3) += (*it)(3);
-              bbox(2) = octave::math::max (bbox(2), (*it)(2));
-            }
-        }
-      break;
-    }
-}
-
-void
-ft_text_renderer::update_line_bbox (void)
-{
-  // Called after a font change, when in MODE_BBOX mode, to update the
-  // current line bbox with the new font metrics.  This also includes the
-  // current yoffset, that is the offset of the current glyph's baseline
-  // the line's baseline.
-
-  if (mode == MODE_BBOX)
-    {
-      int asc = font.get_face ()->size->metrics.ascender >> 6;
-      int desc = font.get_face ()->size->metrics.descender >> 6;
-
-      Matrix& bb = line_bbox.back ();
-
-      if ((yoffset + desc) < bb(1))
-        {
-          // The new font goes below the bottom of the current bbox.
-
-          int delta = bb(1) - (yoffset + desc);
-
-          bb(1) -= delta;
-          bb(3) += delta;
-        }
-
-      if ((yoffset + asc) > (bb(1) + bb(3)))
-        {
-          // The new font goes above the top of the current bbox.
-
-          int delta = (yoffset + asc) - (bb(1) + bb(3));
-
-          bb(3) += delta;
-        }
-    }
-}
-
-void
-ft_text_renderer::set_mode (int m)
-{
-  mode = m;
-
-  switch (mode)
-    {
-    case MODE_BBOX:
-      xoffset = line_yoffset = yoffset = 0;
-      bbox = Matrix (1, 4, 0.0);
-      line_bbox.clear ();
-      push_new_line ();
-      break;
-
-    case MODE_RENDER:
-      if (bbox.numel () != 4)
-        {
-          ::warning ("ft_text_renderer: invalid bounding box, cannot render");
-
-          xoffset = line_yoffset = yoffset = 0;
-          pixels = uint8NDArray ();
-        }
-      else
-        {
-          dim_vector d (4, octave_idx_type (bbox(2)),
-                        octave_idx_type (bbox(3)));
-          pixels = uint8NDArray (d, static_cast<uint8_t> (0));
-          xoffset = compute_line_xoffset (line_bbox.front ());
-          line_yoffset = -bbox(1)-1;
-          yoffset = 0;
-        }
-      break;
-
-    default:
-      error ("ft_text_renderer: invalid mode '%d'", mode);
-      break;
-    }
-}
-
-FT_UInt
-ft_text_renderer::process_character (FT_ULong code, FT_UInt previous)
-{
-  FT_Face face = font.get_face ();
-  FT_UInt glyph_index = 0;
-
-  if (face)
-    {
-      glyph_index = FT_Get_Char_Index (face, code);
-
-      if (code != '\n'
-          && (! glyph_index
-              || FT_Load_Glyph (face, glyph_index, FT_LOAD_DEFAULT)))
-        {
-          glyph_index = 0;
-          warn_missing_glyph (code);
-        }
-      else
-        {
-          switch (mode)
-            {
-            case MODE_RENDER:
-              if (code == '\n')
-                {
-                  glyph_index = FT_Get_Char_Index (face, ' ');
-                  if (! glyph_index
-                      || FT_Load_Glyph (face, glyph_index, FT_LOAD_DEFAULT))
-                    {
-                      glyph_index = 0;
-                      warn_missing_glyph (' ');
-                    }
-                  else
-                    push_new_line ();
-                }
-              else if (FT_Render_Glyph (face->glyph, FT_RENDER_MODE_NORMAL))
-                {
-                  glyph_index = 0;
-                  warn_glyph_render (code);
-                }
-              else
-                {
-                  FT_Bitmap& bitmap = face->glyph->bitmap;
-                  int x0, y0;
-
-                  if (previous)
-                    {
-                      FT_Vector delta;
-
-                      FT_Get_Kerning (face, previous, glyph_index,
-                                      FT_KERNING_DEFAULT, &delta);
-                      xoffset += (delta.x >> 6);
-                    }
-
-                  x0 = xoffset + face->glyph->bitmap_left;
-                  y0 = line_yoffset + yoffset + face->glyph->bitmap_top;
-
-                  // 'w' seems to have a negative -1
-                  // face->glyph->bitmap_left, this is so we don't
-                  // index out of bound, and assumes we've allocated
-                  // the right amount of horizontal space in the bbox.
-                  if (x0 < 0)
-                    x0 = 0;
-
-                  for (int r = 0; static_cast<unsigned int> (r) < bitmap.rows; r++)
-                    for (int c = 0; static_cast<unsigned int> (c) < bitmap.width; c++)
-                      {
-                        unsigned char pix = bitmap.buffer[r*bitmap.width+c];
-                        if (x0+c < 0 || x0+c >= pixels.dim2 ()
-                            || y0-r < 0 || y0-r >= pixels.dim3 ())
-                          {
-                            //::warning ("ft_text_renderer: pixel out of bound (char=%d, (x,y)=(%d,%d), (w,h)=(%d,%d)",
-                            //           str[i], x0+c, y0-r, pixels.dim2 (), pixels.dim3 ());
-                          }
-                        else if (pixels(3, x0+c, y0-r).value () == 0)
-                          {
-                            pixels(0, x0+c, y0-r) = color(0);
-                            pixels(1, x0+c, y0-r) = color(1);
-                            pixels(2, x0+c, y0-r) = color(2);
-                            pixels(3, x0+c, y0-r) = pix;
-                          }
-                      }
-
-                  xoffset += (face->glyph->advance.x >> 6);
-                }
-              break;
-
-            case MODE_BBOX:
-              if (code == '\n')
-                {
-                  glyph_index = FT_Get_Char_Index (face, ' ');
-                  if (! glyph_index
-                      || FT_Load_Glyph (face, glyph_index, FT_LOAD_DEFAULT))
-                    {
-                      glyph_index = 0;
-                      warn_missing_glyph (' ');
-                    }
-                  else
-                    push_new_line ();
-                }
-              else
-                {
-                  Matrix& bb = line_bbox.back ();
-
-                  // If we have a previous glyph, use kerning information.
-                  // This usually means moving a bit backward before adding
-                  // the next glyph.  That is, "delta.x" is usually < 0.
-                  if (previous)
-                    {
-                      FT_Vector delta;
-
-                      FT_Get_Kerning (face, previous, glyph_index,
-                                      FT_KERNING_DEFAULT, &delta);
-
-                      xoffset += (delta.x >> 6);
-                    }
-
-                  // Extend current X offset box by the width of the current
-                  // glyph.  Then extend the line bounding box if necessary.
-
-                  xoffset += (face->glyph->advance.x >> 6);
-                  bb(2) = octave::math::max (bb(2), xoffset);
-                }
-              break;
-            }
-        }
-    }
-
-  return glyph_index;
-}
-
-void
-ft_text_renderer::text_to_strlist (const std::string& txt,
-                                   std::list<text_renderer::string>& lst,
-                                   Matrix& box,
-                                   int ha, int va, double rot,
-                                   const caseless_str& interp)
-{
-  uint8NDArray pxls;
-
-  // First run text_to_pixels which will also build the string list
-
-  text_to_pixels (txt, pxls, box, ha, va, rot, interp, false);
-
-  lst = strlist;
-}
-
-void
-ft_text_renderer::visit (text_element_string& e)
-{
-  if (font.is_valid ())
-    {
-      FT_UInt glyph_index, previous = 0;
-
-      std::string str = e.string_value ();
-      size_t n = str.length ();
-      size_t curr = 0;
-      size_t idx = 0;
-      mbstate_t ps;
-      memset (&ps, 0, sizeof (ps));  // Initialize state to 0.
-      wchar_t wc;
-
-      text_renderer::string fs (str, font, xoffset, yoffset);
-
-      while (n > 0)
-        {
-          size_t r = std::mbrtowc (&wc, str.data () + curr, n, &ps);
-
-          if (r > 0
-              && r != static_cast<size_t> (-1)
-              && r != static_cast<size_t> (-2))
-            {
-              n -= r;
-              curr += r;
-
-              if (wc == L'\n')
-                {
-                  // Finish previous string in srtlist before processing
-                  // the newline character
-                  fs.set_y (line_yoffset + yoffset);
-                  fs.set_color (color);
-                  std::string s = str.substr (idx, curr - idx - 1);
-                  if (! s.empty ())
-                    {
-                      fs.set_string (s);
-                      strlist.push_back (fs);
-                    }
-                }
-
-              glyph_index = process_character (wc, previous);
-
-              if (wc == L'\n')
-                {
-                  previous = 0;
-                  // Start a new string in strlist
-                  idx = curr;
-                  fs = text_renderer::string (str.substr (idx), font,
-                                             line_xoffset, yoffset);
-
-                }
-              else
-                previous = glyph_index;
-            }
-          else
-            {
-              if (r != 0)
-                ::warning ("ft_text_renderer: failed to decode string `%s' with "
-                           "locale `%s'", str.c_str (),
-                           std::setlocale (LC_CTYPE, 0));
-              break;
-            }
-        }
-
-      if (! fs.get_string ().empty ())
-        {
-          fs.set_y (line_yoffset + yoffset);
-          fs.set_color (color);
-          strlist.push_back (fs);
-        }
-    }
-}
-
-void
-ft_text_renderer::visit (text_element_list& e)
-{
-  // Save and restore (after processing the list) the current font and color.
-
-  ft_font saved_font (font);
-  uint8NDArray saved_color (color);
-
-  text_processor::visit (e);
-
-  font = saved_font;
-  color = saved_color;
-}
-
-void
-ft_text_renderer::visit (text_element_subscript& e)
-{
-  ft_font saved_font (font);
-  int saved_line_yoffset = line_yoffset;
-  int saved_yoffset = yoffset;
-
-  set_font (font.get_name (), font.get_weight (), font.get_angle (),
-            font.get_size () - 2);
-
-  if (font.is_valid ())
-    {
-      int h = font.get_face ()->size->metrics.height >> 6;
-
-      // Shifting the baseline by 2/3 the font height seems to produce
-      // decent result.
-      yoffset -= (h * 2) / 3;
-
-      if (mode == MODE_BBOX)
-        update_line_bbox ();
-    }
-
-  text_processor::visit (e);
-
-  font = saved_font;
-  // If line_yoffset changed, this means we moved to a new line; hence yoffset
-  // cannot be restored, because the saved value is not relevant anymore.
-  if (line_yoffset == saved_line_yoffset)
-    yoffset = saved_yoffset;
-}
-
-void
-ft_text_renderer::visit (text_element_superscript& e)
-{
-  ft_font saved_font (font);
-  int saved_line_yoffset = line_yoffset;
-  int saved_yoffset = yoffset;
-
-  set_font (font.get_name (), font.get_weight (), font.get_angle (),
-            font.get_size () - 2);
-
-  if (saved_font.is_valid ())
-    {
-      int s_asc = saved_font.get_face ()->size->metrics.ascender >> 6;
-
-      // Shifting the baseline by 2/3 base font ascender seems to produce
-      // decent result.
-      yoffset += (s_asc * 2) / 3;
-
-      if (mode == MODE_BBOX)
-        update_line_bbox ();
-    }
-
-  text_processor::visit (e);
-
-  font = saved_font;
-  // If line_yoffset changed, this means we moved to a new line; hence yoffset
-  // cannot be restored, because the saved value is not relevant anymore.
-  if (line_yoffset == saved_line_yoffset)
-    yoffset = saved_yoffset;
-}
-
-void
-ft_text_renderer::visit (text_element_color& e)
-{
-  if (mode == MODE_RENDER)
-    set_color (e.get_color ());
-}
-
-void
-ft_text_renderer::visit (text_element_fontsize& e)
-{
-  double sz = e.get_fontsize ();
-
-  // FIXME: Matlab documentation says that the font size is expressed
-  //        in the text object FontUnit.
-
-  set_font (font.get_name (), font.get_weight (), font.get_angle (), sz);
-
-  if (mode == MODE_BBOX)
-    update_line_bbox ();
-}
-
-void
-ft_text_renderer::visit (text_element_fontname& e)
-{
-  set_font (e.get_fontname (), font.get_weight (), font.get_angle (),
-            font.get_size ());
-
-  if (mode == MODE_BBOX)
-    update_line_bbox ();
-}
-
-void
-ft_text_renderer::visit (text_element_fontstyle& e)
-{
-  switch (e.get_fontstyle ())
-    {
-    case text_element_fontstyle::normal:
-      set_font (font.get_name (), "normal", "normal", font.get_size ());
-      break;
-
-    case text_element_fontstyle::bold:
-      set_font (font.get_name (), "bold", "normal", font.get_size ());
-      break;
-
-    case text_element_fontstyle::italic:
-      set_font (font.get_name (), "normal", "italic", font.get_size ());
-      break;
-
-    case text_element_fontstyle::oblique:
-      set_font (font.get_name (), "normal", "oblique", font.get_size ());
-      break;
-    }
-
-  if (mode == MODE_BBOX)
-    update_line_bbox ();
-}
-
-void
-ft_text_renderer::visit (text_element_symbol& e)
-{
-  uint32_t code = e.get_symbol_code ();
-
-  text_renderer::string fs (std::string ("-"), font, xoffset, yoffset);
-
-  if (code != text_element_symbol::invalid_code && font.is_valid ())
-    {
-      process_character (code);
-      fs.set_code (code);
-    }
-  else if (font.is_valid ())
-    ::warning ("ignoring unknown symbol: %d", e.get_symbol ());
-
-  if (fs.get_code ())
-    {
-      fs.set_y (line_yoffset + yoffset);
-      fs.set_color (color);
-      strlist.push_back (fs);
-   }
-}
-
-void
-ft_text_renderer::visit (text_element_combined& e)
-{
-  int saved_xoffset = xoffset;
-  int max_xoffset = xoffset;
-
-  for (text_element_combined::iterator it = e.begin (); it != e.end (); ++it)
-    {
-      xoffset = saved_xoffset;
-      (*it)->accept (*this);
-      max_xoffset = octave::math::max (xoffset, max_xoffset);
-    }
-
-  xoffset = max_xoffset;
-}
-
-void
-ft_text_renderer::reset (void)
-{
-  set_mode (MODE_BBOX);
-  set_color (Matrix (1, 3, 0.0));
-}
-
-void
-ft_text_renderer::set_color (const Matrix& c)
-{
-  if (c.numel () == 3)
-    {
-      color(0) = static_cast<uint8_t> (c(0)*255);
-      color(1) = static_cast<uint8_t> (c(1)*255);
-      color(2) = static_cast<uint8_t> (c(2)*255);
-    }
-  else
-    ::warning ("ft_text_renderer::set_color: invalid color");
-}
-
-uint8NDArray
-ft_text_renderer::render (text_element *elt, Matrix& box, int rotation)
-{
-  set_mode (MODE_BBOX);
-  elt->accept (*this);
-  compute_bbox ();
-  box = bbox;
-
-  set_mode (MODE_RENDER);
-  // Clear the list of parsed strings
-  strlist.clear ();
-
-  if (pixels.numel () > 0)
-    {
-      elt->accept (*this);
-
-      switch (rotation)
-        {
-        case ROTATION_0:
-          break;
-
-        case ROTATION_90:
-          {
-            Array<octave_idx_type> perm (dim_vector (3, 1));
-            perm(0) = 0;
-            perm(1) = 2;
-            perm(2) = 1;
-            pixels = pixels.permute (perm);
-
-            Array<idx_vector> idx (dim_vector (3, 1));
-            idx(0) = idx_vector (':');
-            idx(1) = idx_vector (pixels.dim2 ()-1, -1, -1);
-            idx(2) = idx_vector (':');
-            pixels = uint8NDArray (pixels.index (idx));
-          }
-          break;
-
-        case ROTATION_180:
-          {
-            Array<idx_vector> idx (dim_vector (3, 1));
-            idx(0) = idx_vector (':');
-            idx(1) = idx_vector (pixels.dim2 ()-1, -1, -1);
-            idx(2) = idx_vector (pixels.dim3 ()-1, -1, -1);
-            pixels = uint8NDArray (pixels.index (idx));
-          }
-          break;
-
-        case ROTATION_270:
-          {
-            Array<octave_idx_type> perm (dim_vector (3, 1));
-            perm(0) = 0;
-            perm(1) = 2;
-            perm(2) = 1;
-            pixels = pixels.permute (perm);
-
-            Array<idx_vector> idx (dim_vector (3, 1));
-            idx(0) = idx_vector (':');
-            idx(1) = idx_vector (':');
-            idx(2) = idx_vector (pixels.dim3 ()-1, -1, -1);
-            pixels = uint8NDArray (pixels.index (idx));
-          }
-          break;
-        }
-    }
-
-  return pixels;
-}
-
-// Note:
-// x-extent accurately measures width of glyphs.
-// y-extent is overly large because it is measured from baseline-to-baseline.
-// Calling routines, such as ylabel, may need to account for this mismatch.
-
-Matrix
-ft_text_renderer::get_extent (text_element *elt, double rotation)
-{
-  set_mode (MODE_BBOX);
-  elt->accept (*this);
-  compute_bbox ();
-
-  Matrix extent (1, 2, 0.0);
-
-  switch (rotation_to_mode (rotation))
-    {
-    case ROTATION_0:
-    case ROTATION_180:
-      extent(0) = bbox(2);
-      extent(1) = bbox(3);
-      break;
-
-    case ROTATION_90:
-    case ROTATION_270:
-      extent(0) = bbox(3);
-      extent(1) = bbox(2);
-    }
-
-  return extent;
-}
-
-Matrix
-ft_text_renderer::get_extent (const std::string& txt, double rotation,
-                              const caseless_str& interpreter)
-{
-  text_element *elt = text_parser::parse (txt, interpreter);
-  Matrix extent = get_extent (elt, rotation);
-  delete elt;
-
-  return extent;
-}
-
-int
-ft_text_renderer::rotation_to_mode (double rotation) const
-{
-  // Clip rotation to range [0, 360]
-  while (rotation < 0)
-    rotation += 360.0;
-  while (rotation > 360.0)
-    rotation -= 360.0;
-
-  if (rotation == 0.0)
-    return ROTATION_0;
-  else if (rotation == 90.0)
-    return ROTATION_90;
-  else if (rotation == 180.0)
-    return ROTATION_180;
-  else if (rotation == 270.0)
-    return ROTATION_270;
-  else
-    return ROTATION_0;
-}
-
-void
-ft_text_renderer::text_to_pixels (const std::string& txt,
-                                  uint8NDArray& pxls, Matrix& box,
-                                  int _halign, int valign, double rotation,
-                                  const caseless_str& interpreter,
-                                  bool handle_rotation)
-{
-  int rot_mode = rotation_to_mode (rotation);
-
-  halign = _halign;
-
-  text_element *elt = text_parser::parse (txt, interpreter);
-  pxls = render (elt, box, rot_mode);
-  delete elt;
-
-  if (pxls.is_empty ())
-    return;  // nothing to render
-
-  switch (halign)
-    {
-    case 1:
-      box(0) = -box(2)/2;
-      break;
-
-    case 2:
-      box(0) = -box(2);
-      break;
-
-    default:
-      box(0) = 0;
-      break;
-    }
-
-  switch (valign)
-    {
-    case 1:
-      box(1) = -box(3)/2;
-      break;
-
-    case 2:
-      box(1) = -box(3);
-      break;
-
-    case 3:
-      break;
-
-    case 4:
-      box(1) = -box(3)-box(1);
-      break;
-
-    default:
-      box(1) = 0;
-      break;
-    }
-
-  if (handle_rotation)
-    {
-      switch (rot_mode)
-        {
-        case ROTATION_90:
-          std::swap (box(0), box(1));
-          std::swap (box(2), box(3));
-          box(0) = -box(0)-box(2);
-          break;
-
-        case ROTATION_180:
-          box(0) = -box(0)-box(2);
-          box(1) = -box(1)-box(3);
-          break;
-
-        case ROTATION_270:
-          std::swap (box(0), box(1));
-          std::swap (box(2), box(3));
-          box(1) = -box(1)-box(3);
-          break;
-        }
-    }
-}
-
-ft_text_renderer::ft_font::ft_font (const ft_font& ft)
-  : text_renderer::font (ft), face (0)
-{
-#if defined (HAVE_FT_REFERENCE_FACE)
-  FT_Face ft_face = ft.get_face ();
-
-  if (ft_face && FT_Reference_Face (ft_face) == 0)
-    face = ft_face;
-#endif
-}
-
-ft_text_renderer::ft_font&
-ft_text_renderer::ft_font::operator = (const ft_font& ft)
-{
-  if (&ft != this)
-    {
-      text_renderer::font::operator = (ft);
-
-      if (face)
-        {
-          FT_Done_Face (face);
-          face = 0;
-        }
 
 #if defined (HAVE_FT_REFERENCE_FACE)
-      FT_Face ft_face = ft.get_face ();
+        FT_Face ft_face = ft.get_face ();
 
-      if (ft_face && FT_Reference_Face (ft_face) == 0)
-        face = ft_face;
+        if (ft_face && FT_Reference_Face (ft_face) == 0)
+          face = ft_face;
 #endif
-    }
+      }
 
-  return *this;
-}
+    return *this;
+  }
 
-FT_Face
-ft_text_renderer::ft_font::get_face (void) const
-{
-  if (! face && ! name.empty ())
-    {
-      face = ft_manager::get_font (name, weight, angle, size);
+  FT_Face
+  ft_text_renderer::ft_font::get_face (void) const
+  {
+    if (! face && ! name.empty ())
+      {
+        face = ft_manager::get_font (name, weight, angle, size);
 
-      if (face)
-        {
-          if (FT_Set_Char_Size (face, 0, size*64, 0, 0))
-            ::warning ("ft_text_renderer: unable to set font size to %g", size);
-        }
-      else
-        ::warning ("ft_text_renderer: unable to load appropriate font");
-    }
+        if (face)
+          {
+            if (FT_Set_Char_Size (face, 0, size*64, 0, 0))
+              ::warning ("ft_text_renderer: unable to set font size to %g", size);
+          }
+        else
+          ::warning ("ft_text_renderer: unable to load appropriate font");
+      }
 
-  return face;
-}
-
+    return face;
+  }
 }
 
 #endif
--- a/libinterp/corefcn/gl-render.cc	Wed Aug 17 08:20:26 2016 -0700
+++ b/libinterp/corefcn/gl-render.cc	Wed Aug 17 11:43:27 2016 -0400
@@ -55,3965 +55,3963 @@
 
 namespace octave
 {
-
 #define LIGHT_MODE GL_FRONT_AND_BACK
 
-// Use symbolic names for axes
-enum
-{
-  X_AXIS,
-  Y_AXIS,
-  Z_AXIS
-};
-
-// Use symbolic names for color mode
-enum
-{
-  UNIFORM,
-  FLAT,
-  INTERP,
-  TEXTURE
-};
-
-// Use symbolic names for lighting
-enum
-{
-  NONE,
-  //FLAT,  // Already declared in anonymous enum for color mode
-  GOURAUD = 2
-};
-
-// Win32 API requires the CALLBACK attributes for
-// GLU callback functions.  Define it to empty on
-// other platforms.
+  // Use symbolic names for axes
+  enum
+    {
+      X_AXIS,
+      Y_AXIS,
+      Z_AXIS
+    };
+
+  // Use symbolic names for color mode
+  enum
+    {
+      UNIFORM,
+      FLAT,
+      INTERP,
+      TEXTURE
+    };
+
+  // Use symbolic names for lighting
+  enum
+    {
+      NONE,
+      //FLAT,  // Already declared in anonymous enum for color mode
+      GOURAUD = 2
+    };
+
+  // Win32 API requires the CALLBACK attributes for
+  // GLU callback functions.  Define it to empty on
+  // other platforms.
 #if ! defined (CALLBACK)
 #  define CALLBACK
 #endif
 
-class
-opengl_texture
-{
-protected:
-  class texture_rep
+  class
+  opengl_texture
   {
+  protected:
+    class texture_rep
+    {
+    public:
+      texture_rep (void)
+        : id (), w (), h (), tw (), th (), tx (), ty (),
+          valid (false), count (1)
+      { }
+
+      texture_rep (GLuint id_arg, int w_arg, int h_arg, int tw_arg, int th_arg)
+        : id (id_arg), w (w_arg), h (h_arg), tw (tw_arg), th (th_arg),
+          tx (double(w)/tw), ty (double(h)/th), valid (true),
+          count (1) { }
+
+      ~texture_rep (void)
+      {
+        if (valid)
+          glDeleteTextures (1, &id);
+      }
+
+      void bind (int mode) const
+      { if (valid) glBindTexture (mode, id); }
+
+      void tex_coord (double q, double r) const
+      { if (valid) glTexCoord2d (q*tx, r*ty); }
+
+      GLuint id;
+      int w, h;
+      int tw, th;
+      double tx, ty;
+      bool valid;
+      octave_refcount<int> count;
+    };
+
+    texture_rep *rep;
+
+  private:
+    opengl_texture (texture_rep *_rep) : rep (_rep) { }
+
   public:
-    texture_rep (void)
-      : id (), w (), h (), tw (), th (), tx (), ty (),
-        valid (false), count (1)
-    { }
-
-    texture_rep (GLuint id_arg, int w_arg, int h_arg, int tw_arg, int th_arg)
-      : id (id_arg), w (w_arg), h (h_arg), tw (tw_arg), th (th_arg),
-        tx (double(w)/tw), ty (double(h)/th), valid (true),
-        count (1) { }
-
-    ~texture_rep (void)
+    opengl_texture (void) : rep (new texture_rep ()) { }
+
+    opengl_texture (const opengl_texture& tx)
+      : rep (tx.rep)
+    {
+      rep->count++;
+    }
+
+    ~opengl_texture (void)
     {
-      if (valid)
-        glDeleteTextures (1, &id);
+      if (--rep->count == 0)
+        delete rep;
     }
 
-    void bind (int mode) const
-    { if (valid) glBindTexture (mode, id); }
+    opengl_texture& operator = (const opengl_texture& tx)
+    {
+      if (--rep->count == 0)
+        delete rep;
+
+      rep = tx.rep;
+      rep->count++;
+
+      return *this;
+    }
+
+    static opengl_texture create (const octave_value& data);
+
+    void bind (int mode = GL_TEXTURE_2D) const
+    { rep->bind (mode); }
 
     void tex_coord (double q, double r) const
-    { if (valid) glTexCoord2d (q*tx, r*ty); }
-
-    GLuint id;
-    int w, h;
-    int tw, th;
-    double tx, ty;
-    bool valid;
-    octave_refcount<int> count;
+    { rep->tex_coord (q, r); }
+
+    bool is_valid (void) const
+    { return rep->valid; }
   };
 
-  texture_rep *rep;
-
-private:
-  opengl_texture (texture_rep *_rep) : rep (_rep) { }
-
-public:
-  opengl_texture (void) : rep (new texture_rep ()) { }
-
-  opengl_texture (const opengl_texture& tx)
-    : rep (tx.rep)
+  opengl_texture
+  opengl_texture::create (const octave_value& data)
   {
-    rep->count++;
-  }
-
-  ~opengl_texture (void)
-  {
-    if (--rep->count == 0)
-      delete rep;
-  }
-
-  opengl_texture& operator = (const opengl_texture& tx)
-  {
-    if (--rep->count == 0)
-      delete rep;
-
-    rep = tx.rep;
-    rep->count++;
-
-    return *this;
+    opengl_texture retval;
+
+    dim_vector dv (data.dims ());
+
+    // Expect RGB data
+    if (dv.ndims () == 3 && dv(2) == 3)
+      {
+        // FIXME: dim_vectors hold octave_idx_type values.
+        //        Should we check for dimensions larger than intmax?
+        int h, w, tw, th;
+        h = dv(0), w = dv(1);
+        GLuint id;
+        bool ok = true;
+
+        tw = next_power_of_2 (w);
+        th = next_power_of_2 (h);
+
+        glGenTextures (1, &id);
+        glBindTexture (GL_TEXTURE_2D, id);
+
+        if (data.is_double_type ())
+          {
+            const NDArray xdata = data.array_value ();
+
+            OCTAVE_LOCAL_BUFFER (float, a, (3*tw*th));
+
+            for (int i = 0; i < h; i++)
+              {
+                for (int j = 0, idx = i*tw*3; j < w; j++, idx += 3)
+                  {
+                    a[idx]   = xdata(i,j,0);
+                    a[idx+1] = xdata(i,j,1);
+                    a[idx+2] = xdata(i,j,2);
+                  }
+              }
+
+            glTexImage2D (GL_TEXTURE_2D, 0, 3, tw, th, 0, GL_RGB, GL_FLOAT, a);
+          }
+        else if (data.is_uint8_type ())
+          {
+            const uint8NDArray xdata = data.uint8_array_value ();
+
+            OCTAVE_LOCAL_BUFFER (octave_uint8, a, (3*tw*th));
+
+            for (int i = 0; i < h; i++)
+              {
+                for (int j = 0, idx = i*tw*3; j < w; j++, idx += 3)
+                  {
+                    a[idx]   = xdata(i,j,0);
+                    a[idx+1] = xdata(i,j,1);
+                    a[idx+2] = xdata(i,j,2);
+                  }
+              }
+
+            glTexImage2D (GL_TEXTURE_2D, 0, 3, tw, th, 0,
+                          GL_RGB, GL_UNSIGNED_BYTE, a);
+          }
+        else
+          {
+            ok = false;
+            warning ("opengl_texture::create: invalid texture data type (double or uint8 required)");
+          }
+
+        if (ok)
+          {
+            glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+            glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+            if (glGetError () != GL_NO_ERROR)
+              warning ("opengl_texture::create: OpenGL error while generating texture data");
+            else
+              retval = opengl_texture (new texture_rep (id, w, h, tw, th));
+          }
+      }
+    else
+      warning ("opengl_texture::create: invalid texture data size");
+
+    return retval;
   }
 
-  static opengl_texture create (const octave_value& data);
-
-  void bind (int mode = GL_TEXTURE_2D) const
-  { rep->bind (mode); }
-
-  void tex_coord (double q, double r) const
-  { rep->tex_coord (q, r); }
-
-  bool is_valid (void) const
-  { return rep->valid; }
-};
-
-opengl_texture
-opengl_texture::create (const octave_value& data)
-{
-  opengl_texture retval;
-
-  dim_vector dv (data.dims ());
-
-  // Expect RGB data
-  if (dv.ndims () == 3 && dv(2) == 3)
+  class
+  opengl_tesselator
+  {
+  public:
+#if defined (HAVE_FRAMEWORK_OPENGL) && defined (HAVE_GLUTESSCALLBACK_THREEDOTS)
+    typedef GLvoid (CALLBACK *fcn) (...);
+#else
+    typedef void (CALLBACK *fcn) (void);
+#endif
+
+  public:
+
+    opengl_tesselator (void) : glu_tess (0), fill () { init (); }
+
+    virtual ~opengl_tesselator (void)
+    { if (glu_tess) gluDeleteTess (glu_tess); }
+
+    void begin_polygon (bool filled = true)
+    {
+      gluTessProperty (glu_tess, GLU_TESS_BOUNDARY_ONLY,
+                       (filled ? GL_FALSE : GL_TRUE));
+      fill = filled;
+      gluTessBeginPolygon (glu_tess, this);
+    }
+
+    void end_polygon (void) const
+    { gluTessEndPolygon (glu_tess); }
+
+    void begin_contour (void) const
+    { gluTessBeginContour (glu_tess); }
+
+    void end_contour (void) const
+    { gluTessEndContour (glu_tess); }
+
+    void add_vertex (double *loc, void *data) const
+    { gluTessVertex (glu_tess, loc, data); }
+
+  protected:
+    virtual void begin (GLenum /*type*/) { }
+
+    virtual void end (void) { }
+
+    virtual void vertex (void * /*data*/) { }
+
+    virtual void combine (GLdouble [3] /*c*/, void * [4] /*data*/,
+                          GLfloat  [4] /*w*/, void ** /*out_data*/) { }
+
+    virtual void edge_flag (GLboolean /*flag*/) { }
+
+    virtual void error (GLenum err)
+    { ::error ("OpenGL tesselation error (%d)", err); }
+
+    virtual void init (void)
+    {
+      glu_tess = gluNewTess ();
+
+      gluTessCallback (glu_tess, GLU_TESS_BEGIN_DATA,
+                       reinterpret_cast<fcn> (tess_begin));
+      gluTessCallback (glu_tess, GLU_TESS_END_DATA,
+                       reinterpret_cast<fcn> (tess_end));
+      gluTessCallback (glu_tess, GLU_TESS_VERTEX_DATA,
+                       reinterpret_cast<fcn> (tess_vertex));
+      gluTessCallback (glu_tess, GLU_TESS_COMBINE_DATA,
+                       reinterpret_cast<fcn> (tess_combine));
+      gluTessCallback (glu_tess, GLU_TESS_EDGE_FLAG_DATA,
+                       reinterpret_cast<fcn> (tess_edge_flag));
+      gluTessCallback (glu_tess, GLU_TESS_ERROR_DATA,
+                       reinterpret_cast<fcn> (tess_error));
+    }
+
+    bool is_filled (void) const { return fill; }
+
+  private:
+    static void CALLBACK tess_begin (GLenum type, void *t)
+    { reinterpret_cast<opengl_tesselator *> (t)->begin (type); }
+
+    static void CALLBACK tess_end (void *t)
+    { reinterpret_cast<opengl_tesselator *> (t)->end (); }
+
+    static void CALLBACK tess_vertex (void *v, void *t)
+    { reinterpret_cast<opengl_tesselator *> (t)->vertex (v); }
+
+    static void CALLBACK tess_combine (GLdouble c[3], void *v[4], GLfloat w[4],
+                                       void **out,  void *t)
+    { reinterpret_cast<opengl_tesselator *> (t)->combine (c, v, w, out); }
+
+    static void CALLBACK tess_edge_flag (GLboolean flag, void *t)
+    { reinterpret_cast<opengl_tesselator *> (t)->edge_flag (flag); }
+
+    static void CALLBACK tess_error (GLenum err, void *t)
+    { reinterpret_cast<opengl_tesselator *> (t)->error (err); }
+
+  private:
+
+    // No copying!
+
+    opengl_tesselator (const opengl_tesselator&);
+
+    opengl_tesselator operator = (const opengl_tesselator&);
+
+    GLUtesselator *glu_tess;
+    bool fill;
+  };
+
+  class
+  vertex_data
+  {
+  public:
+    class vertex_data_rep
     {
-      // FIXME: dim_vectors hold octave_idx_type values.
-      //        Should we check for dimensions larger than intmax?
-      int h, w, tw, th;
-      h = dv(0), w = dv(1);
-      GLuint id;
-      bool ok = true;
-
-      tw = next_power_of_2 (w);
-      th = next_power_of_2 (h);
-
-      glGenTextures (1, &id);
-      glBindTexture (GL_TEXTURE_2D, id);
-
-      if (data.is_double_type ())
+    public:
+      Matrix coords;
+      Matrix color;
+      Matrix normal;
+      double alpha;
+      float ambient;
+      float diffuse;
+      float specular;
+      float specular_exp;
+      float specular_color_refl;
+
+      // reference counter
+      octave_refcount<int> count;
+
+      vertex_data_rep (void)
+        : coords (), color (), normal (), alpha (),
+          ambient (), diffuse (), specular (), specular_exp (),
+          specular_color_refl (), count (1) { }
+
+      vertex_data_rep (const Matrix& c, const Matrix& col, const Matrix& n,
+                       double a, float as, float ds, float ss, float se,
+                       float scr)
+        : coords (c), color (col), normal (n), alpha (a),
+          ambient (as), diffuse (ds), specular (ss), specular_exp (se),
+          specular_color_refl (scr), count (1) { }
+    };
+
+  private:
+    vertex_data_rep *rep;
+
+    vertex_data_rep *nil_rep (void) const
+    {
+      static vertex_data_rep *nr = new vertex_data_rep ();
+
+      return nr;
+    }
+
+  public:
+    vertex_data (void) : rep (nil_rep ())
+    { rep->count++; }
+
+    vertex_data (const vertex_data& v) : rep (v.rep)
+    { rep->count++; }
+
+    vertex_data (const Matrix& c, const Matrix& col, const Matrix& n,
+                 double a, float as, float ds, float ss, float se,
+                 float scr)
+      : rep (new vertex_data_rep (c, col, n, a, as, ds, ss, se, scr))
+    { }
+
+    vertex_data (vertex_data_rep *new_rep)
+      : rep (new_rep) { }
+
+    ~vertex_data (void)
+    {
+      if (--rep->count == 0)
+        delete rep;
+    }
+
+    vertex_data& operator = (const vertex_data& v)
+    {
+      if (--rep->count == 0)
+        delete rep;
+
+      rep = v.rep;
+      rep->count++;
+
+      return *this;
+    }
+
+    vertex_data_rep *get_rep (void) const { return rep; }
+  };
+
+  class
+  opengl_renderer::patch_tesselator : public opengl_tesselator
+  {
+  public:
+    patch_tesselator (opengl_renderer *r, int cmode, int lmode, float idx = 0.0)
+      : opengl_tesselator (), renderer (r),
+        color_mode (cmode), light_mode (lmode), index (idx),
+        first (true), tmp_vdata ()
+    { }
+
+  protected:
+    void begin (GLenum type)
+    {
+      //printf ("patch_tesselator::begin (%d)\n", type);
+      first = true;
+
+      if (color_mode == INTERP || light_mode == GOURAUD)
+        glShadeModel (GL_SMOOTH);
+      else
+        glShadeModel (GL_FLAT);
+
+      if (is_filled ())
+        renderer->set_polygon_offset (true, index);
+
+      glBegin (type);
+    }
+
+    void end (void)
+    {
+      //printf ("patch_tesselator::end\n");
+      glEnd ();
+      renderer->set_polygon_offset (false);
+    }
+
+    void vertex (void *data)
+    {
+      vertex_data::vertex_data_rep *v
+        = reinterpret_cast<vertex_data::vertex_data_rep *> (data);
+      //printf ("patch_tesselator::vertex (%g, %g, %g)\n", v->coords(0), v->coords(1), v->coords(2));
+
+      // NOTE: OpenGL can re-order vertices.  For "flat" coloring of FaceColor
+      // the first vertex must be identified in the draw_patch routine.
+
+      if (color_mode == INTERP || (color_mode == FLAT && ! is_filled ()))
         {
-          const NDArray xdata = data.array_value ();
-
-          OCTAVE_LOCAL_BUFFER (float, a, (3*tw*th));
-
-          for (int i = 0; i < h; i++)
+          Matrix col = v->color;
+
+          if (col.numel () == 3)
             {
-              for (int j = 0, idx = i*tw*3; j < w; j++, idx += 3)
+              glColor3dv (col.data ());
+              if (light_mode > 0)
                 {
-                  a[idx]   = xdata(i,j,0);
-                  a[idx+1] = xdata(i,j,1);
-                  a[idx+2] = xdata(i,j,2);
-                }
-            }
-
-          glTexImage2D (GL_TEXTURE_2D, 0, 3, tw, th, 0, GL_RGB, GL_FLOAT, a);
-        }
-      else if (data.is_uint8_type ())
-        {
-          const uint8NDArray xdata = data.uint8_array_value ();
-
-          OCTAVE_LOCAL_BUFFER (octave_uint8, a, (3*tw*th));
-
-          for (int i = 0; i < h; i++)
-            {
-              for (int j = 0, idx = i*tw*3; j < w; j++, idx += 3)
-                {
-                  a[idx]   = xdata(i,j,0);
-                  a[idx+1] = xdata(i,j,1);
-                  a[idx+2] = xdata(i,j,2);
+                  float buf[4] = { 0, 0, 0, 1 };
+
+                  for (int k = 0; k < 3; k++)
+                    buf[k] = (v->ambient * col(k));
+                  glMaterialfv (LIGHT_MODE, GL_AMBIENT, buf);
+
+                  for (int k = 0; k < 3; k++)
+                    buf[k] = (v->diffuse * col(k));
+                  glMaterialfv (LIGHT_MODE, GL_DIFFUSE, buf);
+
+                  for (int k = 0; k < 3; k++)
+                    buf[k] = v->specular * (v->specular_color_refl +
+                                            (1 - v->specular_color_refl) * col(k));
+                  glMaterialfv (LIGHT_MODE, GL_SPECULAR, buf);
+
                 }
             }
-
-          glTexImage2D (GL_TEXTURE_2D, 0, 3, tw, th, 0,
-                        GL_RGB, GL_UNSIGNED_BYTE, a);
         }
-      else
-        {
-          ok = false;
-          warning ("opengl_texture::create: invalid texture data type (double or uint8 required)");
-        }
-
-      if (ok)
-        {
-          glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-          glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-
-          if (glGetError () != GL_NO_ERROR)
-            warning ("opengl_texture::create: OpenGL error while generating texture data");
-          else
-            retval = opengl_texture (new texture_rep (id, w, h, tw, th));
-        }
+
+      if (light_mode > 0 && (first || light_mode == GOURAUD))
+        glNormal3dv (v->normal.data ());
+
+      glVertex3dv (v->coords.data ());
+
+      first = false;
     }
-  else
-    warning ("opengl_texture::create: invalid texture data size");
-
-  return retval;
-}
-
-class
-opengl_tesselator
-{
-public:
-#if defined (HAVE_FRAMEWORK_OPENGL) && defined (HAVE_GLUTESSCALLBACK_THREEDOTS)
-  typedef GLvoid (CALLBACK *fcn) (...);
-#else
-  typedef void (CALLBACK *fcn) (void);
-#endif
-
-public:
-
-  opengl_tesselator (void) : glu_tess (0), fill () { init (); }
-
-  virtual ~opengl_tesselator (void)
-  { if (glu_tess) gluDeleteTess (glu_tess); }
-
-  void begin_polygon (bool filled = true)
-  {
-    gluTessProperty (glu_tess, GLU_TESS_BOUNDARY_ONLY,
-                     (filled ? GL_FALSE : GL_TRUE));
-    fill = filled;
-    gluTessBeginPolygon (glu_tess, this);
-  }
-
-  void end_polygon (void) const
-  { gluTessEndPolygon (glu_tess); }
-
-  void begin_contour (void) const
-  { gluTessBeginContour (glu_tess); }
-
-  void end_contour (void) const
-  { gluTessEndContour (glu_tess); }
-
-  void add_vertex (double *loc, void *data) const
-  { gluTessVertex (glu_tess, loc, data); }
-
-protected:
-  virtual void begin (GLenum /*type*/) { }
-
-  virtual void end (void) { }
-
-  virtual void vertex (void * /*data*/) { }
-
-  virtual void combine (GLdouble [3] /*c*/, void * [4] /*data*/,
-                        GLfloat  [4] /*w*/, void ** /*out_data*/) { }
-
-  virtual void edge_flag (GLboolean /*flag*/) { }
-
-  virtual void error (GLenum err)
-  { ::error ("OpenGL tesselation error (%d)", err); }
-
-  virtual void init (void)
-  {
-    glu_tess = gluNewTess ();
-
-    gluTessCallback (glu_tess, GLU_TESS_BEGIN_DATA,
-                     reinterpret_cast<fcn> (tess_begin));
-    gluTessCallback (glu_tess, GLU_TESS_END_DATA,
-                     reinterpret_cast<fcn> (tess_end));
-    gluTessCallback (glu_tess, GLU_TESS_VERTEX_DATA,
-                     reinterpret_cast<fcn> (tess_vertex));
-    gluTessCallback (glu_tess, GLU_TESS_COMBINE_DATA,
-                     reinterpret_cast<fcn> (tess_combine));
-    gluTessCallback (glu_tess, GLU_TESS_EDGE_FLAG_DATA,
-                     reinterpret_cast<fcn> (tess_edge_flag));
-    gluTessCallback (glu_tess, GLU_TESS_ERROR_DATA,
-                     reinterpret_cast<fcn> (tess_error));
-  }
-
-  bool is_filled (void) const { return fill; }
-
-private:
-  static void CALLBACK tess_begin (GLenum type, void *t)
-  { reinterpret_cast<opengl_tesselator *> (t)->begin (type); }
-
-  static void CALLBACK tess_end (void *t)
-  { reinterpret_cast<opengl_tesselator *> (t)->end (); }
-
-  static void CALLBACK tess_vertex (void *v, void *t)
-  { reinterpret_cast<opengl_tesselator *> (t)->vertex (v); }
-
-  static void CALLBACK tess_combine (GLdouble c[3], void *v[4], GLfloat w[4],
-                                     void **out,  void *t)
-  { reinterpret_cast<opengl_tesselator *> (t)->combine (c, v, w, out); }
-
-  static void CALLBACK tess_edge_flag (GLboolean flag, void *t)
-  { reinterpret_cast<opengl_tesselator *> (t)->edge_flag (flag); }
-
-  static void CALLBACK tess_error (GLenum err, void *t)
-  { reinterpret_cast<opengl_tesselator *> (t)->error (err); }
-
-private:
-
-  // No copying!
-
-  opengl_tesselator (const opengl_tesselator&);
-
-  opengl_tesselator operator = (const opengl_tesselator&);
-
-  GLUtesselator *glu_tess;
-  bool fill;
-};
-
-class
-vertex_data
-{
-public:
-  class vertex_data_rep
-  {
-  public:
-    Matrix coords;
-    Matrix color;
-    Matrix normal;
-    double alpha;
-    float ambient;
-    float diffuse;
-    float specular;
-    float specular_exp;
-    float specular_color_refl;
-
-    // reference counter
-    octave_refcount<int> count;
-
-    vertex_data_rep (void)
-      : coords (), color (), normal (), alpha (),
-        ambient (), diffuse (), specular (), specular_exp (),
-        specular_color_refl (), count (1) { }
-
-    vertex_data_rep (const Matrix& c, const Matrix& col, const Matrix& n,
-                     double a, float as, float ds, float ss, float se,
-                     float scr)
-      : coords (c), color (col), normal (n), alpha (a),
-        ambient (as), diffuse (ds), specular (ss), specular_exp (se),
-        specular_color_refl (scr), count (1) { }
+
+    void combine (GLdouble xyz[3], void *data[4], GLfloat w[4], void **out_data)
+    {
+      //printf ("patch_tesselator::combine\n");
+
+      vertex_data::vertex_data_rep *v[4];
+      int vmax = 4;
+
+      for (int i = 0; i < 4; i++)
+        {
+          v[i] = reinterpret_cast<vertex_data::vertex_data_rep *> (data[i]);
+
+          if (vmax == 4 && ! v[i])
+            vmax = i;
+        }
+
+      Matrix vv (1, 3, 0.0);
+      Matrix cc;
+      Matrix nn (1, 3, 0.0);
+      double aa = 0.0;
+
+      vv(0) = xyz[0];
+      vv(1) = xyz[1];
+      vv(2) = xyz[2];
+
+      if (v[0]->color.numel ())
+        {
+          cc.resize (1, 3, 0.0);
+          for (int ic = 0; ic < 3; ic++)
+            for (int iv = 0; iv < vmax; iv++)
+              cc(ic) += (w[iv] * v[iv]->color (ic));
+        }
+
+      if (v[0]->normal.numel () > 0)
+        {
+          for (int in = 0; in < 3; in++)
+            for (int iv = 0; iv < vmax; iv++)
+              nn(in) += (w[iv] * v[iv]->normal (in));
+        }
+
+      for (int iv = 0; iv < vmax; iv++)
+        aa += (w[iv] * v[iv]->alpha);
+
+      vertex_data new_v (vv, cc, nn, aa, v[0]->ambient, v[0]->diffuse,
+                         v[0]->specular, v[0]->specular_exp, v[0]->specular_color_refl);
+      tmp_vdata.push_back (new_v);
+
+      *out_data = new_v.get_rep ();
+    }
+
+  private:
+
+    // No copying!
+
+    patch_tesselator (const patch_tesselator&);
+
+    patch_tesselator& operator = (const patch_tesselator&);
+
+    opengl_renderer *renderer;
+    int color_mode;
+    int light_mode;
+    int index;
+    bool first;
+    std::list<vertex_data> tmp_vdata;
   };
 
-private:
-  vertex_data_rep *rep;
-
-  vertex_data_rep *nil_rep (void) const
-  {
-    static vertex_data_rep *nr = new vertex_data_rep ();
-
-    return nr;
-  }
-
-public:
-  vertex_data (void) : rep (nil_rep ())
-  { rep->count++; }
-
-  vertex_data (const vertex_data& v) : rep (v.rep)
-  { rep->count++; }
-
-  vertex_data (const Matrix& c, const Matrix& col, const Matrix& n,
-               double a, float as, float ds, float ss, float se,
-                     float scr)
-    : rep (new vertex_data_rep (c, col, n, a, as, ds, ss, se, scr))
-  { }
-
-  vertex_data (vertex_data_rep *new_rep)
-    : rep (new_rep) { }
-
-  ~vertex_data (void)
-  {
-    if (--rep->count == 0)
-      delete rep;
-  }
-
-  vertex_data& operator = (const vertex_data& v)
-  {
-    if (--rep->count == 0)
-      delete rep;
-
-    rep = v.rep;
-    rep->count++;
-
-    return *this;
-  }
-
-  vertex_data_rep *get_rep (void) const { return rep; }
-};
-
-class
-opengl_renderer::patch_tesselator : public opengl_tesselator
-{
-public:
-  patch_tesselator (opengl_renderer *r, int cmode, int lmode, float idx = 0.0)
-    : opengl_tesselator (), renderer (r),
-      color_mode (cmode), light_mode (lmode), index (idx),
-      first (true), tmp_vdata ()
-  { }
-
-protected:
-  void begin (GLenum type)
-  {
-    //printf ("patch_tesselator::begin (%d)\n", type);
-    first = true;
-
-    if (color_mode == INTERP || light_mode == GOURAUD)
-      glShadeModel (GL_SMOOTH);
-    else
-      glShadeModel (GL_FLAT);
-
-    if (is_filled ())
-      renderer->set_polygon_offset (true, index);
-
-    glBegin (type);
-  }
-
-  void end (void)
-  {
-    //printf ("patch_tesselator::end\n");
-    glEnd ();
-    renderer->set_polygon_offset (false);
-  }
-
-  void vertex (void *data)
-  {
-    vertex_data::vertex_data_rep *v
-      = reinterpret_cast<vertex_data::vertex_data_rep *> (data);
-    //printf ("patch_tesselator::vertex (%g, %g, %g)\n", v->coords(0), v->coords(1), v->coords(2));
-
-    // NOTE: OpenGL can re-order vertices.  For "flat" coloring of FaceColor
-    // the first vertex must be identified in the draw_patch routine.
-
-    if (color_mode == INTERP || (color_mode == FLAT && ! is_filled ()))
-      {
-        Matrix col = v->color;
-
-        if (col.numel () == 3)
-          {
-            glColor3dv (col.data ());
-            if (light_mode > 0)
-              {
-                float buf[4] = { 0, 0, 0, 1 };
-
-                for (int k = 0; k < 3; k++)
-                  buf[k] = (v->ambient * col(k));
-                glMaterialfv (LIGHT_MODE, GL_AMBIENT, buf);
-
-                for (int k = 0; k < 3; k++)
-                  buf[k] = (v->diffuse * col(k));
-                glMaterialfv (LIGHT_MODE, GL_DIFFUSE, buf);
-
-                for (int k = 0; k < 3; k++)
-                  buf[k] = v->specular * (v->specular_color_refl +
-                           (1 - v->specular_color_refl) * col(k));
-                glMaterialfv (LIGHT_MODE, GL_SPECULAR, buf);
-
-            }
-          }
-      }
-
-    if (light_mode > 0 && (first || light_mode == GOURAUD))
-      glNormal3dv (v->normal.data ());
-
-    glVertex3dv (v->coords.data ());
-
-    first = false;
-  }
-
-  void combine (GLdouble xyz[3], void *data[4], GLfloat w[4], void **out_data)
-  {
-    //printf ("patch_tesselator::combine\n");
-
-    vertex_data::vertex_data_rep *v[4];
-    int vmax = 4;
-
-    for (int i = 0; i < 4; i++)
-      {
-        v[i] = reinterpret_cast<vertex_data::vertex_data_rep *> (data[i]);
-
-        if (vmax == 4 && ! v[i])
-          vmax = i;
-      }
-
-    Matrix vv (1, 3, 0.0);
-    Matrix cc;
-    Matrix nn (1, 3, 0.0);
-    double aa = 0.0;
-
-    vv(0) = xyz[0];
-    vv(1) = xyz[1];
-    vv(2) = xyz[2];
-
-    if (v[0]->color.numel ())
-      {
-        cc.resize (1, 3, 0.0);
-        for (int ic = 0; ic < 3; ic++)
-          for (int iv = 0; iv < vmax; iv++)
-            cc(ic) += (w[iv] * v[iv]->color (ic));
-      }
-
-    if (v[0]->normal.numel () > 0)
-      {
-        for (int in = 0; in < 3; in++)
-          for (int iv = 0; iv < vmax; iv++)
-            nn(in) += (w[iv] * v[iv]->normal (in));
-      }
-
-    for (int iv = 0; iv < vmax; iv++)
-      aa += (w[iv] * v[iv]->alpha);
-
-    vertex_data new_v (vv, cc, nn, aa, v[0]->ambient, v[0]->diffuse,
-                       v[0]->specular, v[0]->specular_exp, v[0]->specular_color_refl);
-    tmp_vdata.push_back (new_v);
-
-    *out_data = new_v.get_rep ();
-  }
-
-private:
-
-  // No copying!
-
-  patch_tesselator (const patch_tesselator&);
-
-  patch_tesselator& operator = (const patch_tesselator&);
-
-  opengl_renderer *renderer;
-  int color_mode;
-  int light_mode;
-  int index;
-  bool first;
-  std::list<vertex_data> tmp_vdata;
-};
-
 #else
 
-class
-opengl_renderer::patch_tesselator
-{
-  // Dummy class.
-};
+  class
+  opengl_renderer::patch_tesselator
+  {
+    // Dummy class.
+  };
 
 #endif
 
 #if defined (HAVE_OPENGL)
 
-static int
-get_maxlights (void)
-{
-
-  static int max_lights = 0;
-
-  // Check actual maximum number of lights possible
-  if (max_lights == 0)
-    {
-      for (max_lights = 0; max_lights < GL_MAX_LIGHTS; max_lights++)
-        {
-          glDisable (GL_LIGHT0 + max_lights);
-          if (glGetError ())
-            break;
-        }
-    }
-
-  return max_lights;
-
-}
+  static int
+  get_maxlights (void)
+  {
+
+    static int max_lights = 0;
+
+    // Check actual maximum number of lights possible
+    if (max_lights == 0)
+      {
+        for (max_lights = 0; max_lights < GL_MAX_LIGHTS; max_lights++)
+          {
+            glDisable (GL_LIGHT0 + max_lights);
+            if (glGetError ())
+              break;
+          }
+      }
+
+    return max_lights;
+
+  }
 
 #endif
 
-opengl_renderer::opengl_renderer (void)
-  : toolkit (), xform (), xmin (), xmax (), ymin (), ymax (),
-    zmin (), zmax (), xZ1 (), xZ2 (), marker_id (), filled_marker_id (),
-    camera_pos (), camera_dir (), interpreter ("none"), txt_renderer ()
-{
-  // This constructor will fail if we don't have OpenGL or if the data
-  // types we assumed in our public interface aren't compatible with the
-  // OpenGL types.
+  opengl_renderer::opengl_renderer (void)
+    : toolkit (), xform (), xmin (), xmax (), ymin (), ymax (),
+      zmin (), zmax (), xZ1 (), xZ2 (), marker_id (), filled_marker_id (),
+      camera_pos (), camera_dir (), interpreter ("none"), txt_renderer ()
+  {
+    // This constructor will fail if we don't have OpenGL or if the data
+    // types we assumed in our public interface aren't compatible with the
+    // OpenGL types.
 
 #if defined (HAVE_OPENGL)
 
-  // Ensure that we can't request an image larger than OpenGL can handle.
-  // FIXME: should we check signed vs. unsigned?
-
-  static bool ok = (sizeof (int) <= sizeof (GLsizei));
-
-  if (! ok)
-    error ("the size of GLsizei is smaller than the size of int");
-
-  // Check actual maximum number of lights possible
-  max_lights = get_maxlights ();
+    // Ensure that we can't request an image larger than OpenGL can handle.
+    // FIXME: should we check signed vs. unsigned?
+
+    static bool ok = (sizeof (int) <= sizeof (GLsizei));
+
+    if (! ok)
+      error ("the size of GLsizei is smaller than the size of int");
+
+    // Check actual maximum number of lights possible
+    max_lights = get_maxlights ();
 
 #else
 
-  err_disabled_feature ("opengl_renderer", "OpenGL");
+    err_disabled_feature ("opengl_renderer", "OpenGL");
 
 #endif
-}
-
-void
-opengl_renderer::draw (const graphics_object& go, bool toplevel)
-{
-  if (! go.valid_object ())
-    return;
-
-  const base_properties& props = go.get_properties ();
-
-  if (! toolkit)
-    toolkit = props.get_toolkit ();
-
-  if (go.isa ("figure"))
-    draw_figure (dynamic_cast<const figure::properties&> (props));
-  else if (go.isa ("axes"))
-    draw_axes (dynamic_cast<const axes::properties&> (props));
-  else if (go.isa ("line"))
-    draw_line (dynamic_cast<const line::properties&> (props));
-  else if (go.isa ("surface"))
-    draw_surface (dynamic_cast<const surface::properties&> (props));
-  else if (go.isa ("patch"))
-    draw_patch (dynamic_cast<const patch::properties&> (props));
-  else if (go.isa ("light"))
-    draw_light (dynamic_cast<const light::properties&> (props));
-  else if (go.isa ("hggroup"))
-    draw_hggroup (dynamic_cast<const hggroup::properties&> (props));
-  else if (go.isa ("text"))
-    draw_text (dynamic_cast<const text::properties&> (props));
-  else if (go.isa ("image"))
-    draw_image (dynamic_cast<const image::properties&> (props));
-  else if (go.isa ("uimenu") || go.isa ("uicontrol")
-           || go.isa ("uicontextmenu") || go.isa ("uitoolbar")
-           || go.isa ("uipushtool") || go.isa ("uitoggletool"))
-    ; // SKIP
-  else if (go.isa ("uipanel"))
-    {
-      if (toplevel)
-        draw_uipanel (dynamic_cast<const uipanel::properties&> (props), go);
-    }
-  else if (go.isa ("uibuttongroup"))
-    {
-      if (toplevel)
-        draw_uibuttongroup (dynamic_cast<const uibuttongroup::properties&> (props), go);
-    }
-  else
-    {
-      warning ("opengl_renderer: cannot render object of type '%s'",
-               props.graphics_object_name ().c_str ());
-    }
-}
+  }
+
+  void
+  opengl_renderer::draw (const graphics_object& go, bool toplevel)
+  {
+    if (! go.valid_object ())
+      return;
+
+    const base_properties& props = go.get_properties ();
+
+    if (! toolkit)
+      toolkit = props.get_toolkit ();
+
+    if (go.isa ("figure"))
+      draw_figure (dynamic_cast<const figure::properties&> (props));
+    else if (go.isa ("axes"))
+      draw_axes (dynamic_cast<const axes::properties&> (props));
+    else if (go.isa ("line"))
+      draw_line (dynamic_cast<const line::properties&> (props));
+    else if (go.isa ("surface"))
+      draw_surface (dynamic_cast<const surface::properties&> (props));
+    else if (go.isa ("patch"))
+      draw_patch (dynamic_cast<const patch::properties&> (props));
+    else if (go.isa ("light"))
+      draw_light (dynamic_cast<const light::properties&> (props));
+    else if (go.isa ("hggroup"))
+      draw_hggroup (dynamic_cast<const hggroup::properties&> (props));
+    else if (go.isa ("text"))
+      draw_text (dynamic_cast<const text::properties&> (props));
+    else if (go.isa ("image"))
+      draw_image (dynamic_cast<const image::properties&> (props));
+    else if (go.isa ("uimenu") || go.isa ("uicontrol")
+             || go.isa ("uicontextmenu") || go.isa ("uitoolbar")
+             || go.isa ("uipushtool") || go.isa ("uitoggletool"))
+      ; // SKIP
+    else if (go.isa ("uipanel"))
+      {
+        if (toplevel)
+          draw_uipanel (dynamic_cast<const uipanel::properties&> (props), go);
+      }
+    else if (go.isa ("uibuttongroup"))
+      {
+        if (toplevel)
+          draw_uibuttongroup (dynamic_cast<const uibuttongroup::properties&> (props), go);
+      }
+    else
+      {
+        warning ("opengl_renderer: cannot render object of type '%s'",
+                 props.graphics_object_name ().c_str ());
+      }
+  }
+
+#if defined (HAVE_OPENGL)
+
+  static std::string
+  gl_get_string (GLenum id)
+  {
+    // This is kind of ugly, but glGetString returns a pointer to GLubyte
+    // and there is no std::string constructor that matches.  Is there a
+    // better way?
+
+    std::ostringstream buf;
+    buf << glGetString (id);
+    return std::string (buf.str ());
+  }
+
+#endif
+
+  void
+  opengl_renderer::draw_figure (const figure::properties& props)
+  {
+    // Initialize OpenGL context
+
+    init_gl_context (props.is_graphicssmoothing (), props.get_color_rgb ());
 
 #if defined (HAVE_OPENGL)
 
-static std::string
-gl_get_string (GLenum id)
-{
-  // This is kind of ugly, but glGetString returns a pointer to GLubyte
-  // and there is no std::string constructor that matches.  Is there a
-  // better way?
-
-  std::ostringstream buf;
-  buf << glGetString (id);
-  return std::string (buf.str ());
-}
+    props.set___gl_extensions__ (gl_get_string (GL_EXTENSIONS));
+    props.set___gl_renderer__ (gl_get_string (GL_RENDERER));
+    props.set___gl_vendor__ (gl_get_string (GL_VENDOR));
+    props.set___gl_version__ (gl_get_string (GL_VERSION));
 
 #endif
 
-void
-opengl_renderer::draw_figure (const figure::properties& props)
-{
-  // Initialize OpenGL context
-
-  init_gl_context (props.is_graphicssmoothing (), props.get_color_rgb ());
-
+    // Draw children
+
+    draw (props.get_all_children (), false);
+  }
+
+  void
+  opengl_renderer::draw_uipanel (const uipanel::properties& props,
+                                 const graphics_object& go)
+  {
+    graphics_object fig = go.get_ancestor ("figure");
+    const figure::properties& figProps =
+      dynamic_cast<const figure::properties&> (fig.get_properties ());
+
+    // Initialize OpenGL context
+
+    init_gl_context (figProps.is_graphicssmoothing (),
+                     props.get_backgroundcolor_rgb ());
+
+    // Draw children
+
+    draw (props.get_all_children (), false);
+  }
+
+  void
+  opengl_renderer::draw_uibuttongroup (const uibuttongroup::properties& props,
+                                       const graphics_object& go)
+  {
+    graphics_object fig = go.get_ancestor ("figure");
+    const figure::properties& figProps =
+      dynamic_cast<const figure::properties&> (fig.get_properties ());
+
+    // Initialize OpenGL context
+
+    init_gl_context (figProps.is_graphicssmoothing (),
+                     props.get_backgroundcolor_rgb ());
+
+    // Draw children
+
+    draw (props.get_all_children (), false);
+  }
+
+  void
+  opengl_renderer::init_gl_context (bool enhanced, const Matrix& c)
+  {
 #if defined (HAVE_OPENGL)
 
-  props.set___gl_extensions__ (gl_get_string (GL_EXTENSIONS));
-  props.set___gl_renderer__ (gl_get_string (GL_RENDERER));
-  props.set___gl_vendor__ (gl_get_string (GL_VENDOR));
-  props.set___gl_version__ (gl_get_string (GL_VERSION));
+    // Initialize OpenGL context
+
+    glEnable (GL_DEPTH_TEST);
+    glDepthFunc (GL_LEQUAL);
+    glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+    glAlphaFunc (GL_GREATER, 0.0f);
+    glEnable (GL_NORMALIZE);
+
+    if (enhanced)
+      {
+        glEnable (GL_BLEND);
+        glEnable (GL_MULTISAMPLE);
+        GLint iMultiSample, iNumSamples;
+        glGetIntegerv (GL_SAMPLE_BUFFERS, &iMultiSample);
+        glGetIntegerv (GL_SAMPLES, &iNumSamples);
+        if (iMultiSample != GL_TRUE || iNumSamples == 0)
+          {
+            // MultiSample not implemented.  Use old-style anti-aliasing
+            glDisable (GL_MULTISAMPLE);
+            glEnable (GL_LINE_SMOOTH);
+            glHint (GL_LINE_SMOOTH_HINT, GL_NICEST);
+          }
+      }
+    else
+      {
+        glDisable (GL_BLEND);
+        glDisable (GL_LINE_SMOOTH);
+      }
+
+    // Clear background
+
+    if (c.numel () >= 3)
+      {
+        glClearColor (c(0), c(1), c(2), 1);
+        glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+      }
+
+#else
+
+    octave_unused_parameter (enhanced);
+    octave_unused_parameter (c);
+
+    // This shouldn't happen because construction of opengl_renderer
+    // objects is supposed to be impossible if OpenGL is not available.
+
+    panic_impossible ();
 
 #endif
-
-  // Draw children
-
-  draw (props.get_all_children (), false);
-}
-
-void
-opengl_renderer::draw_uipanel (const uipanel::properties& props,
-                               const graphics_object& go)
-{
-  graphics_object fig = go.get_ancestor ("figure");
-  const figure::properties& figProps =
-    dynamic_cast<const figure::properties&> (fig.get_properties ());
-
-  // Initialize OpenGL context
-
-  init_gl_context (figProps.is_graphicssmoothing (),
-                   props.get_backgroundcolor_rgb ());
-
-  // Draw children
-
-  draw (props.get_all_children (), false);
-}
-
-void
-opengl_renderer::draw_uibuttongroup (const uibuttongroup::properties& props,
-                                     const graphics_object& go)
-{
-  graphics_object fig = go.get_ancestor ("figure");
-  const figure::properties& figProps =
-    dynamic_cast<const figure::properties&> (fig.get_properties ());
-
-  // Initialize OpenGL context
-
-  init_gl_context (figProps.is_graphicssmoothing (),
-                   props.get_backgroundcolor_rgb ());
-
-  // Draw children
-
-  draw (props.get_all_children (), false);
-}
-
-void
-opengl_renderer::init_gl_context (bool enhanced, const Matrix& c)
-{
+  }
+
+  void
+  opengl_renderer::render_grid (const std::string& gridstyle,
+                                const Matrix& ticks, double lim1, double lim2,
+                                double p1, double p1N, double p2, double p2N,
+                                int xyz, bool is_3D)
+  {
 #if defined (HAVE_OPENGL)
 
-  // Initialize OpenGL context
-
-  glEnable (GL_DEPTH_TEST);
-  glDepthFunc (GL_LEQUAL);
-  glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-  glAlphaFunc (GL_GREATER, 0.0f);
-  glEnable (GL_NORMALIZE);
-
-  if (enhanced)
-    {
-      glEnable (GL_BLEND);
-      glEnable (GL_MULTISAMPLE);
-      GLint iMultiSample, iNumSamples;
-      glGetIntegerv (GL_SAMPLE_BUFFERS, &iMultiSample);
-      glGetIntegerv (GL_SAMPLES, &iNumSamples);
-      if (iMultiSample != GL_TRUE || iNumSamples == 0)
-        {
-          // MultiSample not implemented.  Use old-style anti-aliasing
-          glDisable (GL_MULTISAMPLE);
-          glEnable (GL_LINE_SMOOTH);
-          glHint (GL_LINE_SMOOTH_HINT, GL_NICEST);
-        }
-    }
-  else
-    {
-      glDisable (GL_BLEND);
-      glDisable (GL_LINE_SMOOTH);
-    }
-
-  // Clear background
-
-  if (c.numel () >= 3)
-    {
-      glClearColor (c(0), c(1), c(2), 1);
-      glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-    }
+    set_linestyle (gridstyle, true);
+    glBegin (GL_LINES);
+    for (int i = 0; i < ticks.numel (); i++)
+      {
+        double val = ticks(i);
+        if (lim1 <= val && val <= lim2)
+          {
+            if (xyz == X_AXIS)
+              {
+                glVertex3d (val, p1N, p2);
+                glVertex3d (val, p1, p2);
+                if (is_3D)
+                  {
+                    glVertex3d (val, p1, p2N);
+                    glVertex3d (val, p1, p2);
+                  }
+              }
+            else if (xyz == Y_AXIS)
+              {
+                glVertex3d (p1N, val, p2);
+                glVertex3d (p1, val, p2);
+                if (is_3D)
+                  {
+                    glVertex3d (p1, val, p2N);
+                    glVertex3d (p1, val, p2);
+                  }
+              }
+            else if (xyz == Z_AXIS)
+              {
+                glVertex3d (p1N, p2, val);
+                glVertex3d (p1, p2, val);
+                glVertex3d (p1, p2N, val);
+                glVertex3d (p1, p2, val);
+              }
+          }
+      }
+    glEnd ();
+    set_linestyle ("-", true);
+
+#else
+
+    octave_unused_parameter (gridstyle);
+    octave_unused_parameter (ticks);
+    octave_unused_parameter (lim1);
+    octave_unused_parameter (lim2);
+    octave_unused_parameter (p1);
+    octave_unused_parameter (p1N);
+    octave_unused_parameter (p2);
+    octave_unused_parameter (p2N);
+    octave_unused_parameter (xyz);
+    octave_unused_parameter (is_3D);
+
+    // This shouldn't happen because construction of opengl_renderer
+    // objects is supposed to be impossible if OpenGL is not available.
+
+    panic_impossible ();
+
+#endif
+  }
+
+  void
+  opengl_renderer::render_tickmarks (const Matrix& ticks,
+                                     double lim1, double lim2,
+                                     double p1, double p1N,
+                                     double p2, double p2N,
+                                     double dx, double dy, double dz,
+                                     int xyz, bool mirror)
+  {
+#if defined (HAVE_OPENGL)
+
+    glBegin (GL_LINES);
+
+    for (int i = 0; i < ticks.numel (); i++)
+      {
+        double val = ticks(i);
+
+        if (lim1 <= val && val <= lim2)
+          {
+            if (xyz == X_AXIS)
+              {
+                glVertex3d (val, p1, p2);
+                glVertex3d (val, p1+dy, p2+dz);
+                if (mirror)
+                  {
+                    glVertex3d (val, p1N, p2N);
+                    glVertex3d (val, p1N-dy, p2N-dz);
+                  }
+              }
+            else if (xyz == Y_AXIS)
+              {
+                glVertex3d (p1, val, p2);
+                glVertex3d (p1+dx, val, p2+dz);
+                if (mirror)
+                  {
+                    glVertex3d (p1N, val, p2N);
+                    glVertex3d (p1N-dx, val, p2N-dz);
+                  }
+              }
+            else if (xyz == Z_AXIS)
+              {
+                glVertex3d (p1, p2, val);
+                glVertex3d (p1+dx, p2+dy, val);
+                if (mirror)
+                  {
+                    glVertex3d (p1N, p2N, val);
+                    glVertex3d (p1N-dx, p2N-dy, val);
+                  }
+              }
+          }
+      }
+
+    glEnd ();
 
 #else
 
-  octave_unused_parameter (enhanced);
-  octave_unused_parameter (c);
-
-  // This shouldn't happen because construction of opengl_renderer
-  // objects is supposed to be impossible if OpenGL is not available.
-
-  panic_impossible ();
+    octave_unused_parameter (ticks);
+    octave_unused_parameter (lim1);
+    octave_unused_parameter (lim2);
+    octave_unused_parameter (p1);
+    octave_unused_parameter (p1N);
+    octave_unused_parameter (p2);
+    octave_unused_parameter (p2N);
+    octave_unused_parameter (dx);
+    octave_unused_parameter (dy);
+    octave_unused_parameter (dz);
+    octave_unused_parameter (xyz);
+    octave_unused_parameter (mirror);
+
+    // This shouldn't happen because construction of opengl_renderer
+    // objects is supposed to be impossible if OpenGL is not available.
+
+    panic_impossible ();
+
+#endif
+  }
+
+  void
+  opengl_renderer::render_ticktexts (const Matrix& ticks,
+                                     const string_vector& ticklabels,
+                                     double lim1, double lim2,
+                                     double p1, double p2,
+                                     int xyz, int ha, int va,
+                                     int& wmax, int& hmax)
+  {
+#if defined (HAVE_OPENGL)
+
+    int nticks  = ticks.numel ();
+    int nlabels = ticklabels.numel ();
+
+    if (nlabels == 0)
+      return;
+
+    for (int i = 0; i < nticks; i++)
+      {
+        double val = ticks(i);
+
+        if (lim1 <= val && val <= lim2)
+          {
+            Matrix b;
+
+            std::string label (ticklabels(i % nlabels));
+            label.erase (0, label.find_first_not_of (" "));
+            label = label.substr (0, label.find_last_not_of (" ")+1);
+
+            // FIXME: As tick text is transparent, shouldn't it be
+            //        drawn after axes object, for correct rendering?
+            if (xyz == X_AXIS)
+              {
+                b = render_text (label, val, p1, p2, ha, va);
+              }
+            else if (xyz == Y_AXIS)
+              {
+                b = render_text (label, p1, val, p2, ha, va);
+              }
+            else if (xyz == Z_AXIS)
+              {
+                b = render_text (label, p1, p2, val, ha, va);
+              }
+
+            wmax = std::max (wmax, static_cast<int> (b(2)));
+            hmax = std::max (hmax, static_cast<int> (b(3)));
+          }
+      }
+
+#else
+
+    octave_unused_parameter (ticks);
+    octave_unused_parameter (ticklabels);
+    octave_unused_parameter (lim1);
+    octave_unused_parameter (lim2);
+    octave_unused_parameter (p1);
+    octave_unused_parameter (p2);
+    octave_unused_parameter (xyz);
+    octave_unused_parameter (ha);
+    octave_unused_parameter (va);
+    octave_unused_parameter (wmax);
+    octave_unused_parameter (hmax);
+
+    // This shouldn't happen because construction of opengl_renderer
+    // objects is supposed to be impossible if OpenGL is not available.
+
+    panic_impossible ();
+
+#endif
+  }
+
+  void
+  opengl_renderer::finish (void)
+  {
+#if defined (HAVE_OPENGL)
+
+    glFinish ();
+
+#else
+
+    // This shouldn't happen because construction of opengl_renderer
+    // objects is supposed to be impossible if OpenGL is not available.
+
+    panic_impossible ();
 
 #endif
-}
-
-void
-opengl_renderer::render_grid (const std::string& gridstyle,
-                              const Matrix& ticks, double lim1, double lim2,
-                              double p1, double p1N, double p2, double p2N,
-                              int xyz, bool is_3D)
-{
+  }
+
+  void
+  opengl_renderer::setup_opengl_transformation (const axes::properties& props)
+  {
 #if defined (HAVE_OPENGL)
 
-  set_linestyle (gridstyle, true);
-  glBegin (GL_LINES);
-  for (int i = 0; i < ticks.numel (); i++)
-    {
-      double val = ticks(i);
-      if (lim1 <= val && val <= lim2)
-        {
-          if (xyz == X_AXIS)
-            {
-              glVertex3d (val, p1N, p2);
-              glVertex3d (val, p1, p2);
-              if (is_3D)
-                {
-                  glVertex3d (val, p1, p2N);
-                  glVertex3d (val, p1, p2);
-                }
-            }
-          else if (xyz == Y_AXIS)
-            {
-              glVertex3d (p1N, val, p2);
-              glVertex3d (p1, val, p2);
-              if (is_3D)
-                {
-                  glVertex3d (p1, val, p2N);
-                  glVertex3d (p1, val, p2);
-                }
-            }
-          else if (xyz == Z_AXIS)
-            {
-              glVertex3d (p1N, p2, val);
-              glVertex3d (p1, p2, val);
-              glVertex3d (p1, p2N, val);
-              glVertex3d (p1, p2, val);
-            }
-        }
-    }
-  glEnd ();
-  set_linestyle ("-", true);
+    // setup OpenGL transformation
+
+    Matrix x_zlim = props.get_transform_zlim ();
+
+    xZ1 = x_zlim(0)-(x_zlim(1)-x_zlim(0))/2;
+    xZ2 = x_zlim(1)+(x_zlim(1)-x_zlim(0))/2;
+
+    Matrix x_mat1 = props.get_opengl_matrix_1 ();
+    Matrix x_mat2 = props.get_opengl_matrix_2 ();
+
+#if defined (HAVE_FRAMEWORK_OPENGL)
+    GLint vw[4];
+#else
+    int vw[4];
+#endif
+
+    glGetIntegerv (GL_VIEWPORT, vw);
+
+    glMatrixMode (GL_MODELVIEW);
+    glLoadIdentity ();
+    glScaled (1, 1, -1);
+    glMultMatrixd (x_mat1.data ());
+    glMatrixMode (GL_PROJECTION);
+    glLoadIdentity ();
+    glOrtho (0, vw[2], vw[3], 0, xZ1, xZ2);
+    glMultMatrixd (x_mat2.data ());
+    glMatrixMode (GL_MODELVIEW);
+
+    glClear (GL_DEPTH_BUFFER_BIT);
+
+    // store axes transformation data
+
+    xform = props.get_transform ();
 
 #else
 
-  octave_unused_parameter (gridstyle);
-  octave_unused_parameter (ticks);
-  octave_unused_parameter (lim1);
-  octave_unused_parameter (lim2);
-  octave_unused_parameter (p1);
-  octave_unused_parameter (p1N);
-  octave_unused_parameter (p2);
-  octave_unused_parameter (p2N);
-  octave_unused_parameter (xyz);
-  octave_unused_parameter (is_3D);
-
-  // This shouldn't happen because construction of opengl_renderer
-  // objects is supposed to be impossible if OpenGL is not available.
-
-  panic_impossible ();
+    octave_unused_parameter (props);
+
+    // This shouldn't happen because construction of opengl_renderer
+    // objects is supposed to be impossible if OpenGL is not available.
+
+    panic_impossible ();
+
+#endif
+  }
+
+  void
+  opengl_renderer::draw_axes_planes (const axes::properties& props)
+  {
+#if defined (HAVE_OPENGL)
+
+    Matrix axe_color = props.get_color_rgb ();
+    if (axe_color.is_empty () || ! props.is_visible ())
+      return;
+
+    double xPlane = props.get_xPlane ();
+    double yPlane = props.get_yPlane ();
+    double zPlane = props.get_zPlane ();
+    double xPlaneN = props.get_xPlaneN ();
+    double yPlaneN = props.get_yPlaneN ();
+    double zPlaneN = props.get_zPlaneN ();
+    bool is2d = props.get_is2D ();
+
+    // Axes planes
+    set_color (axe_color);
+    set_polygon_offset (true, 2.5);
+
+    glBegin (GL_QUADS);
+
+    if (! is2d)
+      {
+        // X plane
+        glVertex3d (xPlane, yPlaneN, zPlaneN);
+        glVertex3d (xPlane, yPlane, zPlaneN);
+        glVertex3d (xPlane, yPlane, zPlane);
+        glVertex3d (xPlane, yPlaneN, zPlane);
+
+        // Y plane
+        glVertex3d (xPlaneN, yPlane, zPlaneN);
+        glVertex3d (xPlane, yPlane, zPlaneN);
+        glVertex3d (xPlane, yPlane, zPlane);
+        glVertex3d (xPlaneN, yPlane, zPlane);
+      }
+
+    // Z plane
+    glVertex3d (xPlaneN, yPlaneN, zPlane);
+    glVertex3d (xPlane, yPlaneN, zPlane);
+    glVertex3d (xPlane, yPlane, zPlane);
+    glVertex3d (xPlaneN, yPlane, zPlane);
+
+    glEnd ();
+
+    set_polygon_offset (false);
+
+#else
+
+    octave_unused_parameter (props);
+
+    // This shouldn't happen because construction of opengl_renderer
+    // objects is supposed to be impossible if OpenGL is not available.
+
+    panic_impossible ();
 
 #endif
-}
-
-void
-opengl_renderer::render_tickmarks (const Matrix& ticks,
-                                   double lim1, double lim2,
-                                   double p1, double p1N,
-                                   double p2, double p2N,
-                                   double dx, double dy, double dz,
-                                   int xyz, bool mirror)
-{
+  }
+
+  void
+  opengl_renderer::draw_axes_boxes (const axes::properties& props)
+  {
 #if defined (HAVE_OPENGL)
 
-  glBegin (GL_LINES);
-
-  for (int i = 0; i < ticks.numel (); i++)
-    {
-      double val = ticks(i);
-
-      if (lim1 <= val && val <= lim2)
-        {
-          if (xyz == X_AXIS)
-            {
-              glVertex3d (val, p1, p2);
-              glVertex3d (val, p1+dy, p2+dz);
-              if (mirror)
-                {
-                  glVertex3d (val, p1N, p2N);
-                  glVertex3d (val, p1N-dy, p2N-dz);
-                }
-            }
-          else if (xyz == Y_AXIS)
-            {
-              glVertex3d (p1, val, p2);
-              glVertex3d (p1+dx, val, p2+dz);
-              if (mirror)
-                {
-                  glVertex3d (p1N, val, p2N);
-                  glVertex3d (p1N-dx, val, p2N-dz);
-                }
-            }
-          else if (xyz == Z_AXIS)
-            {
-              glVertex3d (p1, p2, val);
-              glVertex3d (p1+dx, p2+dy, val);
-              if (mirror)
-                {
-                  glVertex3d (p1N, p2N, val);
-                  glVertex3d (p1N-dx, p2N-dy, val);
-                }
-            }
-        }
-    }
-
-  glEnd ();
+    if (! props.is_visible ())
+      return;
+
+    bool xySym = props.get_xySym ();
+    bool layer2Dtop = props.get_layer2Dtop ();
+    bool is2d = props.get_is2D ();
+    double xPlane = props.get_xPlane ();
+    double yPlane = props.get_yPlane ();
+    double zPlane = props.get_zPlane ();
+    double xPlaneN = props.get_xPlaneN ();
+    double yPlaneN = props.get_yPlaneN ();
+    double zPlaneN = props.get_zPlaneN ();
+    double xpTick = props.get_xpTick ();
+    double ypTick = props.get_ypTick ();
+    double zpTick = props.get_zpTick ();
+    double xpTickN = props.get_xpTickN ();
+    double ypTickN = props.get_ypTickN ();
+    double zpTickN = props.get_zpTickN ();
+
+    bool plotyy = (props.has_property ("__plotyy_axes__"));
+
+    // Axes box
+
+    set_linestyle ("-", true);
+    set_linewidth (props.get_linewidth ());
+
+    glBegin (GL_LINES);
+
+    if (layer2Dtop)
+      std::swap (zpTick, zpTickN);
+
+    // X box
+    set_color (props.get_xcolor_rgb ());
+    glVertex3d (xPlaneN, ypTick, zpTick);
+    glVertex3d (xPlane, ypTick, zpTick);
+
+    if (props.is_box ())
+      {
+        glVertex3d (xPlaneN, ypTickN, zpTick);
+        glVertex3d (xPlane, ypTickN, zpTick);
+        if (! is2d)
+          {
+            glVertex3d (xPlaneN, ypTickN, zpTickN);
+            glVertex3d (xPlane, ypTickN, zpTickN);
+            glVertex3d (xPlaneN, ypTick, zpTickN);
+            glVertex3d (xPlane, ypTick, zpTickN);
+          }
+      }
+
+    // Y box
+    set_color (props.get_ycolor_rgb ());
+    glVertex3d (xpTick, yPlaneN, zpTick);
+    glVertex3d (xpTick, yPlane, zpTick);
+
+    if (props.is_box () && ! plotyy)
+      {
+        glVertex3d (xpTickN, yPlaneN, zpTick);
+        glVertex3d (xpTickN, yPlane, zpTick);
+
+        if (! is2d)
+          {
+            glVertex3d (xpTickN, yPlaneN, zpTickN);
+            glVertex3d (xpTickN, yPlane, zpTickN);
+            glVertex3d (xpTick, yPlaneN, zpTickN);
+            glVertex3d (xpTick, yPlane, zpTickN);
+          }
+      }
+
+    // Z box
+    if (! is2d)
+      {
+        set_color (props.get_zcolor_rgb ());
+
+        if (xySym)
+          {
+            glVertex3d (xPlaneN, yPlane, zPlaneN);
+            glVertex3d (xPlaneN, yPlane, zPlane);
+          }
+        else
+          {
+            glVertex3d (xPlane, yPlaneN, zPlaneN);
+            glVertex3d (xPlane, yPlaneN, zPlane);
+          }
+
+        if (props.is_box ())
+          {
+            glVertex3d (xPlane, yPlane, zPlaneN);
+            glVertex3d (xPlane, yPlane, zPlane);
+
+            if (xySym)
+              {
+                glVertex3d (xPlane, yPlaneN, zPlaneN);
+                glVertex3d (xPlane, yPlaneN, zPlane);
+              }
+            else
+              {
+                glVertex3d (xPlaneN, yPlane, zPlaneN);
+                glVertex3d (xPlaneN, yPlane, zPlane);
+              }
+
+            glVertex3d (xPlaneN, yPlaneN, zPlaneN);
+            glVertex3d (xPlaneN, yPlaneN, zPlane);
+          }
+      }
+
+    glEnd ();
 
 #else
 
-  octave_unused_parameter (ticks);
-  octave_unused_parameter (lim1);
-  octave_unused_parameter (lim2);
-  octave_unused_parameter (p1);
-  octave_unused_parameter (p1N);
-  octave_unused_parameter (p2);
-  octave_unused_parameter (p2N);
-  octave_unused_parameter (dx);
-  octave_unused_parameter (dy);
-  octave_unused_parameter (dz);
-  octave_unused_parameter (xyz);
-  octave_unused_parameter (mirror);
-
-  // This shouldn't happen because construction of opengl_renderer
-  // objects is supposed to be impossible if OpenGL is not available.
-
-  panic_impossible ();
-
-#endif
-}
-
-void
-opengl_renderer::render_ticktexts (const Matrix& ticks,
-                                   const string_vector& ticklabels,
-                                   double lim1, double lim2,
-                                   double p1, double p2,
-                                   int xyz, int ha, int va,
-                                   int& wmax, int& hmax)
-{
-#if defined (HAVE_OPENGL)
-
-  int nticks  = ticks.numel ();
-  int nlabels = ticklabels.numel ();
-
-  if (nlabels == 0)
-    return;
-
-  for (int i = 0; i < nticks; i++)
-    {
-      double val = ticks(i);
-
-      if (lim1 <= val && val <= lim2)
-        {
-          Matrix b;
-
-          std::string label (ticklabels(i % nlabels));
-          label.erase (0, label.find_first_not_of (" "));
-          label = label.substr (0, label.find_last_not_of (" ")+1);
-
-          // FIXME: As tick text is transparent, shouldn't it be
-          //        drawn after axes object, for correct rendering?
-          if (xyz == X_AXIS)
-            {
-              b = render_text (label, val, p1, p2, ha, va);
-            }
-          else if (xyz == Y_AXIS)
-            {
-              b = render_text (label, p1, val, p2, ha, va);
-            }
-          else if (xyz == Z_AXIS)
-            {
-              b = render_text (label, p1, p2, val, ha, va);
-            }
-
-          wmax = std::max (wmax, static_cast<int> (b(2)));
-          hmax = std::max (hmax, static_cast<int> (b(3)));
-        }
-    }
-
-#else
-
-  octave_unused_parameter (ticks);
-  octave_unused_parameter (ticklabels);
-  octave_unused_parameter (lim1);
-  octave_unused_parameter (lim2);
-  octave_unused_parameter (p1);
-  octave_unused_parameter (p2);
-  octave_unused_parameter (xyz);
-  octave_unused_parameter (ha);
-  octave_unused_parameter (va);
-  octave_unused_parameter (wmax);
-  octave_unused_parameter (hmax);
-
-  // This shouldn't happen because construction of opengl_renderer
-  // objects is supposed to be impossible if OpenGL is not available.
-
-  panic_impossible ();
-
-#endif
-}
-
-void
-opengl_renderer::finish (void)
-{
-#if defined (HAVE_OPENGL)
-
-  glFinish ();
-
-#else
-
-  // This shouldn't happen because construction of opengl_renderer
-  // objects is supposed to be impossible if OpenGL is not available.
-
-  panic_impossible ();
+    octave_unused_parameter (props);
+
+    // This shouldn't happen because construction of opengl_renderer
+    // objects is supposed to be impossible if OpenGL is not available.
+
+    panic_impossible ();
 
 #endif
-}
-
-void
-opengl_renderer::setup_opengl_transformation (const axes::properties& props)
-{
+  }
+
+  void
+  opengl_renderer::draw_axes_x_grid (const axes::properties& props)
+  {
+    int xstate = props.get_xstate ();
+
+    if (props.is_visible () && xstate != AXE_DEPTH_DIR)
+      {
+        int zstate = props.get_zstate ();
+        bool x2Dtop = props.get_x2Dtop ();
+        bool layer2Dtop = props.get_layer2Dtop ();
+        bool xyzSym = props.get_xyzSym ();
+        bool nearhoriz = props.get_nearhoriz ();
+        double xticklen = props.get_xticklen ();
+        double xtickoffset = props.get_xtickoffset ();
+        double fy = props.get_fy ();
+        double fz = props.get_fz ();
+        double x_min = props.get_x_min ();
+        double x_max = props.get_x_max ();
+        double yPlane = props.get_yPlane ();
+        double yPlaneN = props.get_yPlaneN ();
+        double ypTick = props.get_ypTick ();
+        double ypTickN = props.get_ypTickN ();
+        double zPlane = props.get_zPlane ();
+        double zPlaneN = props.get_zPlaneN ();
+        double zpTick = props.get_zpTick ();
+        double zpTickN = props.get_zpTickN ();
+
+        // X grid
+
+        std::string gridstyle = props.get_gridlinestyle ();
+        std::string minorgridstyle = props.get_minorgridlinestyle ();
+        bool do_xgrid = (props.is_xgrid () && (gridstyle != "none"));
+        bool do_xminorgrid = (props.is_xminorgrid ()
+                              && (minorgridstyle != "none"));
+        bool do_xminortick = props.is_xminortick ();
+        Matrix xticks = xform.xscale (props.get_xtick ().matrix_value ());
+        Matrix xmticks = xform.xscale (props.get_xmtick ().matrix_value ());
+        string_vector xticklabels = props.get_xticklabel ().string_vector_value ();
+        int wmax = 0;
+        int hmax = 0;
+        bool tick_along_z = nearhoriz || octave::math::isinf (fy);
+        bool mirror = props.is_box () && xstate != AXE_ANY_DIR;
+
+        set_color (props.get_xcolor_rgb ());
+
+        // grid lines
+        if (do_xgrid)
+          render_grid (gridstyle, xticks, x_min, x_max,
+                       yPlane, yPlaneN, layer2Dtop ? zPlaneN : zPlane,
+                       zPlaneN, 0, (zstate != AXE_DEPTH_DIR));
+
+        // tick marks
+        if (tick_along_z)
+          {
+            render_tickmarks (xticks, x_min, x_max, ypTick, ypTick,
+                              zpTick, zpTickN, 0., 0.,
+                              octave::math::signum (zpTick-zpTickN)*fz*xticklen,
+                              0, mirror);
+          }
+        else
+          {
+            render_tickmarks (xticks, x_min, x_max, ypTick, ypTickN,
+                              zpTick, zpTick, 0.,
+                              octave::math::signum (ypTick-ypTickN)*fy*xticklen,
+                              0., 0, mirror);
+          }
+
+        // tick texts
+        if (xticklabels.numel () > 0)
+          {
+            int halign = (xstate == AXE_HORZ_DIR ? 1 : (xyzSym ? 0 : 2));
+            int valign = (xstate == AXE_VERT_DIR ? 1 : (x2Dtop ? 0 : 2));
+
+            if (tick_along_z)
+              render_ticktexts (xticks, xticklabels, x_min, x_max, ypTick,
+                                zpTick+octave::math::signum (zpTick-zpTickN)*fz*xtickoffset,
+                                0, halign, valign, wmax, hmax);
+            else
+              render_ticktexts (xticks, xticklabels, x_min, x_max,
+                                ypTick+octave::math::signum (ypTick-ypTickN)*fy*xtickoffset,
+                                zpTick, 0, halign, valign, wmax, hmax);
+          }
+
+        // minor grid lines
+        if (do_xminorgrid)
+          render_grid (minorgridstyle, xmticks, x_min, x_max,
+                       yPlane, yPlaneN, layer2Dtop ? zPlaneN : zPlane,
+                       zPlaneN, 0, (zstate != AXE_DEPTH_DIR));
+
+        // minor tick marks
+        if (do_xminortick)
+          {
+            if (tick_along_z)
+              render_tickmarks (xmticks, x_min, x_max, ypTick, ypTick,
+                                zpTick, zpTickN, 0., 0.,
+                                octave::math::signum (zpTick-zpTickN)*fz*xticklen/2,
+                                0, mirror);
+            else
+              render_tickmarks (xmticks, x_min, x_max, ypTick, ypTickN,
+                                zpTick, zpTick, 0.,
+                                octave::math::signum (ypTick-ypTickN)*fy*xticklen/2,
+                                0., 0, mirror);
+          }
+
+        gh_manager::get_object (props.get_xlabel ()).set ("visible", "on");
+      }
+    else
+      gh_manager::get_object (props.get_xlabel ()).set ("visible", "off");
+  }
+
+  void
+  opengl_renderer::draw_axes_y_grid (const axes::properties& props)
+  {
+    int ystate = props.get_ystate ();
+
+    if (ystate != AXE_DEPTH_DIR && props.is_visible ())
+      {
+        int zstate = props.get_zstate ();
+        bool y2Dright = props.get_y2Dright ();
+        bool layer2Dtop = props.get_layer2Dtop ();
+        bool xyzSym = props.get_xyzSym ();
+        bool nearhoriz = props.get_nearhoriz ();
+        double yticklen = props.get_yticklen ();
+        double ytickoffset = props.get_ytickoffset ();
+        double fx = props.get_fx ();
+        double fz = props.get_fz ();
+        double xPlane = props.get_xPlane ();
+        double xPlaneN = props.get_xPlaneN ();
+        double xpTick = props.get_xpTick ();
+        double xpTickN = props.get_xpTickN ();
+        double y_min = props.get_y_min ();
+        double y_max = props.get_y_max ();
+        double zPlane = props.get_zPlane ();
+        double zPlaneN = props.get_zPlaneN ();
+        double zpTick = props.get_zpTick ();
+        double zpTickN = props.get_zpTickN ();
+
+        // Y grid
+
+        std::string gridstyle = props.get_gridlinestyle ();
+        std::string minorgridstyle = props.get_minorgridlinestyle ();
+        bool do_ygrid = (props.is_ygrid () && (gridstyle != "none"));
+        bool do_yminorgrid = (props.is_yminorgrid ()
+                              && (minorgridstyle != "none"));
+        bool do_yminortick = props.is_yminortick ();
+        Matrix yticks = xform.yscale (props.get_ytick ().matrix_value ());
+        Matrix ymticks = xform.yscale (props.get_ymtick ().matrix_value ());
+        string_vector yticklabels = props.get_yticklabel ().string_vector_value ();
+        int wmax = 0;
+        int hmax = 0;
+        bool tick_along_z = nearhoriz || octave::math::isinf (fx);
+        bool mirror = props.is_box () && ystate != AXE_ANY_DIR
+          && (! props.has_property ("__plotyy_axes__"));
+
+        set_color (props.get_ycolor_rgb ());
+
+        // grid lines
+        if (do_ygrid)
+          render_grid (gridstyle, yticks, y_min, y_max,
+                       xPlane, xPlaneN, layer2Dtop ? zPlaneN : zPlane,
+                       zPlaneN, 1, (zstate != AXE_DEPTH_DIR));
+
+        // tick marks
+        if (tick_along_z)
+          render_tickmarks (yticks, y_min, y_max, xpTick, xpTick,
+                            zpTick, zpTickN, 0., 0.,
+                            octave::math::signum (zpTick-zpTickN)*fz*yticklen,
+                            1, mirror);
+        else
+          render_tickmarks (yticks, y_min, y_max, xpTick, xpTickN,
+                            zpTick, zpTick,
+                            octave::math::signum (xPlaneN-xPlane)*fx*yticklen,
+                            0., 0., 1, mirror);
+
+        // tick texts
+        if (yticklabels.numel () > 0)
+          {
+            int halign = (ystate == AXE_HORZ_DIR
+                          ? 1 : (! xyzSym || y2Dright ? 0 : 2));
+            int valign = (ystate == AXE_VERT_DIR ? 1 : 2);
+
+            if (tick_along_z)
+              render_ticktexts (yticks, yticklabels, y_min, y_max, xpTick,
+                                zpTick+octave::math::signum (zpTick-zpTickN)*fz*ytickoffset,
+                                1, halign, valign, wmax, hmax);
+            else
+              render_ticktexts (yticks, yticklabels, y_min, y_max,
+                                xpTick+octave::math::signum (xpTick-xpTickN)*fx*ytickoffset,
+                                zpTick, 1, halign, valign, wmax, hmax);
+          }
+
+        // minor grid lines
+        if (do_yminorgrid)
+          render_grid (minorgridstyle, ymticks, y_min, y_max,
+                       xPlane, xPlaneN, layer2Dtop ? zPlaneN : zPlane,
+                       zPlaneN, 1, (zstate != AXE_DEPTH_DIR));
+
+        // minor tick marks
+        if (do_yminortick)
+          {
+            if (tick_along_z)
+              render_tickmarks (ymticks, y_min, y_max, xpTick, xpTick,
+                                zpTick, zpTickN, 0., 0.,
+                                octave::math::signum (zpTick-zpTickN)*fz*yticklen/2,
+                                1, mirror);
+            else
+              render_tickmarks (ymticks, y_min, y_max, xpTick, xpTickN,
+                                zpTick, zpTick,
+                                octave::math::signum (xpTick-xpTickN)*fx*yticklen/2,
+                                0., 0., 1, mirror);
+          }
+
+        gh_manager::get_object (props.get_ylabel ()).set ("visible", "on");
+      }
+    else
+      gh_manager::get_object (props.get_ylabel ()).set ("visible", "off");
+  }
+
+  void
+  opengl_renderer::draw_axes_z_grid (const axes::properties& props)
+  {
+    int zstate = props.get_zstate ();
+
+    if (zstate != AXE_DEPTH_DIR && props.is_visible ())
+      {
+        bool xySym = props.get_xySym ();
+        bool zSign = props.get_zSign ();
+        double zticklen = props.get_zticklen ();
+        double ztickoffset = props.get_ztickoffset ();
+        double fx = props.get_fx ();
+        double fy = props.get_fy ();
+        double xPlane = props.get_xPlane ();
+        double xPlaneN = props.get_xPlaneN ();
+        double yPlane = props.get_yPlane ();
+        double yPlaneN = props.get_yPlaneN ();
+        double z_min = props.get_z_min ();
+        double z_max = props.get_z_max ();
+
+        // Z Grid
+
+        std::string gridstyle = props.get_gridlinestyle ();
+        std::string minorgridstyle = props.get_minorgridlinestyle ();
+        bool do_zgrid = (props.is_zgrid () && (gridstyle != "none"));
+        bool do_zminorgrid = (props.is_zminorgrid ()
+                              && (minorgridstyle != "none"));
+        bool do_zminortick = props.is_zminortick ();
+        Matrix zticks = xform.zscale (props.get_ztick ().matrix_value ());
+        Matrix zmticks = xform.zscale (props.get_zmtick ().matrix_value ());
+        string_vector zticklabels = props.get_zticklabel ().string_vector_value ();
+        int wmax = 0;
+        int hmax = 0;
+        bool mirror = props.is_box () && zstate != AXE_ANY_DIR;
+
+        set_color (props.get_zcolor_rgb ());
+
+        // grid lines
+        if (do_zgrid)
+          render_grid (gridstyle, zticks, z_min, z_max,
+                       xPlane, xPlaneN, yPlane, yPlaneN, 2, true);
+
+        // tick marks
+        if (xySym)
+          {
+            if (octave::math::isinf (fy))
+              render_tickmarks (zticks, z_min, z_max, xPlaneN, xPlane,
+                                yPlane, yPlane,
+                                octave::math::signum (xPlaneN-xPlane)*fx*zticklen,
+                                0., 0., 2, mirror);
+            else
+              render_tickmarks (zticks, z_min, z_max, xPlaneN, xPlaneN,
+                                yPlane, yPlane, 0.,
+                                octave::math::signum (yPlane-yPlaneN)*fy*zticklen,
+                                0., 2, false);
+          }
+        else
+          {
+            if (octave::math::isinf (fx))
+              render_tickmarks (zticks, z_min, z_max, xPlaneN, xPlane,
+                                yPlaneN, yPlane, 0.,
+                                octave::math::signum (yPlaneN-yPlane)*fy*zticklen,
+                                0., 2, mirror);
+            else
+              render_tickmarks (zticks, z_min, z_max, xPlane, xPlane,
+                                yPlaneN, yPlane,
+                                octave::math::signum (xPlane-xPlaneN)*fx*zticklen,
+                                0., 0., 2, false);
+          }
+
+        // FIXME: tick texts
+        if (zticklabels.numel () > 0)
+          {
+            int halign = 2;
+            int valign = (zstate == AXE_VERT_DIR ? 1 : (zSign ? 3 : 2));
+
+            if (xySym)
+              {
+                if (octave::math::isinf (fy))
+                  render_ticktexts (zticks, zticklabels, z_min, z_max,
+                                    xPlaneN+octave::math::signum (xPlaneN-xPlane)*fx*ztickoffset,
+                                    yPlane, 2, halign, valign, wmax, hmax);
+                else
+                  render_ticktexts (zticks, zticklabels, z_min, z_max, xPlaneN,
+                                    yPlane+octave::math::signum (yPlane-yPlaneN)*fy*ztickoffset,
+                                    2, halign, valign, wmax, hmax);
+              }
+            else
+              {
+                if (octave::math::isinf (fx))
+                  render_ticktexts (zticks, zticklabels, z_min, z_max, xPlane,
+                                    yPlaneN+octave::math::signum (yPlaneN-yPlane)*fy*ztickoffset,
+                                    2, halign, valign, wmax, hmax);
+                else
+                  render_ticktexts (zticks, zticklabels, z_min, z_max,
+                                    xPlane+octave::math::signum (xPlane-xPlaneN)*fx*ztickoffset,
+                                    yPlaneN, 2, halign, valign, wmax, hmax);
+              }
+          }
+
+        // minor grid lines
+        if (do_zminorgrid)
+          render_grid (minorgridstyle, zmticks, z_min, z_max,
+                       xPlane, xPlaneN, yPlane, yPlaneN, 2, true);
+
+        // minor tick marks
+        if (do_zminortick)
+          {
+            if (xySym)
+              {
+                if (octave::math::isinf (fy))
+                  render_tickmarks (zmticks, z_min, z_max, xPlaneN, xPlane,
+                                    yPlane, yPlane,
+                                    octave::math::signum (xPlaneN-xPlane)*fx*zticklen/2,
+                                    0., 0., 2, mirror);
+                else
+                  render_tickmarks (zmticks, z_min, z_max, xPlaneN, xPlaneN,
+                                    yPlane, yPlane, 0.,
+                                    octave::math::signum (yPlane-yPlaneN)*fy*zticklen/2,
+                                    0., 2, false);
+              }
+            else
+              {
+                if (octave::math::isinf (fx))
+                  render_tickmarks (zmticks, z_min, z_max, xPlane, xPlane,
+                                    yPlaneN, yPlane, 0.,
+                                    octave::math::signum (yPlaneN-yPlane)*fy*zticklen/2,
+                                    0., 2, mirror);
+                else
+                  render_tickmarks (zmticks, z_min, z_max, xPlane, xPlane,
+                                    yPlaneN, yPlaneN,
+                                    octave::math::signum (xPlane-xPlaneN)*fx*zticklen/2,
+                                    0., 0., 2, false);
+              }
+          }
+
+        gh_manager::get_object (props.get_zlabel ()).set ("visible", "on");
+      }
+    else
+      gh_manager::get_object (props.get_zlabel ()).set ("visible", "off");
+  }
+
+  void
+  opengl_renderer::draw_all_lights (const base_properties& props, std::list<graphics_object>& obj_list)
+  {
 #if defined (HAVE_OPENGL)
-
-  // setup OpenGL transformation
-
-  Matrix x_zlim = props.get_transform_zlim ();
-
-  xZ1 = x_zlim(0)-(x_zlim(1)-x_zlim(0))/2;
-  xZ2 = x_zlim(1)+(x_zlim(1)-x_zlim(0))/2;
-
-  Matrix x_mat1 = props.get_opengl_matrix_1 ();
-  Matrix x_mat2 = props.get_opengl_matrix_2 ();
-
-#if defined (HAVE_FRAMEWORK_OPENGL)
-  GLint vw[4];
-#else
-  int vw[4];
-#endif
-
-  glGetIntegerv (GL_VIEWPORT, vw);
-
-  glMatrixMode (GL_MODELVIEW);
-  glLoadIdentity ();
-  glScaled (1, 1, -1);
-  glMultMatrixd (x_mat1.data ());
-  glMatrixMode (GL_PROJECTION);
-  glLoadIdentity ();
-  glOrtho (0, vw[2], vw[3], 0, xZ1, xZ2);
-  glMultMatrixd (x_mat2.data ());
-  glMatrixMode (GL_MODELVIEW);
-
-  glClear (GL_DEPTH_BUFFER_BIT);
-
-  // store axes transformation data
-
-  xform = props.get_transform ();
-
+    Matrix children = props.get_all_children ();
+
+    for (octave_idx_type i = children.numel () - 1; i >= 0; i--)
+      {
+        graphics_object go = gh_manager::get_object (children(i));
+
+        if (go.get_properties ().is_visible ())
+          {
+            if (go.isa ("light"))
+              {
+                if (num_lights < max_lights)
+                  {
+                    current_light = GL_LIGHT0 + num_lights;
+                    set_clipping (go.get_properties ().is_clipping ());
+                    draw (go);
+                    num_lights++;
+                  }
+                else
+                  warning_with_id ("Octave:max-lights-exceeded",
+                                   "light: Maximum number of lights (%d) in these axes is "
+                                   "exceeded.", max_lights);
+              }
+            else if (go.isa ("hggroup"))
+              draw_all_lights (go.get_properties (), obj_list);
+            else
+              obj_list.push_back (go);
+          }
+      }
 #else
 
-  octave_unused_parameter (props);
-
-  // This shouldn't happen because construction of opengl_renderer
-  // objects is supposed to be impossible if OpenGL is not available.
-
-  panic_impossible ();
-
-#endif
-}
-
-void
-opengl_renderer::draw_axes_planes (const axes::properties& props)
-{
-#if defined (HAVE_OPENGL)
-
-  Matrix axe_color = props.get_color_rgb ();
-  if (axe_color.is_empty () || ! props.is_visible ())
-    return;
-
-  double xPlane = props.get_xPlane ();
-  double yPlane = props.get_yPlane ();
-  double zPlane = props.get_zPlane ();
-  double xPlaneN = props.get_xPlaneN ();
-  double yPlaneN = props.get_yPlaneN ();
-  double zPlaneN = props.get_zPlaneN ();
-  bool is2d = props.get_is2D ();
-
-  // Axes planes
-  set_color (axe_color);
-  set_polygon_offset (true, 2.5);
-
-  glBegin (GL_QUADS);
-
-  if (! is2d)
-    {
-      // X plane
-      glVertex3d (xPlane, yPlaneN, zPlaneN);
-      glVertex3d (xPlane, yPlane, zPlaneN);
-      glVertex3d (xPlane, yPlane, zPlane);
-      glVertex3d (xPlane, yPlaneN, zPlane);
-
-      // Y plane
-      glVertex3d (xPlaneN, yPlane, zPlaneN);
-      glVertex3d (xPlane, yPlane, zPlaneN);
-      glVertex3d (xPlane, yPlane, zPlane);
-      glVertex3d (xPlaneN, yPlane, zPlane);
-    }
-
-  // Z plane
-  glVertex3d (xPlaneN, yPlaneN, zPlane);
-  glVertex3d (xPlane, yPlaneN, zPlane);
-  glVertex3d (xPlane, yPlane, zPlane);
-  glVertex3d (xPlaneN, yPlane, zPlane);
-
-  glEnd ();
-
-  set_polygon_offset (false);
-
-#else
-
-  octave_unused_parameter (props);
-
-  // This shouldn't happen because construction of opengl_renderer
-  // objects is supposed to be impossible if OpenGL is not available.
-
-  panic_impossible ();
+    octave_unused_parameter (props);
+    octave_unused_parameter (obj_list);
+
+    // This shouldn't happen because construction of opengl_renderer
+    // objects is supposed to be impossible if OpenGL is not available.
+
+    panic_impossible ();
 
 #endif
-}
-
-void
-opengl_renderer::draw_axes_boxes (const axes::properties& props)
-{
+  }
+
+  void
+  opengl_renderer::draw_axes_children (const axes::properties& props)
+  {
 #if defined (HAVE_OPENGL)
-
-  if (! props.is_visible ())
-    return;
-
-  bool xySym = props.get_xySym ();
-  bool layer2Dtop = props.get_layer2Dtop ();
-  bool is2d = props.get_is2D ();
-  double xPlane = props.get_xPlane ();
-  double yPlane = props.get_yPlane ();
-  double zPlane = props.get_zPlane ();
-  double xPlaneN = props.get_xPlaneN ();
-  double yPlaneN = props.get_yPlaneN ();
-  double zPlaneN = props.get_zPlaneN ();
-  double xpTick = props.get_xpTick ();
-  double ypTick = props.get_ypTick ();
-  double zpTick = props.get_zpTick ();
-  double xpTickN = props.get_xpTickN ();
-  double ypTickN = props.get_ypTickN ();
-  double zpTickN = props.get_zpTickN ();
-
-  bool plotyy = (props.has_property ("__plotyy_axes__"));
-
-  // Axes box
-
-  set_linestyle ("-", true);
-  set_linewidth (props.get_linewidth ());
-
-  glBegin (GL_LINES);
-
-  if (layer2Dtop)
-    std::swap (zpTick, zpTickN);
-
-  // X box
-  set_color (props.get_xcolor_rgb ());
-  glVertex3d (xPlaneN, ypTick, zpTick);
-  glVertex3d (xPlane, ypTick, zpTick);
-
-  if (props.is_box ())
-    {
-      glVertex3d (xPlaneN, ypTickN, zpTick);
-      glVertex3d (xPlane, ypTickN, zpTick);
-      if (! is2d)
-        {
-          glVertex3d (xPlaneN, ypTickN, zpTickN);
-          glVertex3d (xPlane, ypTickN, zpTickN);
-          glVertex3d (xPlaneN, ypTick, zpTickN);
-          glVertex3d (xPlane, ypTick, zpTickN);
-        }
-    }
-
-  // Y box
-  set_color (props.get_ycolor_rgb ());
-  glVertex3d (xpTick, yPlaneN, zpTick);
-  glVertex3d (xpTick, yPlane, zpTick);
-
-  if (props.is_box () && ! plotyy)
-    {
-      glVertex3d (xpTickN, yPlaneN, zpTick);
-      glVertex3d (xpTickN, yPlane, zpTick);
-
-      if (! is2d)
-        {
-          glVertex3d (xpTickN, yPlaneN, zpTickN);
-          glVertex3d (xpTickN, yPlane, zpTickN);
-          glVertex3d (xpTick, yPlaneN, zpTickN);
-          glVertex3d (xpTick, yPlane, zpTickN);
-        }
-    }
-
-  // Z box
-  if (! is2d)
-    {
-      set_color (props.get_zcolor_rgb ());
-
-      if (xySym)
-        {
-          glVertex3d (xPlaneN, yPlane, zPlaneN);
-          glVertex3d (xPlaneN, yPlane, zPlane);
-        }
-      else
-        {
-          glVertex3d (xPlane, yPlaneN, zPlaneN);
-          glVertex3d (xPlane, yPlaneN, zPlane);
-        }
-
-      if (props.is_box ())
-        {
-          glVertex3d (xPlane, yPlane, zPlaneN);
-          glVertex3d (xPlane, yPlane, zPlane);
-
-          if (xySym)
-            {
-              glVertex3d (xPlane, yPlaneN, zPlaneN);
-              glVertex3d (xPlane, yPlaneN, zPlane);
-            }
-          else
-            {
-              glVertex3d (xPlaneN, yPlane, zPlaneN);
-              glVertex3d (xPlaneN, yPlane, zPlane);
-            }
-
-          glVertex3d (xPlaneN, yPlaneN, zPlaneN);
-          glVertex3d (xPlaneN, yPlaneN, zPlane);
-        }
-    }
-
-  glEnd ();
+    // list for non-light child objects
+    std::list<graphics_object> obj_list;
+    std::list<graphics_object>::iterator it;
+
+    // 1st pass: draw light objects
+
+    // Start with the last element of the array of child objects to
+    // display them in the order they were added to the array.
+
+    num_lights = 0;
+    draw_all_lights (props, obj_list);
+
+    // disable other OpenGL lights
+    for (int i = num_lights; i < max_lights; i++)
+      glDisable (GL_LIGHT0 + i);
+
+    // save camera position and set ambient light color before drawing
+    // other objects
+    view_vector = props.get_cameraposition ().matrix_value ();
+
+    float cb[4] = { 1.0, 1.0, 1.0, 1.0 };
+    ColumnVector ambient_color = props.get_ambientlightcolor_rgb ();
+    for (int i = 0; i < 3; i++)
+      cb[i] = ambient_color(i);
+    glLightfv (GL_LIGHT0, GL_AMBIENT, cb);
+
+    // 2nd pass: draw other objects (with units set to "data")
+
+    it = obj_list.begin ();
+    while (it != obj_list.end ())
+      {
+        graphics_object go = (*it);
+
+        // FIXME: check whether object has "units" property and it is set
+        // to "data"
+        if (! go.isa ("text") || go.get ("units").string_value () == "data")
+          {
+            set_clipping (go.get_properties ().is_clipping ());
+            draw (go);
+
+            it = obj_list.erase (it);
+          }
+        else
+          it++;
+      }
+
+    // 3rd pass: draw remaining objects
+
+    glDisable (GL_DEPTH_TEST);
+
+    for (it = obj_list.begin (); it != obj_list.end (); it++)
+      {
+        graphics_object go = (*it);
+
+        set_clipping (go.get_properties ().is_clipping ());
+        draw (go);
+      }
+
+    glEnable (GL_DEPTH_TEST);
+
+    set_clipping (false);
+
+    // FIXME: finalize rendering (transparency processing)
+    // FIXME: draw zoom box, if needed
 
 #else
 
-  octave_unused_parameter (props);
-
-  // This shouldn't happen because construction of opengl_renderer
-  // objects is supposed to be impossible if OpenGL is not available.
-
-  panic_impossible ();
+    octave_unused_parameter (props);
+
+    // This shouldn't happen because construction of opengl_renderer
+    // objects is supposed to be impossible if OpenGL is not available.
+
+    panic_impossible ();
 
 #endif
-}
-
-void
-opengl_renderer::draw_axes_x_grid (const axes::properties& props)
-{
-  int xstate = props.get_xstate ();
-
-  if (props.is_visible () && xstate != AXE_DEPTH_DIR)
-    {
-      int zstate = props.get_zstate ();
-      bool x2Dtop = props.get_x2Dtop ();
-      bool layer2Dtop = props.get_layer2Dtop ();
-      bool xyzSym = props.get_xyzSym ();
-      bool nearhoriz = props.get_nearhoriz ();
-      double xticklen = props.get_xticklen ();
-      double xtickoffset = props.get_xtickoffset ();
-      double fy = props.get_fy ();
-      double fz = props.get_fz ();
-      double x_min = props.get_x_min ();
-      double x_max = props.get_x_max ();
-      double yPlane = props.get_yPlane ();
-      double yPlaneN = props.get_yPlaneN ();
-      double ypTick = props.get_ypTick ();
-      double ypTickN = props.get_ypTickN ();
-      double zPlane = props.get_zPlane ();
-      double zPlaneN = props.get_zPlaneN ();
-      double zpTick = props.get_zpTick ();
-      double zpTickN = props.get_zpTickN ();
-
-      // X grid
-
-      std::string gridstyle = props.get_gridlinestyle ();
-      std::string minorgridstyle = props.get_minorgridlinestyle ();
-      bool do_xgrid = (props.is_xgrid () && (gridstyle != "none"));
-      bool do_xminorgrid = (props.is_xminorgrid ()
-                            && (minorgridstyle != "none"));
-      bool do_xminortick = props.is_xminortick ();
-      Matrix xticks = xform.xscale (props.get_xtick ().matrix_value ());
-      Matrix xmticks = xform.xscale (props.get_xmtick ().matrix_value ());
-      string_vector xticklabels = props.get_xticklabel ().string_vector_value ();
-      int wmax = 0;
-      int hmax = 0;
-      bool tick_along_z = nearhoriz || octave::math::isinf (fy);
-      bool mirror = props.is_box () && xstate != AXE_ANY_DIR;
-
-      set_color (props.get_xcolor_rgb ());
-
-      // grid lines
-      if (do_xgrid)
-        render_grid (gridstyle, xticks, x_min, x_max,
-                     yPlane, yPlaneN, layer2Dtop ? zPlaneN : zPlane,
-                     zPlaneN, 0, (zstate != AXE_DEPTH_DIR));
-
-      // tick marks
-      if (tick_along_z)
-        {
-          render_tickmarks (xticks, x_min, x_max, ypTick, ypTick,
-                            zpTick, zpTickN, 0., 0.,
-                            octave::math::signum (zpTick-zpTickN)*fz*xticklen,
-                            0, mirror);
-        }
-      else
-        {
-          render_tickmarks (xticks, x_min, x_max, ypTick, ypTickN,
-                            zpTick, zpTick, 0.,
-                            octave::math::signum (ypTick-ypTickN)*fy*xticklen,
-                            0., 0, mirror);
-        }
-
-      // tick texts
-      if (xticklabels.numel () > 0)
-        {
-          int halign = (xstate == AXE_HORZ_DIR ? 1 : (xyzSym ? 0 : 2));
-          int valign = (xstate == AXE_VERT_DIR ? 1 : (x2Dtop ? 0 : 2));
-
-          if (tick_along_z)
-            render_ticktexts (xticks, xticklabels, x_min, x_max, ypTick,
-                              zpTick+octave::math::signum (zpTick-zpTickN)*fz*xtickoffset,
-                              0, halign, valign, wmax, hmax);
-          else
-            render_ticktexts (xticks, xticklabels, x_min, x_max,
-                              ypTick+octave::math::signum (ypTick-ypTickN)*fy*xtickoffset,
-                              zpTick, 0, halign, valign, wmax, hmax);
-        }
-
-      // minor grid lines
-      if (do_xminorgrid)
-        render_grid (minorgridstyle, xmticks, x_min, x_max,
-                     yPlane, yPlaneN, layer2Dtop ? zPlaneN : zPlane,
-                     zPlaneN, 0, (zstate != AXE_DEPTH_DIR));
-
-      // minor tick marks
-      if (do_xminortick)
-        {
-          if (tick_along_z)
-            render_tickmarks (xmticks, x_min, x_max, ypTick, ypTick,
-                              zpTick, zpTickN, 0., 0.,
-                              octave::math::signum (zpTick-zpTickN)*fz*xticklen/2,
-                              0, mirror);
-          else
-            render_tickmarks (xmticks, x_min, x_max, ypTick, ypTickN,
-                              zpTick, zpTick, 0.,
-                              octave::math::signum (ypTick-ypTickN)*fy*xticklen/2,
-                              0., 0, mirror);
-        }
-
-      gh_manager::get_object (props.get_xlabel ()).set ("visible", "on");
-    }
-  else
-    gh_manager::get_object (props.get_xlabel ()).set ("visible", "off");
-}
-
-void
-opengl_renderer::draw_axes_y_grid (const axes::properties& props)
-{
-  int ystate = props.get_ystate ();
-
-  if (ystate != AXE_DEPTH_DIR && props.is_visible ())
-    {
-      int zstate = props.get_zstate ();
-      bool y2Dright = props.get_y2Dright ();
-      bool layer2Dtop = props.get_layer2Dtop ();
-      bool xyzSym = props.get_xyzSym ();
-      bool nearhoriz = props.get_nearhoriz ();
-      double yticklen = props.get_yticklen ();
-      double ytickoffset = props.get_ytickoffset ();
-      double fx = props.get_fx ();
-      double fz = props.get_fz ();
-      double xPlane = props.get_xPlane ();
-      double xPlaneN = props.get_xPlaneN ();
-      double xpTick = props.get_xpTick ();
-      double xpTickN = props.get_xpTickN ();
-      double y_min = props.get_y_min ();
-      double y_max = props.get_y_max ();
-      double zPlane = props.get_zPlane ();
-      double zPlaneN = props.get_zPlaneN ();
-      double zpTick = props.get_zpTick ();
-      double zpTickN = props.get_zpTickN ();
-
-      // Y grid
-
-      std::string gridstyle = props.get_gridlinestyle ();
-      std::string minorgridstyle = props.get_minorgridlinestyle ();
-      bool do_ygrid = (props.is_ygrid () && (gridstyle != "none"));
-      bool do_yminorgrid = (props.is_yminorgrid ()
-                            && (minorgridstyle != "none"));
-      bool do_yminortick = props.is_yminortick ();
-      Matrix yticks = xform.yscale (props.get_ytick ().matrix_value ());
-      Matrix ymticks = xform.yscale (props.get_ymtick ().matrix_value ());
-      string_vector yticklabels = props.get_yticklabel ().string_vector_value ();
-      int wmax = 0;
-      int hmax = 0;
-      bool tick_along_z = nearhoriz || octave::math::isinf (fx);
-      bool mirror = props.is_box () && ystate != AXE_ANY_DIR
-                    && (! props.has_property ("__plotyy_axes__"));
-
-      set_color (props.get_ycolor_rgb ());
-
-      // grid lines
-      if (do_ygrid)
-        render_grid (gridstyle, yticks, y_min, y_max,
-                     xPlane, xPlaneN, layer2Dtop ? zPlaneN : zPlane,
-                     zPlaneN, 1, (zstate != AXE_DEPTH_DIR));
-
-      // tick marks
-      if (tick_along_z)
-        render_tickmarks (yticks, y_min, y_max, xpTick, xpTick,
-                          zpTick, zpTickN, 0., 0.,
-                          octave::math::signum (zpTick-zpTickN)*fz*yticklen,
-                          1, mirror);
-      else
-        render_tickmarks (yticks, y_min, y_max, xpTick, xpTickN,
-                          zpTick, zpTick,
-                          octave::math::signum (xPlaneN-xPlane)*fx*yticklen,
-                          0., 0., 1, mirror);
-
-      // tick texts
-      if (yticklabels.numel () > 0)
-        {
-          int halign = (ystate == AXE_HORZ_DIR
-                        ? 1 : (! xyzSym || y2Dright ? 0 : 2));
-          int valign = (ystate == AXE_VERT_DIR ? 1 : 2);
-
-          if (tick_along_z)
-            render_ticktexts (yticks, yticklabels, y_min, y_max, xpTick,
-                              zpTick+octave::math::signum (zpTick-zpTickN)*fz*ytickoffset,
-                              1, halign, valign, wmax, hmax);
-          else
-            render_ticktexts (yticks, yticklabels, y_min, y_max,
-                              xpTick+octave::math::signum (xpTick-xpTickN)*fx*ytickoffset,
-                              zpTick, 1, halign, valign, wmax, hmax);
-        }
-
-      // minor grid lines
-      if (do_yminorgrid)
-        render_grid (minorgridstyle, ymticks, y_min, y_max,
-                     xPlane, xPlaneN, layer2Dtop ? zPlaneN : zPlane,
-                     zPlaneN, 1, (zstate != AXE_DEPTH_DIR));
-
-      // minor tick marks
-      if (do_yminortick)
-        {
-          if (tick_along_z)
-            render_tickmarks (ymticks, y_min, y_max, xpTick, xpTick,
-                              zpTick, zpTickN, 0., 0.,
-                              octave::math::signum (zpTick-zpTickN)*fz*yticklen/2,
-                              1, mirror);
-          else
-            render_tickmarks (ymticks, y_min, y_max, xpTick, xpTickN,
-                              zpTick, zpTick,
-                              octave::math::signum (xpTick-xpTickN)*fx*yticklen/2,
-                              0., 0., 1, mirror);
-        }
-
-      gh_manager::get_object (props.get_ylabel ()).set ("visible", "on");
-    }
-  else
-    gh_manager::get_object (props.get_ylabel ()).set ("visible", "off");
-}
-
-void
-opengl_renderer::draw_axes_z_grid (const axes::properties& props)
-{
-  int zstate = props.get_zstate ();
-
-  if (zstate != AXE_DEPTH_DIR && props.is_visible ())
-    {
-      bool xySym = props.get_xySym ();
-      bool zSign = props.get_zSign ();
-      double zticklen = props.get_zticklen ();
-      double ztickoffset = props.get_ztickoffset ();
-      double fx = props.get_fx ();
-      double fy = props.get_fy ();
-      double xPlane = props.get_xPlane ();
-      double xPlaneN = props.get_xPlaneN ();
-      double yPlane = props.get_yPlane ();
-      double yPlaneN = props.get_yPlaneN ();
-      double z_min = props.get_z_min ();
-      double z_max = props.get_z_max ();
-
-      // Z Grid
-
-      std::string gridstyle = props.get_gridlinestyle ();
-      std::string minorgridstyle = props.get_minorgridlinestyle ();
-      bool do_zgrid = (props.is_zgrid () && (gridstyle != "none"));
-      bool do_zminorgrid = (props.is_zminorgrid ()
-                            && (minorgridstyle != "none"));
-      bool do_zminortick = props.is_zminortick ();
-      Matrix zticks = xform.zscale (props.get_ztick ().matrix_value ());
-      Matrix zmticks = xform.zscale (props.get_zmtick ().matrix_value ());
-      string_vector zticklabels = props.get_zticklabel ().string_vector_value ();
-      int wmax = 0;
-      int hmax = 0;
-      bool mirror = props.is_box () && zstate != AXE_ANY_DIR;
-
-      set_color (props.get_zcolor_rgb ());
-
-      // grid lines
-      if (do_zgrid)
-        render_grid (gridstyle, zticks, z_min, z_max,
-                     xPlane, xPlaneN, yPlane, yPlaneN, 2, true);
-
-      // tick marks
-      if (xySym)
-        {
-          if (octave::math::isinf (fy))
-            render_tickmarks (zticks, z_min, z_max, xPlaneN, xPlane,
-                              yPlane, yPlane,
-                              octave::math::signum (xPlaneN-xPlane)*fx*zticklen,
-                              0., 0., 2, mirror);
-          else
-            render_tickmarks (zticks, z_min, z_max, xPlaneN, xPlaneN,
-                              yPlane, yPlane, 0.,
-                              octave::math::signum (yPlane-yPlaneN)*fy*zticklen,
-                              0., 2, false);
-        }
-      else
-        {
-          if (octave::math::isinf (fx))
-            render_tickmarks (zticks, z_min, z_max, xPlaneN, xPlane,
-                              yPlaneN, yPlane, 0.,
-                              octave::math::signum (yPlaneN-yPlane)*fy*zticklen,
-                              0., 2, mirror);
-          else
-            render_tickmarks (zticks, z_min, z_max, xPlane, xPlane,
-                              yPlaneN, yPlane,
-                              octave::math::signum (xPlane-xPlaneN)*fx*zticklen,
-                              0., 0., 2, false);
-        }
-
-      // FIXME: tick texts
-      if (zticklabels.numel () > 0)
-        {
-          int halign = 2;
-          int valign = (zstate == AXE_VERT_DIR ? 1 : (zSign ? 3 : 2));
-
-          if (xySym)
-            {
-              if (octave::math::isinf (fy))
-                render_ticktexts (zticks, zticklabels, z_min, z_max,
-                                  xPlaneN+octave::math::signum (xPlaneN-xPlane)*fx*ztickoffset,
-                                  yPlane, 2, halign, valign, wmax, hmax);
-              else
-                render_ticktexts (zticks, zticklabels, z_min, z_max, xPlaneN,
-                                  yPlane+octave::math::signum (yPlane-yPlaneN)*fy*ztickoffset,
-                                  2, halign, valign, wmax, hmax);
-            }
-          else
-            {
-              if (octave::math::isinf (fx))
-                render_ticktexts (zticks, zticklabels, z_min, z_max, xPlane,
-                                  yPlaneN+octave::math::signum (yPlaneN-yPlane)*fy*ztickoffset,
-                                  2, halign, valign, wmax, hmax);
-              else
-                render_ticktexts (zticks, zticklabels, z_min, z_max,
-                                  xPlane+octave::math::signum (xPlane-xPlaneN)*fx*ztickoffset,
-                                  yPlaneN, 2, halign, valign, wmax, hmax);
-            }
-        }
-
-      // minor grid lines
-      if (do_zminorgrid)
-        render_grid (minorgridstyle, zmticks, z_min, z_max,
-                     xPlane, xPlaneN, yPlane, yPlaneN, 2, true);
-
-      // minor tick marks
-      if (do_zminortick)
-        {
-          if (xySym)
-            {
-              if (octave::math::isinf (fy))
-                render_tickmarks (zmticks, z_min, z_max, xPlaneN, xPlane,
-                                  yPlane, yPlane,
-                                  octave::math::signum (xPlaneN-xPlane)*fx*zticklen/2,
-                                  0., 0., 2, mirror);
-              else
-                render_tickmarks (zmticks, z_min, z_max, xPlaneN, xPlaneN,
-                                  yPlane, yPlane, 0.,
-                                  octave::math::signum (yPlane-yPlaneN)*fy*zticklen/2,
-                                  0., 2, false);
-            }
-          else
-            {
-              if (octave::math::isinf (fx))
-                render_tickmarks (zmticks, z_min, z_max, xPlane, xPlane,
-                                  yPlaneN, yPlane, 0.,
-                                  octave::math::signum (yPlaneN-yPlane)*fy*zticklen/2,
-                                  0., 2, mirror);
-              else
-                render_tickmarks (zmticks, z_min, z_max, xPlane, xPlane,
-                                  yPlaneN, yPlaneN,
-                                  octave::math::signum (xPlane-xPlaneN)*fx*zticklen/2,
-                                  0., 0., 2, false);
-            }
-        }
-
-      gh_manager::get_object (props.get_zlabel ()).set ("visible", "on");
-    }
-  else
-    gh_manager::get_object (props.get_zlabel ()).set ("visible", "off");
-}
-
-void
-opengl_renderer::draw_all_lights (const base_properties& props, std::list<graphics_object>& obj_list)
-{
+  }
+
+  void
+  opengl_renderer::draw_axes (const axes::properties& props)
+  {
 #if defined (HAVE_OPENGL)
-  Matrix children = props.get_all_children ();
-
-  for (octave_idx_type i = children.numel () - 1; i >= 0; i--)
-    {
-      graphics_object go = gh_manager::get_object (children(i));
-
-      if (go.get_properties ().is_visible ())
-        {
-          if (go.isa ("light"))
-            {
-              if (num_lights < max_lights)
-                {
-                  current_light = GL_LIGHT0 + num_lights;
-                  set_clipping (go.get_properties ().is_clipping ());
-                  draw (go);
-                  num_lights++;
-                }
-              else
-                warning_with_id ("Octave:max-lights-exceeded",
-                  "light: Maximum number of lights (%d) in these axes is "
-                  "exceeded.", max_lights);
-            }
-          else if (go.isa ("hggroup"))
-            draw_all_lights (go.get_properties (), obj_list);
-          else
-            obj_list.push_back (go);
-        }
-    }
+
+    // Legends are not drawn when "visible" is "off".
+    if (! props.is_visible () && props.get_tag () == "legend")
+      return;
+
+    static double floatmax = std::numeric_limits<float>::max ();
+
+    double x_min = props.get_x_min ();
+    double x_max = props.get_x_max ();
+    double y_min = props.get_y_min ();
+    double y_max = props.get_y_max ();
+    double z_min = props.get_z_min ();
+    double z_max = props.get_z_max ();
+
+    if (x_max > floatmax || y_max > floatmax || z_max > floatmax
+        || x_min < -floatmax || y_min < -floatmax || z_min < -floatmax)
+      {
+        warning ("opengl_renderer: data values greater than float capacity.  (1) Scale data, or (2) Use gnuplot");
+        return;
+      }
+
+    setup_opengl_transformation (props);
+
+    // Disable line smoothing for axes
+    GLboolean antialias;
+    glGetBooleanv (GL_LINE_SMOOTH, &antialias);
+    if (antialias == GL_TRUE)
+      glDisable (GL_LINE_SMOOTH);
+
+    // draw axes object
+    draw_axes_planes (props);
+    if (props.get_tag () != "legend" || props.get_box () != "off")
+      draw_axes_boxes (props);
+
+    set_font (props);
+    set_interpreter (props.get_ticklabelinterpreter ());
+
+    draw_axes_x_grid (props);
+    draw_axes_y_grid (props);
+    draw_axes_z_grid (props);
+
+    set_linestyle ("-");
+
+    set_clipbox (x_min, x_max, y_min, y_max, z_min, z_max);
+
+    // Re-enable line smoothing for children
+    if (antialias == GL_TRUE)
+      glEnable (GL_LINE_SMOOTH);
+
+    draw_axes_children (props);
+
 #else
 
-  octave_unused_parameter (props);
-  octave_unused_parameter (obj_list);
-
-  // This shouldn't happen because construction of opengl_renderer
-  // objects is supposed to be impossible if OpenGL is not available.
-
-  panic_impossible ();
+    octave_unused_parameter (props);
+
+    // This shouldn't happen because construction of opengl_renderer
+    // objects is supposed to be impossible if OpenGL is not available.
+
+    panic_impossible ();
 
 #endif
-}
-
-void
-opengl_renderer::draw_axes_children (const axes::properties& props)
-{
+  }
+
+  void
+  opengl_renderer::draw_line (const line::properties& props)
+  {
 #if defined (HAVE_OPENGL)
-  // list for non-light child objects
-  std::list<graphics_object> obj_list;
-  std::list<graphics_object>::iterator it;
-
-  // 1st pass: draw light objects
-
-  // Start with the last element of the array of child objects to
-  // display them in the order they were added to the array.
-
-  num_lights = 0;
-  draw_all_lights (props, obj_list);
-
-  // disable other OpenGL lights
-  for (int i = num_lights; i < max_lights; i++)
-    glDisable (GL_LIGHT0 + i);
-
-  // save camera position and set ambient light color before drawing
-  // other objects
-  view_vector = props.get_cameraposition ().matrix_value ();
-
-  float cb[4] = { 1.0, 1.0, 1.0, 1.0 };
-  ColumnVector ambient_color = props.get_ambientlightcolor_rgb ();
-  for (int i = 0; i < 3; i++)
-    cb[i] = ambient_color(i);
-  glLightfv (GL_LIGHT0, GL_AMBIENT, cb);
-
-  // 2nd pass: draw other objects (with units set to "data")
-
-  it = obj_list.begin ();
-  while (it != obj_list.end ())
-    {
-      graphics_object go = (*it);
-
-      // FIXME: check whether object has "units" property and it is set
-      // to "data"
-      if (! go.isa ("text") || go.get ("units").string_value () == "data")
-        {
-          set_clipping (go.get_properties ().is_clipping ());
-          draw (go);
-
-          it = obj_list.erase (it);
-        }
-      else
-        it++;
-    }
-
-  // 3rd pass: draw remaining objects
-
-  glDisable (GL_DEPTH_TEST);
-
-  for (it = obj_list.begin (); it != obj_list.end (); it++)
-    {
-      graphics_object go = (*it);
-
-      set_clipping (go.get_properties ().is_clipping ());
-      draw (go);
-    }
-
-  glEnable (GL_DEPTH_TEST);
-
-  set_clipping (false);
-
-  // FIXME: finalize rendering (transparency processing)
-  // FIXME: draw zoom box, if needed
+
+    Matrix x = xform.xscale (props.get_xdata ().matrix_value ());
+    Matrix y = xform.yscale (props.get_ydata ().matrix_value ());
+    Matrix z = xform.zscale (props.get_zdata ().matrix_value ());
+
+    bool has_z = (z.numel () > 0);
+    int n = static_cast<int> (std::min (std::min (x.numel (), y.numel ()),
+                                        (has_z ? z.numel ()
+                                         : std::numeric_limits<int>::max ())));
+    octave_uint8 clip_mask = (props.is_clipping () ? 0x7F : 0x40), clip_ok (0x40);
+
+    std::vector<octave_uint8> clip (n);
+
+    if (has_z)
+      for (int i = 0; i < n; i++)
+        clip[i] = (clip_code (x(i), y(i), z(i)) & clip_mask);
+    else
+      {
+        double z_mid = (zmin+zmax)/2;
+
+        for (int i = 0; i < n; i++)
+          clip[i] = (clip_code (x(i), y(i), z_mid) & clip_mask);
+      }
+
+    if (! props.linestyle_is ("none") && ! props.color_is ("none"))
+      {
+        set_color (props.get_color_rgb ());
+        set_linestyle (props.get_linestyle (), false);
+        set_linewidth (props.get_linewidth ());
+
+        if (has_z)
+          {
+            bool flag = false;
+
+            for (int i = 1; i < n; i++)
+              {
+                if ((clip[i-1] & clip[i]) == clip_ok)
+                  {
+                    if (! flag)
+                      {
+                        flag = true;
+                        glBegin (GL_LINE_STRIP);
+                        glVertex3d (x(i-1), y(i-1), z(i-1));
+                      }
+                    glVertex3d (x(i), y(i), z(i));
+                  }
+                else if (flag)
+                  {
+                    flag = false;
+                    glEnd ();
+                  }
+              }
+
+            if (flag)
+              glEnd ();
+          }
+        else
+          {
+            bool flag = false;
+
+            for (int i = 1; i < n; i++)
+              {
+                if ((clip[i-1] & clip[i]) == clip_ok)
+                  {
+                    if (! flag)
+                      {
+                        flag = true;
+                        glBegin (GL_LINE_STRIP);
+                        glVertex2d (x(i-1), y(i-1));
+                      }
+                    glVertex2d (x(i), y(i));
+                  }
+                else if (flag)
+                  {
+                    flag = false;
+                    glEnd ();
+                  }
+              }
+
+            if (flag)
+              glEnd ();
+          }
+
+        set_linewidth (0.5);
+        set_linestyle ("-");
+      }
+
+    set_clipping (false);
+
+    if (! props.marker_is ("none")
+        && ! (props.markeredgecolor_is ("none")
+              && props.markerfacecolor_is ("none")))
+      {
+        Matrix lc, fc;
+
+        if (props.markeredgecolor_is ("auto"))
+          lc = props.get_color_rgb ();
+        else if (! props.markeredgecolor_is ("none"))
+          lc = props.get_markeredgecolor_rgb ();
+
+        if (props.markerfacecolor_is ("auto"))
+          fc = props.get_color_rgb ();
+        else if (! props.markerfacecolor_is ("none"))
+          fc = props.get_markerfacecolor_rgb ();
+
+        init_marker (props.get_marker (), props.get_markersize (),
+                     props.get_linewidth ());
+
+        for (int i = 0; i < n; i++)
+          {
+            if (clip[i] == clip_ok)
+              draw_marker (x(i), y(i),
+                           has_z ? z(i) : 0.0,
+                           lc, fc);
+          }
+
+        end_marker ();
+      }
+
+    set_clipping (props.is_clipping ());
 
 #else
 
-  octave_unused_parameter (props);
-
-  // This shouldn't happen because construction of opengl_renderer
-  // objects is supposed to be impossible if OpenGL is not available.
-
-  panic_impossible ();
-
-#endif
-}
-
-void
-opengl_renderer::draw_axes (const axes::properties& props)
-{
-#if defined (HAVE_OPENGL)
-
-  // Legends are not drawn when "visible" is "off".
-  if (! props.is_visible () && props.get_tag () == "legend")
-    return;
-
-  static double floatmax = std::numeric_limits<float>::max ();
-
-  double x_min = props.get_x_min ();
-  double x_max = props.get_x_max ();
-  double y_min = props.get_y_min ();
-  double y_max = props.get_y_max ();
-  double z_min = props.get_z_min ();
-  double z_max = props.get_z_max ();
-
-  if (x_max > floatmax || y_max > floatmax || z_max > floatmax
-      || x_min < -floatmax || y_min < -floatmax || z_min < -floatmax)
-    {
-      warning ("opengl_renderer: data values greater than float capacity.  (1) Scale data, or (2) Use gnuplot");
-      return;
-    }
-
-  setup_opengl_transformation (props);
-
-  // Disable line smoothing for axes
-  GLboolean antialias;
-  glGetBooleanv (GL_LINE_SMOOTH, &antialias);
-  if (antialias == GL_TRUE)
-    glDisable (GL_LINE_SMOOTH);
-
-  // draw axes object
-  draw_axes_planes (props);
-  if (props.get_tag () != "legend" || props.get_box () != "off")
-    draw_axes_boxes (props);
-
-  set_font (props);
-  set_interpreter (props.get_ticklabelinterpreter ());
-
-  draw_axes_x_grid (props);
-  draw_axes_y_grid (props);
-  draw_axes_z_grid (props);
-
-  set_linestyle ("-");
-
-  set_clipbox (x_min, x_max, y_min, y_max, z_min, z_max);
-
-  // Re-enable line smoothing for children
-  if (antialias == GL_TRUE)
-    glEnable (GL_LINE_SMOOTH);
-
-  draw_axes_children (props);
-
-#else
-
-  octave_unused_parameter (props);
-
-  // This shouldn't happen because construction of opengl_renderer
-  // objects is supposed to be impossible if OpenGL is not available.
-
-  panic_impossible ();
+    octave_unused_parameter (props);
+
+    // This shouldn't happen because construction of opengl_renderer
+    // objects is supposed to be impossible if OpenGL is not available.
+
+    panic_impossible ();
 
 #endif
-}
-
-void
-opengl_renderer::draw_line (const line::properties& props)
-{
+  }
+
+  void
+  opengl_renderer::draw_surface (const surface::properties& props)
+  {
 #if defined (HAVE_OPENGL)
 
-  Matrix x = xform.xscale (props.get_xdata ().matrix_value ());
-  Matrix y = xform.yscale (props.get_ydata ().matrix_value ());
-  Matrix z = xform.zscale (props.get_zdata ().matrix_value ());
-
-  bool has_z = (z.numel () > 0);
-  int n = static_cast<int> (std::min (std::min (x.numel (), y.numel ()),
-                                      (has_z ? z.numel ()
-                                             : std::numeric_limits<int>::max ())));
-  octave_uint8 clip_mask = (props.is_clipping () ? 0x7F : 0x40), clip_ok (0x40);
-
-  std::vector<octave_uint8> clip (n);
-
-  if (has_z)
-    for (int i = 0; i < n; i++)
-      clip[i] = (clip_code (x(i), y(i), z(i)) & clip_mask);
-  else
-    {
-      double z_mid = (zmin+zmax)/2;
-
-      for (int i = 0; i < n; i++)
-        clip[i] = (clip_code (x(i), y(i), z_mid) & clip_mask);
-    }
-
-  if (! props.linestyle_is ("none") && ! props.color_is ("none"))
-    {
-      set_color (props.get_color_rgb ());
-      set_linestyle (props.get_linestyle (), false);
-      set_linewidth (props.get_linewidth ());
-
-      if (has_z)
-        {
-          bool flag = false;
-
-          for (int i = 1; i < n; i++)
-            {
-              if ((clip[i-1] & clip[i]) == clip_ok)
-                {
-                  if (! flag)
-                    {
-                      flag = true;
-                      glBegin (GL_LINE_STRIP);
-                      glVertex3d (x(i-1), y(i-1), z(i-1));
-                    }
-                  glVertex3d (x(i), y(i), z(i));
-                }
-              else if (flag)
-                {
-                  flag = false;
-                  glEnd ();
-                }
-            }
-
-          if (flag)
-            glEnd ();
-        }
-      else
-        {
-          bool flag = false;
-
-          for (int i = 1; i < n; i++)
-            {
-              if ((clip[i-1] & clip[i]) == clip_ok)
-                {
-                  if (! flag)
-                    {
-                      flag = true;
-                      glBegin (GL_LINE_STRIP);
-                      glVertex2d (x(i-1), y(i-1));
-                    }
-                  glVertex2d (x(i), y(i));
-                }
-              else if (flag)
-                {
-                  flag = false;
-                  glEnd ();
-                }
-            }
-
-          if (flag)
-            glEnd ();
-        }
-
-      set_linewidth (0.5);
-      set_linestyle ("-");
-    }
-
-  set_clipping (false);
-
-  if (! props.marker_is ("none")
-      && ! (props.markeredgecolor_is ("none")
-            && props.markerfacecolor_is ("none")))
-    {
-      Matrix lc, fc;
-
-      if (props.markeredgecolor_is ("auto"))
-        lc = props.get_color_rgb ();
-      else if (! props.markeredgecolor_is ("none"))
-        lc = props.get_markeredgecolor_rgb ();
-
-      if (props.markerfacecolor_is ("auto"))
-        fc = props.get_color_rgb ();
-      else if (! props.markerfacecolor_is ("none"))
-        fc = props.get_markerfacecolor_rgb ();
-
-      init_marker (props.get_marker (), props.get_markersize (),
-                   props.get_linewidth ());
-
-      for (int i = 0; i < n; i++)
-        {
-          if (clip[i] == clip_ok)
-            draw_marker (x(i), y(i),
-                         has_z ? z(i) : 0.0,
-                         lc, fc);
-        }
-
-      end_marker ();
-    }
-
-  set_clipping (props.is_clipping ());
+    const Matrix x = xform.xscale (props.get_xdata ().matrix_value ());
+    const Matrix y = xform.yscale (props.get_ydata ().matrix_value ());
+    const Matrix z = xform.zscale (props.get_zdata ().matrix_value ());
+
+    int zr = z.rows ();
+    int zc = z.columns ();
+
+    NDArray c;
+    const NDArray n = props.get_vertexnormals ().array_value ();
+
+    // FIXME: handle transparency
+    Matrix a;
+
+    int fc_mode = (props.facecolor_is_rgb () ? 0 :
+                   (props.facecolor_is ("flat") ? 1 :
+                    (props.facecolor_is ("interp") ? 2 :
+                     (props.facecolor_is ("texturemap") ? 3 : -1))));
+    int fl_mode = (props.facelighting_is ("none") ? 0 :
+                   (props.facelighting_is ("flat") ? 1 : 2));
+    int fa_mode = (props.facealpha_is_double () ? 0 :
+                   (props.facealpha_is ("flat") ? 1 : 2));
+    int ec_mode = (props.edgecolor_is_rgb () ? 0 :
+                   (props.edgecolor_is ("flat") ? 1 :
+                    (props.edgecolor_is ("interp") ? 2 : -1)));
+    int el_mode = (props.edgelighting_is ("none") ? 0 :
+                   (props.edgelighting_is ("flat") ? 1 : 2));
+    int ea_mode = (props.edgealpha_is_double () ? 0 :
+                   (props.edgealpha_is ("flat") ? 1 : 2));
+    int bfl_mode = (props.backfacelighting_is ("lit") ? 0 :
+                    (props.backfacelighting_is ("reverselit") ? 1 : 2));
+
+    Matrix fcolor = (fc_mode == TEXTURE ? Matrix (1, 3, 1.0)
+                     : props.get_facecolor_rgb ());
+    Matrix ecolor = props.get_edgecolor_rgb ();
+
+    float as = props.get_ambientstrength ();
+    float ds = props.get_diffusestrength ();
+    float ss = props.get_specularstrength ();
+    float se = props.get_specularexponent () * 5; // to fit Matlab
+    float scr = props.get_specularcolorreflectance ();
+    float cb[4] = { 0.0, 0.0, 0.0, 1.0 };
+
+    opengl_texture tex;
+
+    int i1, i2, j1, j2;
+    bool x_mat = (x.rows () == z.rows ());
+    bool y_mat = (y.columns () == z.columns ());
+
+    i1 = i2 = j1 = j2 = 0;
+
+    if ((fc_mode > 0 && fc_mode < 3) || ec_mode > 0)
+      c = props.get_color_data ().array_value ();
+
+    boolMatrix clip (z.dims (), false);
+
+    for (int i = 0; i < zr; i++)
+      {
+        if (x_mat)
+          i1 = i;
+
+        for (int j = 0; j < zc; j++)
+          {
+            if (y_mat)
+              j1 = j;
+
+            clip(i,j) = is_nan_or_inf (x(i1,j), y(i,j1), z(i,j));
+          }
+      }
+
+    if (fa_mode > 0 || ea_mode > 0)
+      {
+        // FIXME: implement alphadata conversion
+        //a = props.get_alpha_data ();
+      }
+
+    if (fl_mode > 0 || el_mode > 0)
+      glMaterialf (LIGHT_MODE, GL_SHININESS, se);
+
+    // FIXME: good candidate for caching,
+    //        transferring pixel data to OpenGL is time consuming.
+    if (fc_mode == TEXTURE)
+      tex = opengl_texture::create (props.get_color_data ());
+
+    if (! props.facecolor_is ("none"))
+      {
+        if (props.get_facealpha_double () == 1)
+          {
+            if (fc_mode == UNIFORM || fc_mode == TEXTURE)
+              {
+                glColor3dv (fcolor.data ());
+                if (fl_mode > 0)
+                  {
+                    for (int i = 0; i < 3; i++)
+                      cb[i] = as * fcolor(i);
+                    glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
+
+                    for (int i = 0; i < 3; i++)
+                      cb[i] = ds * fcolor(i);
+                    glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
+
+                    for (int i = 0; i < 3; i++)
+                      cb[i] = ss * (scr + (1-scr) * fcolor(i));
+                    glMaterialfv (LIGHT_MODE, GL_SPECULAR, cb);
+                  }
+              }
+
+            if ((fl_mode > 0) && (num_lights > 0))
+              glEnable (GL_LIGHTING);
+            glShadeModel ((fc_mode == INTERP || fl_mode == GOURAUD) ? GL_SMOOTH
+                          : GL_FLAT);
+            set_polygon_offset (true, 1);
+            if (fc_mode == TEXTURE)
+              glEnable (GL_TEXTURE_2D);
+
+            for (int i = 1; i < zc; i++)
+              {
+                if (y_mat)
+                  {
+                    i1 = i-1;
+                    i2 = i;
+                  }
+
+                for (int j = 1; j < zr; j++)
+                  {
+
+                    if (clip(j-1, i-1) || clip(j, i-1)
+                        || clip(j-1, i) || clip(j, i))
+                      continue;
+
+                    if (fc_mode == FLAT)
+                      {
+                        // "flat" only needs color at lower-left vertex
+                        if (! octave::math::finite (c(j-1,i-1)))
+                          continue;
+                      }
+                    else if (fc_mode == INTERP)
+                      {
+                        // "interp" needs valid color at all 4 vertices
+                        if (! (octave::math::finite (c(j-1, i-1)) && octave::math::finite (c(j, i-1))
+                               && octave::math::finite (c(j-1, i)) && octave::math::finite (c(j, i))))
+                          continue;
+                      }
+
+                    if (x_mat)
+                      {
+                        j1 = j-1;
+                        j2 = j;
+                      }
+
+                    glBegin (GL_QUADS);
+
+                    // Vertex 1
+                    if (fc_mode == TEXTURE)
+                      tex.tex_coord (double (i-1) / (zc-1),
+                                     double (j-1) / (zr-1));
+                    else if (fc_mode > 0)
+                      {
+                        // FIXME: is there a smarter way to do this?
+                        for (int k = 0; k < 3; k++)
+                          cb[k] = c(j-1, i-1, k);
+                        glColor3fv (cb);
+
+                        if (fl_mode > 0)
+                          {
+                            for (int k = 0; k < 3; k++)
+                              cb[k] *= as;
+                            glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
+
+                            for (int k = 0; k < 3; k++)
+                              cb[k] = ds * c(j-1, i-1, k);
+                            glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
+
+                            for (int k = 0; k < 3; k++)
+                              cb[k] = ss * (scr + (1-scr) * c(j-1, i-1, k));
+                            glMaterialfv (LIGHT_MODE, GL_SPECULAR, cb);
+                          }
+                      }
+                    if (fl_mode > 0)
+                      set_normal (bfl_mode, n, j-1, i-1);
+
+                    glVertex3d (x(j1,i-1), y(j-1,i1), z(j-1,i-1));
+
+                    // Vertex 2
+                    if (fc_mode == TEXTURE)
+                      tex.tex_coord (double (i) / (zc-1), double (j-1) / (zr-1));
+                    else if (fc_mode == INTERP)
+                      {
+                        for (int k = 0; k < 3; k++)
+                          cb[k] = c(j-1, i, k);
+                        glColor3fv (cb);
+
+                        if (fl_mode > 0)
+                          {
+                            for (int k = 0; k < 3; k++)
+                              cb[k] *= as;
+                            glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
+
+                            for (int k = 0; k < 3; k++)
+                              cb[k] = ds * c(j-1, i, k);
+                            glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
+
+                            for (int k = 0; k < 3; k++)
+                              cb[k] = ss * (scr + (1-scr) * c(j-1, i, k));
+                            glMaterialfv (LIGHT_MODE, GL_SPECULAR, cb);
+                          }
+                      }
+
+                    if (fl_mode == GOURAUD)
+                      set_normal (bfl_mode, n, j-1, i);
+
+                    glVertex3d (x(j1,i), y(j-1,i2), z(j-1,i));
+
+                    // Vertex 3
+                    if (fc_mode == TEXTURE)
+                      tex.tex_coord (double (i) / (zc-1), double (j) / (zr-1));
+                    else if (fc_mode == INTERP)
+                      {
+                        for (int k = 0; k < 3; k++)
+                          cb[k] = c(j, i, k);
+                        glColor3fv (cb);
+
+                        if (fl_mode > 0)
+                          {
+                            for (int k = 0; k < 3; k++)
+                              cb[k] *= as;
+                            glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
+
+                            for (int k = 0; k < 3; k++)
+                              cb[k] = ds * c(j, i, k);
+                            glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
+
+                            for (int k = 0; k < 3; k++)
+                              cb[k] = ss * (scr + (1-scr) * c(j, i, k));
+                            glMaterialfv (LIGHT_MODE, GL_SPECULAR, cb);
+                          }
+                      }
+                    if (fl_mode == GOURAUD)
+                      set_normal (bfl_mode, n, j, i);
+
+                    glVertex3d (x(j2,i), y(j,i2), z(j,i));
+
+                    // Vertex 4
+                    if (fc_mode == TEXTURE)
+                      tex.tex_coord (double (i-1) / (zc-1), double (j) / (zr-1));
+                    else if (fc_mode == INTERP)
+                      {
+                        for (int k = 0; k < 3; k++)
+                          cb[k] = c(j, i-1, k);
+                        glColor3fv (cb);
+
+                        if (fl_mode > 0)
+                          {
+                            for (int k = 0; k < 3; k++)
+                              cb[k] *= as;
+                            glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
+
+                            for (int k = 0; k < 3; k++)
+                              cb[k] = ds * c(j, i-1, k);
+                            glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
+
+                            for (int k = 0; k < 3; k++)
+                              cb[k] = ss * (scr + (1-scr) * c(j, i-1, k));
+                            glMaterialfv (LIGHT_MODE, GL_SPECULAR, cb);
+                          }
+                      }
+                    if (fl_mode == GOURAUD)
+                      set_normal (bfl_mode, n, j, i-1);
+
+                    glVertex3d (x(j2,i-1), y(j,i1), z(j,i-1));
+
+                    glEnd ();
+                  }
+              }
+
+            set_polygon_offset (false);
+            if (fc_mode == TEXTURE)
+              glDisable (GL_TEXTURE_2D);
+
+            if ((fl_mode > 0) && (num_lights > 0))
+              glDisable (GL_LIGHTING);
+          }
+        else
+          {
+            // FIXME: implement transparency
+          }
+      }
+
+    if (! props.edgecolor_is ("none"))
+      {
+        if (props.get_edgealpha_double () == 1)
+          {
+            if (ec_mode == UNIFORM)
+              {
+                glColor3dv (ecolor.data ());
+                if (fl_mode > 0)
+                  {
+                    for (int i = 0; i < 3; i++)
+                      cb[i] = as * ecolor(i);
+                    glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
+
+                    for (int i = 0; i < 3; i++)
+                      cb[i] = ds * ecolor(i);
+                    glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
+
+                    for (int i = 0; i < 3; i++)
+                      cb[i] = ss * (scr + (1-scr) * ecolor(i));
+                    glMaterialfv (LIGHT_MODE, GL_SPECULAR, cb);
+                  }
+              }
+
+            if ((el_mode > 0) && (num_lights > 0))
+              glEnable (GL_LIGHTING);
+            glShadeModel ((ec_mode == INTERP || el_mode == GOURAUD) ? GL_SMOOTH
+                          : GL_FLAT);
+
+            set_linestyle (props.get_linestyle (), false);
+            set_linewidth (props.get_linewidth ());
+
+            // Mesh along Y-axis
+
+            if (props.meshstyle_is ("both") || props.meshstyle_is ("column"))
+              {
+                for (int i = 0; i < zc; i++)
+                  {
+                    if (y_mat)
+                      {
+                        i1 = i-1;
+                        i2 = i;
+                      }
+
+                    for (int j = 1; j < zr; j++)
+                      {
+                        if (clip(j-1,i) || clip(j,i))
+                          continue;
+
+                        if (ec_mode == FLAT)
+                          {
+                            // "flat" only needs color at lower-left vertex
+                            if (! octave::math::finite (c(j-1,i)))
+                              continue;
+                          }
+                        else if (ec_mode == INTERP)
+                          {
+                            // "interp" needs valid color at both vertices
+                            if (! (octave::math::finite (c(j-1, i)) && octave::math::finite (c(j, i))))
+                              continue;
+                          }
+
+                        if (x_mat)
+                          {
+                            j1 = j-1;
+                            j2 = j;
+                          }
+
+                        glBegin (GL_LINES);
+
+                        // Vertex 1
+                        if (ec_mode > 0)
+                          {
+                            for (int k = 0; k < 3; k++)
+                              cb[k] = c(j-1, i, k);
+                            glColor3fv (cb);
+
+                            if (el_mode > 0)
+                              {
+                                for (int k = 0; k < 3; k++)
+                                  cb[k] *= as;
+                                glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
+
+                                for (int k = 0; k < 3; k++)
+                                  cb[k] = ds * c(j-1, i, k);
+                                glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
+
+                                for (int k = 0; k < 3; k++)
+                                  cb[k] = ss * (scr + (1-scr) * c(j-1, i, k));
+                                glMaterialfv (LIGHT_MODE, GL_SPECULAR, cb);
+                              }
+                          }
+                        if (el_mode > 0)
+                          set_normal (bfl_mode, n, j-1, i);
+
+                        glVertex3d (x(j1,i), y(j-1,i2), z(j-1,i));
+
+                        // Vertex 2
+                        if (ec_mode == INTERP)
+                          {
+                            for (int k = 0; k < 3; k++)
+                              cb[k] = c(j, i, k);
+                            glColor3fv (cb);
+
+                            if (el_mode > 0)
+                              {
+                                for (int k = 0; k < 3; k++)
+                                  cb[k] *= as;
+                                glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
+
+                                for (int k = 0; k < 3; k++)
+                                  cb[k] = ds * c(j, i, k);
+                                glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
+
+                                for (int k = 0; k < 3; k++)
+                                  cb[k] = ss * (scr + (1-scr) * c(j, i, k));
+                                glMaterialfv (LIGHT_MODE, GL_SPECULAR, cb);
+                              }
+                          }
+                        if (el_mode == GOURAUD)
+                          set_normal (bfl_mode, n, j, i);
+
+                        glVertex3d (x(j2,i), y(j,i2), z(j,i));
+
+                        glEnd ();
+                      }
+                  }
+              }
+
+            // Mesh along X-axis
+
+            if (props.meshstyle_is ("both") || props.meshstyle_is ("row"))
+              {
+                for (int j = 0; j < zr; j++)
+                  {
+                    if (x_mat)
+                      {
+                        j1 = j-1;
+                        j2 = j;
+                      }
+
+                    for (int i = 1; i < zc; i++)
+                      {
+                        if (clip(j,i-1) || clip(j,i))
+                          continue;
+
+                        if (ec_mode == FLAT)
+                          {
+                            // "flat" only needs color at lower-left vertex
+                            if (! octave::math::finite (c(j,i-1)))
+                              continue;
+                          }
+                        else if (ec_mode == INTERP)
+                          {
+                            // "interp" needs valid color at both vertices
+                            if (! (octave::math::finite (c(j, i-1)) && octave::math::finite (c(j, i))))
+                              continue;
+                          }
+
+                        if (y_mat)
+                          {
+                            i1 = i-1;
+                            i2 = i;
+                          }
+
+                        glBegin (GL_LINES);
+
+                        // Vertex 1
+                        if (ec_mode > 0)
+                          {
+                            for (int k = 0; k < 3; k++)
+                              cb[k] = c(j, i-1, k);
+                            glColor3fv (cb);
+
+                            if (el_mode > 0)
+                              {
+                                for (int k = 0; k < 3; k++)
+                                  cb[k] *= as;
+                                glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
+
+                                for (int k = 0; k < 3; k++)
+                                  cb[k] = ds * c(j, i-1, k);
+                                glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
+
+                                for (int k = 0; k < 3; k++)
+                                  cb[k] = ss * (scr + (1-scr) * c(j, i-1, k));
+                                glMaterialfv (LIGHT_MODE, GL_SPECULAR, cb);
+                              }
+                          }
+                        if (el_mode > 0)
+                          set_normal (bfl_mode, n, j, i-1);
+
+                        glVertex3d (x(j2,i-1), y(j,i1), z(j,i-1));
+
+                        // Vertex 2
+                        if (ec_mode == INTERP)
+                          {
+                            for (int k = 0; k < 3; k++)
+                              cb[k] = c(j, i, k);
+                            glColor3fv (cb);
+
+                            if (el_mode > 0)
+                              {
+                                for (int k = 0; k < 3; k++)
+                                  cb[k] *= as;
+                                glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
+
+                                for (int k = 0; k < 3; k++)
+                                  cb[k] = ds * c(j, i, k);
+                                glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
+
+                                for (int k = 0; k < 3; k++)
+                                  cb[k] = ss * (scr + (1-scr) * c(j, i, k));
+                                glMaterialfv (LIGHT_MODE, GL_SPECULAR, cb);
+                              }
+                          }
+                        if (el_mode == GOURAUD)
+                          set_normal (bfl_mode, n, j, i);
+
+                        glVertex3d (x(j2,i), y(j,i2), z(j,i));
+
+                        glEnd ();
+                      }
+                  }
+              }
+
+            set_linestyle ("-");
+            set_linewidth (0.5);
+
+            if ((el_mode > 0) && (num_lights > 0))
+              glDisable (GL_LIGHTING);
+          }
+        else
+          {
+            // FIXME: implement transparency
+          }
+      }
+
+    if (! props.marker_is ("none")
+        && ! (props.markeredgecolor_is ("none")
+              && props.markerfacecolor_is ("none")))
+      {
+        // FIXME: check how transparency should be handled in markers
+        // FIXME: check what to do with marker facecolor set to auto
+        //        and facecolor set to none.
+
+        bool do_edge = ! props.markeredgecolor_is ("none");
+        bool do_face = ! props.markerfacecolor_is ("none");
+
+        Matrix mecolor = props.get_markeredgecolor_rgb ();
+        Matrix mfcolor = props.get_markerfacecolor_rgb ();
+        Matrix cc (1, 3, 0.0);
+
+        if (mecolor.is_empty () && props.markeredgecolor_is ("auto"))
+          {
+            mecolor = props.get_edgecolor_rgb ();
+            do_edge = ! props.edgecolor_is ("none");
+          }
+
+        if (mfcolor.is_empty () && props.markerfacecolor_is ("auto"))
+          {
+            mfcolor = props.get_facecolor_rgb ();
+            do_face = ! props.facecolor_is ("none");
+          }
+
+        if ((mecolor.is_empty () || mfcolor.is_empty ()) && c.is_empty ())
+          c = props.get_color_data ().array_value ();
+
+        init_marker (props.get_marker (), props.get_markersize (),
+                     props.get_linewidth ());
+
+        for (int i = 0; i < zc; i++)
+          {
+            if (y_mat)
+              i1 = i;
+
+            for (int j = 0; j < zr; j++)
+              {
+                if (clip(j,i))
+                  continue;
+
+                if (x_mat)
+                  j1 = j;
+
+                if ((do_edge && mecolor.is_empty ())
+                    || (do_face && mfcolor.is_empty ()))
+                  {
+                    if (! octave::math::finite (c(j,i)))
+                      continue;  // Skip NaNs in color data
+
+                    for (int k = 0; k < 3; k++)
+                      cc(k) = c(j,i,k);
+                  }
+
+                Matrix lc = (do_edge ? (mecolor.is_empty () ? cc : mecolor)
+                             : Matrix ());
+                Matrix fc = (do_face ? (mfcolor.is_empty () ? cc : mfcolor)
+                             : Matrix ());
+
+                draw_marker (x(j1,i), y(j,i1), z(j,i), lc, fc);
+              }
+          }
+
+        end_marker ();
+      }
 
 #else
 
-  octave_unused_parameter (props);
-
-  // This shouldn't happen because construction of opengl_renderer
-  // objects is supposed to be impossible if OpenGL is not available.
-
-  panic_impossible ();
+    octave_unused_parameter (props);
+
+    // This shouldn't happen because construction of opengl_renderer
+    // objects is supposed to be impossible if OpenGL is not available.
+
+    panic_impossible ();
 
 #endif
-}
-
-void
-opengl_renderer::draw_surface (const surface::properties& props)
-{
+  }
+
+  // FIXME: global optimization (rendering, data structures...),
+  // there is probably a smarter/faster/less-memory-consuming way to do this.
+  void
+  opengl_renderer::draw_patch (const patch::properties &props)
+  {
 #if defined (HAVE_OPENGL)
 
-  const Matrix x = xform.xscale (props.get_xdata ().matrix_value ());
-  const Matrix y = xform.yscale (props.get_ydata ().matrix_value ());
-  const Matrix z = xform.zscale (props.get_zdata ().matrix_value ());
-
-  int zr = z.rows ();
-  int zc = z.columns ();
-
-  NDArray c;
-  const NDArray n = props.get_vertexnormals ().array_value ();
-
-  // FIXME: handle transparency
-  Matrix a;
-
-  int fc_mode = (props.facecolor_is_rgb () ? 0 :
-                 (props.facecolor_is ("flat") ? 1 :
-                  (props.facecolor_is ("interp") ? 2 :
-                   (props.facecolor_is ("texturemap") ? 3 : -1))));
-  int fl_mode = (props.facelighting_is ("none") ? 0 :
-                 (props.facelighting_is ("flat") ? 1 : 2));
-  int fa_mode = (props.facealpha_is_double () ? 0 :
-                 (props.facealpha_is ("flat") ? 1 : 2));
-  int ec_mode = (props.edgecolor_is_rgb () ? 0 :
-                 (props.edgecolor_is ("flat") ? 1 :
-                  (props.edgecolor_is ("interp") ? 2 : -1)));
-  int el_mode = (props.edgelighting_is ("none") ? 0 :
-                 (props.edgelighting_is ("flat") ? 1 : 2));
-  int ea_mode = (props.edgealpha_is_double () ? 0 :
-                 (props.edgealpha_is ("flat") ? 1 : 2));
-  int bfl_mode = (props.backfacelighting_is ("lit") ? 0 :
-                  (props.backfacelighting_is ("reverselit") ? 1 : 2));
-
-  Matrix fcolor = (fc_mode == TEXTURE ? Matrix (1, 3, 1.0)
-                                      : props.get_facecolor_rgb ());
-  Matrix ecolor = props.get_edgecolor_rgb ();
-
-  float as = props.get_ambientstrength ();
-  float ds = props.get_diffusestrength ();
-  float ss = props.get_specularstrength ();
-  float se = props.get_specularexponent () * 5; // to fit Matlab
-  float scr = props.get_specularcolorreflectance ();
-  float cb[4] = { 0.0, 0.0, 0.0, 1.0 };
-
-  opengl_texture tex;
-
-  int i1, i2, j1, j2;
-  bool x_mat = (x.rows () == z.rows ());
-  bool y_mat = (y.columns () == z.columns ());
-
-  i1 = i2 = j1 = j2 = 0;
-
-  if ((fc_mode > 0 && fc_mode < 3) || ec_mode > 0)
-    c = props.get_color_data ().array_value ();
-
-  boolMatrix clip (z.dims (), false);
-
-  for (int i = 0; i < zr; i++)
-    {
-      if (x_mat)
-        i1 = i;
-
-      for (int j = 0; j < zc; j++)
+    // Do not render if the patch has incoherent data
+    std::string msg;
+    if (props.has_bad_data (msg))
+      {
+        warning ("opengl_renderer: %s.  Not rendering.", msg.c_str ());
+        return;
+      }
+
+    const Matrix f = props.get_faces ().matrix_value ();
+    const Matrix v = xform.scale (props.get_vertices ().matrix_value ());
+    Matrix c;
+    const Matrix n = props.get_vertexnormals ().matrix_value ();
+    Matrix a;
+
+    int nv = v.rows ();
+    int nf = f.rows ();
+    int fcmax = f.columns ();
+
+    bool has_z = (v.columns () > 2);
+    bool has_facecolor = false;
+    bool has_facealpha = false;
+    // FIXME: remove when patch object has normal computation (patch #8951)
+    bool has_normals = (n.rows () == nv);
+
+    int fc_mode = ((props.facecolor_is ("none")
+                    || props.facecolor_is_rgb ()) ? 0 :
+                   (props.facecolor_is ("flat") ? 1 : 2));
+    int fl_mode = (props.facelighting_is ("none") ? 0 :
+                   (props.facelighting_is ("flat") ? 1 : 2));
+    int fa_mode = (props.facealpha_is_double () ? 0 :
+                   (props.facealpha_is ("flat") ? 1 : 2));
+    int ec_mode = ((props.edgecolor_is ("none")
+                    || props.edgecolor_is_rgb ()) ? 0 :
+                   (props.edgecolor_is ("flat") ? 1 : 2));
+    int el_mode = (props.edgelighting_is ("none") ? 0 :
+                   (props.edgelighting_is ("flat") ? 1 : 2));
+    int ea_mode = (props.edgealpha_is_double () ? 0 :
+                   (props.edgealpha_is ("flat") ? 1 : 2));
+    int bfl_mode = (props.backfacelighting_is ("lit") ? 0 :
+                    (props.backfacelighting_is ("reverselit") ? 1 : 2));
+
+    Matrix fcolor = props.get_facecolor_rgb ();
+    Matrix ecolor = props.get_edgecolor_rgb ();
+
+    float as = props.get_ambientstrength ();
+    float ds = props.get_diffusestrength ();
+    float ss = props.get_specularstrength ();
+    float se = props.get_specularexponent () * 5; // to fit Matlab
+    float scr = props.get_specularcolorreflectance ();
+
+    boolMatrix clip (1, nv, false);
+
+    if (has_z)
+      for (int i = 0; i < nv; i++)
+        clip(i) = is_nan_or_inf (v(i,0), v(i,1), v(i,2));
+    else
+      for (int i = 0; i < nv; i++)
+        clip(i) = is_nan_or_inf (v(i,0), v(i,1), 0);
+
+    boolMatrix clip_f (1, nf, false);
+    Array<int> count_f (dim_vector (nf, 1), 0);
+
+    for (int i = 0; i < nf; i++)
+      {
+        bool fclip = false;
+        int count = 0;
+
+        for (int j = 0; j < fcmax && ! octave::math::isnan (f(i,j)); j++, count++)
+          fclip = (fclip || clip(int (f(i,j) - 1)));
+
+        clip_f(i) = fclip;
+        count_f(i) = count;
+      }
+
+    if (fc_mode > 0 || ec_mode > 0)
+      {
+        c = props.get_color_data ().matrix_value ();
+
+        if (c.rows () == 1)
+          {
+            // Single color specifications, we can simplify a little bit
+
+            if (fc_mode > 0)
+              {
+                fcolor = c;
+                fc_mode = UNIFORM;
+              }
+
+            if (ec_mode > 0)
+              {
+                ecolor = c;
+                ec_mode = UNIFORM;
+              }
+
+            c = Matrix ();
+          }
+        else
+          has_facecolor = ((c.numel () > 0) && (c.rows () == f.rows ()));
+      }
+
+    if (fa_mode > 0 || ea_mode > 0)
+      {
+        // FIXME: retrieve alpha data from patch object
+        //a = props.get_alpha_data ();
+        has_facealpha = ((a.numel () > 0) && (a.rows () == f.rows ()));
+      }
+
+    octave_idx_type fr = f.rows ();
+    std::vector<vertex_data> vdata (f.numel ());
+
+    for (int i = 0; i < nf; i++)
+      for (int j = 0; j < count_f(i); j++)
         {
-          if (y_mat)
-            j1 = j;
-
-          clip(i,j) = is_nan_or_inf (x(i1,j), y(i,j1), z(i,j));
-        }
-    }
-
-  if (fa_mode > 0 || ea_mode > 0)
-    {
-      // FIXME: implement alphadata conversion
-      //a = props.get_alpha_data ();
-    }
-
-  if (fl_mode > 0 || el_mode > 0)
-    glMaterialf (LIGHT_MODE, GL_SHININESS, se);
-
-  // FIXME: good candidate for caching,
-  //        transferring pixel data to OpenGL is time consuming.
-  if (fc_mode == TEXTURE)
-    tex = opengl_texture::create (props.get_color_data ());
-
-  if (! props.facecolor_is ("none"))
-    {
-      if (props.get_facealpha_double () == 1)
-        {
-          if (fc_mode == UNIFORM || fc_mode == TEXTURE)
-            {
-              glColor3dv (fcolor.data ());
-              if (fl_mode > 0)
-                {
-                  for (int i = 0; i < 3; i++)
-                    cb[i] = as * fcolor(i);
-                  glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
-
-                  for (int i = 0; i < 3; i++)
-                    cb[i] = ds * fcolor(i);
-                  glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
-
-                  for (int i = 0; i < 3; i++)
-                    cb[i] = ss * (scr + (1-scr) * fcolor(i));
-                  glMaterialfv (LIGHT_MODE, GL_SPECULAR, cb);
-                }
-            }
-
-          if ((fl_mode > 0) && (num_lights > 0))
-            glEnable (GL_LIGHTING);
-          glShadeModel ((fc_mode == INTERP || fl_mode == GOURAUD) ? GL_SMOOTH
-                                                                  : GL_FLAT);
-          set_polygon_offset (true, 1);
-          if (fc_mode == TEXTURE)
-            glEnable (GL_TEXTURE_2D);
-
-          for (int i = 1; i < zc; i++)
+          int idx = int (f(i,j) - 1);
+
+          Matrix vv (1, 3, 0.0);
+          Matrix cc;
+          Matrix nn (1, 3, 0.0);
+          double aa = 1.0;
+
+          vv(0) = v(idx,0); vv(1) = v(idx,1);
+          if (has_z)
+            vv(2) = v(idx,2);
+          if (has_normals)
             {
-              if (y_mat)
-                {
-                  i1 = i-1;
-                  i2 = i;
-                }
-
-              for (int j = 1; j < zr; j++)
-                {
-
-                  if (clip(j-1, i-1) || clip(j, i-1)
-                      || clip(j-1, i) || clip(j, i))
-                    continue;
-
-                  if (fc_mode == FLAT)
-                    {
-                      // "flat" only needs color at lower-left vertex
-                      if (! octave::math::finite (c(j-1,i-1)))
-                        continue;
-                    }
-                  else if (fc_mode == INTERP)
-                    {
-                      // "interp" needs valid color at all 4 vertices
-                      if (! (octave::math::finite (c(j-1, i-1)) && octave::math::finite (c(j, i-1))
-                             && octave::math::finite (c(j-1, i)) && octave::math::finite (c(j, i))))
-                        continue;
-                    }
-
-                  if (x_mat)
-                    {
-                      j1 = j-1;
-                      j2 = j;
-                    }
-
-                  glBegin (GL_QUADS);
-
-                  // Vertex 1
-                  if (fc_mode == TEXTURE)
-                    tex.tex_coord (double (i-1) / (zc-1),
-                                   double (j-1) / (zr-1));
-                  else if (fc_mode > 0)
-                    {
-                      // FIXME: is there a smarter way to do this?
-                      for (int k = 0; k < 3; k++)
-                        cb[k] = c(j-1, i-1, k);
-                      glColor3fv (cb);
-
-                      if (fl_mode > 0)
-                        {
-                          for (int k = 0; k < 3; k++)
-                            cb[k] *= as;
-                          glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
-
-                          for (int k = 0; k < 3; k++)
-                            cb[k] = ds * c(j-1, i-1, k);
-                          glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
-
-                          for (int k = 0; k < 3; k++)
-                            cb[k] = ss * (scr + (1-scr) * c(j-1, i-1, k));
-                          glMaterialfv (LIGHT_MODE, GL_SPECULAR, cb);
-                        }
-                    }
-                  if (fl_mode > 0)
-                    set_normal (bfl_mode, n, j-1, i-1);
-
-                  glVertex3d (x(j1,i-1), y(j-1,i1), z(j-1,i-1));
-
-                  // Vertex 2
-                  if (fc_mode == TEXTURE)
-                    tex.tex_coord (double (i) / (zc-1), double (j-1) / (zr-1));
-                  else if (fc_mode == INTERP)
-                    {
-                      for (int k = 0; k < 3; k++)
-                        cb[k] = c(j-1, i, k);
-                      glColor3fv (cb);
-
-                      if (fl_mode > 0)
-                        {
-                          for (int k = 0; k < 3; k++)
-                            cb[k] *= as;
-                          glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
-
-                          for (int k = 0; k < 3; k++)
-                            cb[k] = ds * c(j-1, i, k);
-                          glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
-
-                          for (int k = 0; k < 3; k++)
-                            cb[k] = ss * (scr + (1-scr) * c(j-1, i, k));
-                          glMaterialfv (LIGHT_MODE, GL_SPECULAR, cb);
-                        }
-                    }
-
-                  if (fl_mode == GOURAUD)
-                    set_normal (bfl_mode, n, j-1, i);
-
-                  glVertex3d (x(j1,i), y(j-1,i2), z(j-1,i));
-
-                  // Vertex 3
-                  if (fc_mode == TEXTURE)
-                    tex.tex_coord (double (i) / (zc-1), double (j) / (zr-1));
-                  else if (fc_mode == INTERP)
-                    {
-                      for (int k = 0; k < 3; k++)
-                        cb[k] = c(j, i, k);
-                      glColor3fv (cb);
-
-                      if (fl_mode > 0)
-                        {
-                          for (int k = 0; k < 3; k++)
-                            cb[k] *= as;
-                          glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
-
-                          for (int k = 0; k < 3; k++)
-                            cb[k] = ds * c(j, i, k);
-                          glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
-
-                          for (int k = 0; k < 3; k++)
-                            cb[k] = ss * (scr + (1-scr) * c(j, i, k));
-                          glMaterialfv (LIGHT_MODE, GL_SPECULAR, cb);
-                        }
-                    }
-                  if (fl_mode == GOURAUD)
-                    set_normal (bfl_mode, n, j, i);
-
-                  glVertex3d (x(j2,i), y(j,i2), z(j,i));
-
-                  // Vertex 4
-                  if (fc_mode == TEXTURE)
-                    tex.tex_coord (double (i-1) / (zc-1), double (j) / (zr-1));
-                  else if (fc_mode == INTERP)
-                    {
-                      for (int k = 0; k < 3; k++)
-                        cb[k] = c(j, i-1, k);
-                      glColor3fv (cb);
-
-                      if (fl_mode > 0)
-                        {
-                          for (int k = 0; k < 3; k++)
-                            cb[k] *= as;
-                          glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
-
-                          for (int k = 0; k < 3; k++)
-                            cb[k] = ds * c(j, i-1, k);
-                          glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
-
-                          for (int k = 0; k < 3; k++)
-                            cb[k] = ss * (scr + (1-scr) * c(j, i-1, k));
-                          glMaterialfv (LIGHT_MODE, GL_SPECULAR, cb);
-                        }
-                    }
-                  if (fl_mode == GOURAUD)
-                    set_normal (bfl_mode, n, j, i-1);
-
-                  glVertex3d (x(j2,i-1), y(j,i1), z(j,i-1));
-
-                  glEnd ();
-                }
+              double dir = 1.0;
+              if (bfl_mode > 0)
+                dir = ((n(idx,0) * view_vector(0)
+                        + n(idx,1) * view_vector(1)
+                        + n(idx,2) * view_vector(2) < 0)
+                       ? ((bfl_mode > 1) ? 0.0 : -1.0) : 1.0);
+              nn(0) = dir * n(idx,0);
+              nn(1) = dir * n(idx,1);
+              nn(2) = dir * n(idx,2);
             }
-
-          set_polygon_offset (false);
-          if (fc_mode == TEXTURE)
-            glDisable (GL_TEXTURE_2D);
-
-          if ((fl_mode > 0) && (num_lights > 0))
-            glDisable (GL_LIGHTING);
-        }
-      else
-        {
-          // FIXME: implement transparency
+          if (c.numel () > 0)
+            {
+              cc.resize (1, 3);
+              if (has_facecolor)
+                cc(0) = c(i,0), cc(1) = c(i,1), cc(2) = c(i,2);
+              else
+                cc(0) = c(idx,0), cc(1) = c(idx,1), cc(2) = c(idx,2);
+            }
+          if (a.numel () > 0)
+            {
+              if (has_facealpha)
+                aa = a(i);
+              else
+                aa = a(idx);
+            }
+
+          vdata[i+j*fr] = vertex_data (vv, cc, nn, aa, as, ds, ss, se, scr);
         }
-    }
-
-  if (! props.edgecolor_is ("none"))
-    {
-      if (props.get_edgealpha_double () == 1)
-        {
-          if (ec_mode == UNIFORM)
-            {
-              glColor3dv (ecolor.data ());
-              if (fl_mode > 0)
-                {
-                  for (int i = 0; i < 3; i++)
-                    cb[i] = as * ecolor(i);
-                  glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
-
-                  for (int i = 0; i < 3; i++)
-                    cb[i] = ds * ecolor(i);
-                  glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
-
-                  for (int i = 0; i < 3; i++)
-                    cb[i] = ss * (scr + (1-scr) * ecolor(i));
-                  glMaterialfv (LIGHT_MODE, GL_SPECULAR, cb);
-                }
-            }
-
-          if ((el_mode > 0) && (num_lights > 0))
-            glEnable (GL_LIGHTING);
-          glShadeModel ((ec_mode == INTERP || el_mode == GOURAUD) ? GL_SMOOTH
-                                                                  : GL_FLAT);
-
-          set_linestyle (props.get_linestyle (), false);
-          set_linewidth (props.get_linewidth ());
-
-          // Mesh along Y-axis
-
-          if (props.meshstyle_is ("both") || props.meshstyle_is ("column"))
+
+    if (fl_mode > 0 || el_mode > 0)
+      glMaterialf (LIGHT_MODE, GL_SHININESS, se);
+
+    if (! props.facecolor_is ("none"))
+      {
+        // FIXME: adapt to double-radio property
+        if (props.get_facealpha_double () == 1)
+          {
+            if (fc_mode == UNIFORM)
+              {
+                glColor3dv (fcolor.data ());
+                if (fl_mode > 0)
+                  {
+                    float cb[4] = { 0, 0, 0, 1 };
+
+                    for (int i = 0; i < 3; i++)
+                      cb[i] = as * fcolor(i);
+                    glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
+
+                    for (int i = 0; i < 3; i++)
+                      cb[i] = ds * fcolor(i);
+                    glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
+
+                    for (int i = 0; i < 3; i++)
+                      cb[i] = ss * (scr + (1-scr) * fcolor(i));
+                    glMaterialfv (LIGHT_MODE, GL_SPECULAR, cb);
+                  }
+              }
+
+            if ((fl_mode > 0) && (num_lights > 0) && has_normals)
+              glEnable (GL_LIGHTING);
+
+            // NOTE: Push filled part of patch backwards to avoid Z-fighting with
+            // tesselator outline.  A value of 1.0 seems to work fine.  Value
+            // can't be too large or the patch will be pushed below the axes
+            // planes at +2.5.
+            patch_tesselator tess (this, fc_mode, fl_mode, 1.0);
+
+            for (int i = 0; i < nf; i++)
+              {
+                if (clip_f(i))
+                  continue;
+
+                tess.begin_polygon (true);
+                tess.begin_contour ();
+
+                // Add vertices in reverse order for Matlab compatibility
+                for (int j = count_f(i)-1; j > 0; j--)
+                  {
+                    vertex_data::vertex_data_rep *vv = vdata[i+j*fr].get_rep ();
+
+                    tess.add_vertex (vv->coords.fortran_vec (), vv);
+                  }
+
+                if (count_f(i) > 0)
+                  {
+                    vertex_data::vertex_data_rep *vv = vdata[i].get_rep ();
+
+                    if (fc_mode == FLAT)
+                      {
+                        // For "flat" shading, use color of 1st vertex.
+                        Matrix col = vv->color;
+
+                        if (col.numel () == 3)
+                          {
+                            glColor3dv (col.data ());
+                            if (fl_mode > 0)
+                              {
+                                float cb[4] = { 0, 0, 0, 1 };
+
+                                for (int k = 0; k < 3; k++)
+                                  cb[k] = (vv->ambient * col(k));
+                                glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
+
+                                for (int k = 0; k < 3; k++)
+                                  cb[k] = (vv->diffuse * col(k));
+                                glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
+
+                                for (int k = 0; k < 3; k++)
+                                  cb[k] = vv->specular * (vv->specular_color_refl
+                                                          + (1-vv->specular_color_refl) * col(k));
+                                glMaterialfv (LIGHT_MODE, GL_SPECULAR, cb);
+                              }
+                          }
+                      }
+
+                    tess.add_vertex (vv->coords.fortran_vec (), vv);
+                  }
+
+                tess.end_contour ();
+                tess.end_polygon ();
+              }
+
+            if ((fl_mode > 0) && (num_lights > 0) && has_normals)
+              glDisable (GL_LIGHTING);
+          }
+        else
+          {
+            // FIXME: implement transparency
+          }
+      }
+
+    if (! props.edgecolor_is ("none"))
+      {
+        // FIXME: adapt to double-radio property
+        if (props.get_edgealpha_double () == 1)
+          {
+            if (ec_mode == UNIFORM)
+              {
+                glColor3dv (ecolor.data ());
+                if (el_mode > 0)
+                  {
+                    float cb[4] = { 0, 0, 0, 1 };
+
+                    for (int i = 0; i < 3; i++)
+                      cb[i] = (as * ecolor(i));
+                    glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
+
+                    for (int i = 0; i < 3; i++)
+                      cb[i] = ds * ecolor(i);
+                    glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
+
+                    for (int i = 0; i < 3; i++)
+                      cb[i] = ss * (scr + (1-scr) * ecolor(i));
+                    glMaterialfv (LIGHT_MODE, GL_SPECULAR, cb);
+                  }
+              }
+
+            if ((el_mode > 0) && (num_lights > 0) && has_normals)
+              glEnable (GL_LIGHTING);
+
+            set_linestyle (props.get_linestyle (), false);
+            set_linewidth (props.get_linewidth ());
+
+            // NOTE: patch contour cannot be offset.  Offset must occur with the
+            // filled portion of the patch above.  The tesselator uses
+            // GLU_TESS_BOUNDARY_ONLY to get the outline of the patch and OpenGL
+            // automatically sets the glType to GL_LINE_LOOP.  This primitive is
+            // not supported by glPolygonOffset which is used to do Z offsets.
+            patch_tesselator tess (this, ec_mode, el_mode);
+
+            for (int i = 0; i < nf; i++)
+              {
+                if (clip_f(i))
+                  {
+                    // This is an unclosed contour.  Draw it as a line.
+                    bool flag = false;
+
+                    glShadeModel ((ec_mode == INTERP || el_mode == GOURAUD)
+                                  ? GL_SMOOTH : GL_FLAT);
+
+                    // Add vertices in reverse order for Matlab compatibility
+                    for (int j = count_f(i)-1; j >= 0; j--)
+                      {
+                        if (! clip(int (f(i,j) - 1)))
+                          {
+                            vertex_data::vertex_data_rep *vv
+                              = vdata[i+j*fr].get_rep ();
+                            const Matrix m = vv->coords;
+                            if (! flag)
+                              {
+                                flag = true;
+                                glBegin (GL_LINE_STRIP);
+                              }
+                            if (ec_mode != UNIFORM)
+                              {
+                                Matrix col = vv->color;
+
+                                if (col.numel () == 3)
+                                  glColor3dv (col.data ());
+                              }
+                            glVertex3d (m(0), m(1), m(2));
+                          }
+                        else if (flag)
+                          {
+                            flag = false;
+                            glEnd ();
+                          }
+                      }
+                    // Do loop body with vertex N to "close" GL_LINE_STRIP
+                    // from vertex 0 to vertex N.
+                    int j = count_f(i)-1;
+                    if (flag && ! clip(int (f(i,j) - 1)))
+                      {
+                        vertex_data::vertex_data_rep *vv
+                          = vdata[i+j*fr].get_rep ();
+                        const Matrix m = vv->coords;
+                        if (ec_mode != UNIFORM)
+                          {
+                            Matrix col = vv->color;
+
+                            if (col.numel () == 3)
+                              glColor3dv (col.data ());
+                          }
+                        glVertex3d (m(0), m(1), m(2));
+                      }
+
+                    if (flag)
+                      glEnd ();
+                  }
+                else  // Normal edge contour drawn with tesselator
+                  {
+                    tess.begin_polygon (false);
+                    tess.begin_contour ();
+
+                    for (int j = count_f(i)-1; j >= 0; j--)
+                      {
+                        vertex_data::vertex_data_rep *vv
+                          = vdata[i+j*fr].get_rep ();
+                        tess.add_vertex (vv->coords.fortran_vec (), vv);
+                      }
+
+                    tess.end_contour ();
+                    tess.end_polygon ();
+                  }
+              }
+
+            set_linestyle ("-");
+            set_linewidth (0.5);
+
+            if ((el_mode > 0) && (num_lights > 0) && has_normals)
+              glDisable (GL_LIGHTING);
+          }
+        else
+          {
+            // FIXME: implement transparency
+          }
+      }
+
+    if (! props.marker_is ("none")
+        && ! (props.markeredgecolor_is ("none")
+              && props.markerfacecolor_is ("none")))
+      {
+        bool do_edge = ! props.markeredgecolor_is ("none");
+        bool do_face = ! props.markerfacecolor_is ("none");
+
+        Matrix mecolor = props.get_markeredgecolor_rgb ();
+        Matrix mfcolor = props.get_markerfacecolor_rgb ();
+
+        bool has_markerfacecolor = false;
+
+        if ((mecolor.is_empty () && ! props.markeredgecolor_is ("none"))
+            || (mfcolor.is_empty () && ! props.markerfacecolor_is ("none")))
+          {
+            Matrix mc = props.get_color_data ().matrix_value ();
+
+            if (mc.rows () == 1)
+              {
+                // Single color specifications, we can simplify a little bit
+                if (mfcolor.is_empty () && ! props.markerfacecolor_is ("none"))
+                  mfcolor = mc;
+
+                if (mecolor.is_empty () && ! props.markeredgecolor_is ("none"))
+                  mecolor = mc;
+              }
+            else
+              {
+                if (c.is_empty ())
+                  c = props.get_color_data ().matrix_value ();
+                has_markerfacecolor = ((c.numel () > 0)
+                                       && (c.rows () == f.rows ()));
+              }
+          }
+
+        init_marker (props.get_marker (), props.get_markersize (),
+                     props.get_linewidth ());
+
+        for (int i = 0; i < nf; i++)
+          for (int j = 0; j < count_f(i); j++)
             {
-              for (int i = 0; i < zc; i++)
-                {
-                  if (y_mat)
-                    {
-                      i1 = i-1;
-                      i2 = i;
-                    }
-
-                  for (int j = 1; j < zr; j++)
-                    {
-                      if (clip(j-1,i) || clip(j,i))
-                        continue;
-
-                      if (ec_mode == FLAT)
-                        {
-                          // "flat" only needs color at lower-left vertex
-                          if (! octave::math::finite (c(j-1,i)))
-                            continue;
-                        }
-                      else if (ec_mode == INTERP)
-                        {
-                          // "interp" needs valid color at both vertices
-                          if (! (octave::math::finite (c(j-1, i)) && octave::math::finite (c(j, i))))
-                            continue;
-                        }
-
-                      if (x_mat)
-                        {
-                          j1 = j-1;
-                          j2 = j;
-                        }
-
-                      glBegin (GL_LINES);
-
-                      // Vertex 1
-                      if (ec_mode > 0)
-                        {
-                          for (int k = 0; k < 3; k++)
-                            cb[k] = c(j-1, i, k);
-                          glColor3fv (cb);
-
-                          if (el_mode > 0)
-                            {
-                              for (int k = 0; k < 3; k++)
-                                cb[k] *= as;
-                              glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
-
-                              for (int k = 0; k < 3; k++)
-                                cb[k] = ds * c(j-1, i, k);
-                              glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
-
-                              for (int k = 0; k < 3; k++)
-                                cb[k] = ss * (scr + (1-scr) * c(j-1, i, k));
-                              glMaterialfv (LIGHT_MODE, GL_SPECULAR, cb);
-                            }
-                        }
-                      if (el_mode > 0)
-                        set_normal (bfl_mode, n, j-1, i);
-
-                      glVertex3d (x(j1,i), y(j-1,i2), z(j-1,i));
-
-                      // Vertex 2
-                      if (ec_mode == INTERP)
-                        {
-                          for (int k = 0; k < 3; k++)
-                            cb[k] = c(j, i, k);
-                          glColor3fv (cb);
-
-                          if (el_mode > 0)
-                            {
-                              for (int k = 0; k < 3; k++)
-                                cb[k] *= as;
-                              glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
-
-                              for (int k = 0; k < 3; k++)
-                                cb[k] = ds * c(j, i, k);
-                              glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
-
-                              for (int k = 0; k < 3; k++)
-                                cb[k] = ss * (scr + (1-scr) * c(j, i, k));
-                              glMaterialfv (LIGHT_MODE, GL_SPECULAR, cb);
-                            }
-                        }
-                      if (el_mode == GOURAUD)
-                        set_normal (bfl_mode, n, j, i);
-
-                      glVertex3d (x(j2,i), y(j,i2), z(j,i));
-
-                      glEnd ();
-                    }
-                }
-            }
-
-          // Mesh along X-axis
-
-          if (props.meshstyle_is ("both") || props.meshstyle_is ("row"))
-            {
-              for (int j = 0; j < zr; j++)
+              int idx = int (f(i,j) - 1);
+
+              if (clip(idx))
+                continue;
+
+              Matrix cc;
+              if (c.numel () > 0)
                 {
-                  if (x_mat)
-                    {
-                      j1 = j-1;
-                      j2 = j;
-                    }
-
-                  for (int i = 1; i < zc; i++)
-                    {
-                      if (clip(j,i-1) || clip(j,i))
-                        continue;
-
-                      if (ec_mode == FLAT)
-                        {
-                          // "flat" only needs color at lower-left vertex
-                          if (! octave::math::finite (c(j,i-1)))
-                            continue;
-                        }
-                      else if (ec_mode == INTERP)
-                        {
-                          // "interp" needs valid color at both vertices
-                          if (! (octave::math::finite (c(j, i-1)) && octave::math::finite (c(j, i))))
-                            continue;
-                        }
-
-                      if (y_mat)
-                        {
-                          i1 = i-1;
-                          i2 = i;
-                        }
-
-                      glBegin (GL_LINES);
-
-                      // Vertex 1
-                      if (ec_mode > 0)
-                        {
-                          for (int k = 0; k < 3; k++)
-                            cb[k] = c(j, i-1, k);
-                          glColor3fv (cb);
-
-                          if (el_mode > 0)
-                            {
-                              for (int k = 0; k < 3; k++)
-                                cb[k] *= as;
-                              glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
-
-                              for (int k = 0; k < 3; k++)
-                                cb[k] = ds * c(j, i-1, k);
-                              glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
-
-                              for (int k = 0; k < 3; k++)
-                                cb[k] = ss * (scr + (1-scr) * c(j, i-1, k));
-                              glMaterialfv (LIGHT_MODE, GL_SPECULAR, cb);
-                            }
-                        }
-                      if (el_mode > 0)
-                        set_normal (bfl_mode, n, j, i-1);
-
-                      glVertex3d (x(j2,i-1), y(j,i1), z(j,i-1));
-
-                      // Vertex 2
-                      if (ec_mode == INTERP)
-                        {
-                          for (int k = 0; k < 3; k++)
-                            cb[k] = c(j, i, k);
-                          glColor3fv (cb);
-
-                          if (el_mode > 0)
-                            {
-                              for (int k = 0; k < 3; k++)
-                                cb[k] *= as;
-                              glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
-
-                              for (int k = 0; k < 3; k++)
-                                cb[k] = ds * c(j, i, k);
-                              glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
-
-                              for (int k = 0; k < 3; k++)
-                                cb[k] = ss * (scr + (1-scr) * c(j, i, k));
-                              glMaterialfv (LIGHT_MODE, GL_SPECULAR, cb);
-                            }
-                        }
-                      if (el_mode == GOURAUD)
-                        set_normal (bfl_mode, n, j, i);
-
-                      glVertex3d (x(j2,i), y(j,i2), z(j,i));
-
-                      glEnd ();
-                    }
-                }
-            }
-
-          set_linestyle ("-");
-          set_linewidth (0.5);
-
-          if ((el_mode > 0) && (num_lights > 0))
-            glDisable (GL_LIGHTING);
-        }
-      else
-        {
-          // FIXME: implement transparency
-        }
-    }
-
-  if (! props.marker_is ("none")
-      && ! (props.markeredgecolor_is ("none")
-            && props.markerfacecolor_is ("none")))
-    {
-      // FIXME: check how transparency should be handled in markers
-      // FIXME: check what to do with marker facecolor set to auto
-      //        and facecolor set to none.
-
-      bool do_edge = ! props.markeredgecolor_is ("none");
-      bool do_face = ! props.markerfacecolor_is ("none");
-
-      Matrix mecolor = props.get_markeredgecolor_rgb ();
-      Matrix mfcolor = props.get_markerfacecolor_rgb ();
-      Matrix cc (1, 3, 0.0);
-
-      if (mecolor.is_empty () && props.markeredgecolor_is ("auto"))
-        {
-          mecolor = props.get_edgecolor_rgb ();
-          do_edge = ! props.edgecolor_is ("none");
-        }
-
-      if (mfcolor.is_empty () && props.markerfacecolor_is ("auto"))
-        {
-          mfcolor = props.get_facecolor_rgb ();
-          do_face = ! props.facecolor_is ("none");
-        }
-
-      if ((mecolor.is_empty () || mfcolor.is_empty ()) && c.is_empty ())
-        c = props.get_color_data ().array_value ();
-
-      init_marker (props.get_marker (), props.get_markersize (),
-                   props.get_linewidth ());
-
-      for (int i = 0; i < zc; i++)
-        {
-          if (y_mat)
-            i1 = i;
-
-          for (int j = 0; j < zr; j++)
-            {
-              if (clip(j,i))
-                continue;
-
-              if (x_mat)
-                j1 = j;
-
-              if ((do_edge && mecolor.is_empty ())
-                  || (do_face && mfcolor.is_empty ()))
-                {
-                  if (! octave::math::finite (c(j,i)))
-                    continue;  // Skip NaNs in color data
-
-                  for (int k = 0; k < 3; k++)
-                    cc(k) = c(j,i,k);
+                  cc.resize (1, 3);
+                  if (has_markerfacecolor)
+                    cc(0) = c(i,0), cc(1) = c(i,1), cc(2) = c(i,2);
+                  else
+                    cc(0) = c(idx,0), cc(1) = c(idx,1), cc(2) = c(idx,2);
                 }
 
               Matrix lc = (do_edge ? (mecolor.is_empty () ? cc : mecolor)
-                                   : Matrix ());
+                           : Matrix ());
               Matrix fc = (do_face ? (mfcolor.is_empty () ? cc : mfcolor)
-                                   : Matrix ());
-
-              draw_marker (x(j1,i), y(j,i1), z(j,i), lc, fc);
+                           : Matrix ());
+
+              draw_marker (v(idx,0), v(idx,1), (has_z ? v(idx,2) : 0), lc, fc);
             }
-        }
-
-      end_marker ();
-    }
+
+        end_marker ();
+      }
 
 #else
 
-  octave_unused_parameter (props);
-
-  // This shouldn't happen because construction of opengl_renderer
-  // objects is supposed to be impossible if OpenGL is not available.
-
-  panic_impossible ();
+    octave_unused_parameter (props);
+
+    // This shouldn't happen because construction of opengl_renderer
+    // objects is supposed to be impossible if OpenGL is not available.
+
+    panic_impossible ();
 
 #endif
-}
-
-// FIXME: global optimization (rendering, data structures...),
-// there is probably a smarter/faster/less-memory-consuming way to do this.
-void
-opengl_renderer::draw_patch (const patch::properties &props)
-{
+  }
+
+  void
+  opengl_renderer::draw_light (const light::properties &props)
+  {
 #if defined (HAVE_OPENGL)
 
-  // Do not render if the patch has incoherent data
-  std::string msg;
-  if (props.has_bad_data (msg))
-    {
-      warning ("opengl_renderer: %s.  Not rendering.", msg.c_str ());
-      return;
-    }
-
-  const Matrix f = props.get_faces ().matrix_value ();
-  const Matrix v = xform.scale (props.get_vertices ().matrix_value ());
-  Matrix c;
-  const Matrix n = props.get_vertexnormals ().matrix_value ();
-  Matrix a;
-
-  int nv = v.rows ();
-  int nf = f.rows ();
-  int fcmax = f.columns ();
-
-  bool has_z = (v.columns () > 2);
-  bool has_facecolor = false;
-  bool has_facealpha = false;
-  // FIXME: remove when patch object has normal computation (patch #8951)
-  bool has_normals = (n.rows () == nv);
-
-  int fc_mode = ((props.facecolor_is ("none")
-                  || props.facecolor_is_rgb ()) ? 0 :
-                 (props.facecolor_is ("flat") ? 1 : 2));
-  int fl_mode = (props.facelighting_is ("none") ? 0 :
-                 (props.facelighting_is ("flat") ? 1 : 2));
-  int fa_mode = (props.facealpha_is_double () ? 0 :
-                 (props.facealpha_is ("flat") ? 1 : 2));
-  int ec_mode = ((props.edgecolor_is ("none")
-                  || props.edgecolor_is_rgb ()) ? 0 :
-                 (props.edgecolor_is ("flat") ? 1 : 2));
-  int el_mode = (props.edgelighting_is ("none") ? 0 :
-                 (props.edgelighting_is ("flat") ? 1 : 2));
-  int ea_mode = (props.edgealpha_is_double () ? 0 :
-                 (props.edgealpha_is ("flat") ? 1 : 2));
-  int bfl_mode = (props.backfacelighting_is ("lit") ? 0 :
-                  (props.backfacelighting_is ("reverselit") ? 1 : 2));
-
-  Matrix fcolor = props.get_facecolor_rgb ();
-  Matrix ecolor = props.get_edgecolor_rgb ();
-
-  float as = props.get_ambientstrength ();
-  float ds = props.get_diffusestrength ();
-  float ss = props.get_specularstrength ();
-  float se = props.get_specularexponent () * 5; // to fit Matlab
-  float scr = props.get_specularcolorreflectance ();
-
-  boolMatrix clip (1, nv, false);
-
-  if (has_z)
-    for (int i = 0; i < nv; i++)
-      clip(i) = is_nan_or_inf (v(i,0), v(i,1), v(i,2));
-  else
-    for (int i = 0; i < nv; i++)
-      clip(i) = is_nan_or_inf (v(i,0), v(i,1), 0);
-
-  boolMatrix clip_f (1, nf, false);
-  Array<int> count_f (dim_vector (nf, 1), 0);
-
-  for (int i = 0; i < nf; i++)
-    {
-      bool fclip = false;
-      int count = 0;
-
-      for (int j = 0; j < fcmax && ! octave::math::isnan (f(i,j)); j++, count++)
-        fclip = (fclip || clip(int (f(i,j) - 1)));
-
-      clip_f(i) = fclip;
-      count_f(i) = count;
-    }
-
-  if (fc_mode > 0 || ec_mode > 0)
-    {
-      c = props.get_color_data ().matrix_value ();
-
-      if (c.rows () == 1)
-        {
-          // Single color specifications, we can simplify a little bit
-
-          if (fc_mode > 0)
-            {
-              fcolor = c;
-              fc_mode = UNIFORM;
-            }
-
-          if (ec_mode > 0)
-            {
-              ecolor = c;
-              ec_mode = UNIFORM;
-            }
-
-          c = Matrix ();
-        }
-      else
-        has_facecolor = ((c.numel () > 0) && (c.rows () == f.rows ()));
-    }
-
-  if (fa_mode > 0 || ea_mode > 0)
-    {
-      // FIXME: retrieve alpha data from patch object
-      //a = props.get_alpha_data ();
-      has_facealpha = ((a.numel () > 0) && (a.rows () == f.rows ()));
-    }
-
-  octave_idx_type fr = f.rows ();
-  std::vector<vertex_data> vdata (f.numel ());
-
-  for (int i = 0; i < nf; i++)
-    for (int j = 0; j < count_f(i); j++)
-      {
-        int idx = int (f(i,j) - 1);
-
-        Matrix vv (1, 3, 0.0);
-        Matrix cc;
-        Matrix nn (1, 3, 0.0);
-        double aa = 1.0;
-
-        vv(0) = v(idx,0); vv(1) = v(idx,1);
-        if (has_z)
-          vv(2) = v(idx,2);
-        if (has_normals)
-          {
-            double dir = 1.0;
-            if (bfl_mode > 0)
-              dir = ((n(idx,0) * view_vector(0)
-                      + n(idx,1) * view_vector(1)
-                      + n(idx,2) * view_vector(2) < 0)
-                     ? ((bfl_mode > 1) ? 0.0 : -1.0) : 1.0);
-            nn(0) = dir * n(idx,0);
-            nn(1) = dir * n(idx,1);
-            nn(2) = dir * n(idx,2);
-          }
-        if (c.numel () > 0)
-          {
-            cc.resize (1, 3);
-            if (has_facecolor)
-              cc(0) = c(i,0), cc(1) = c(i,1), cc(2) = c(i,2);
-            else
-              cc(0) = c(idx,0), cc(1) = c(idx,1), cc(2) = c(idx,2);
-          }
-        if (a.numel () > 0)
-          {
-            if (has_facealpha)
-              aa = a(i);
-            else
-              aa = a(idx);
-          }
-
-        vdata[i+j*fr] = vertex_data (vv, cc, nn, aa, as, ds, ss, se, scr);
-      }
-
-  if (fl_mode > 0 || el_mode > 0)
-    glMaterialf (LIGHT_MODE, GL_SHININESS, se);
-
-  if (! props.facecolor_is ("none"))
-    {
-      // FIXME: adapt to double-radio property
-      if (props.get_facealpha_double () == 1)
-        {
-          if (fc_mode == UNIFORM)
-            {
-              glColor3dv (fcolor.data ());
-              if (fl_mode > 0)
-                {
-                  float cb[4] = { 0, 0, 0, 1 };
-
-                  for (int i = 0; i < 3; i++)
-                    cb[i] = as * fcolor(i);
-                  glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
-
-                  for (int i = 0; i < 3; i++)
-                    cb[i] = ds * fcolor(i);
-                  glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
-
-                  for (int i = 0; i < 3; i++)
-                    cb[i] = ss * (scr + (1-scr) * fcolor(i));
-                  glMaterialfv (LIGHT_MODE, GL_SPECULAR, cb);
-                }
-            }
-
-          if ((fl_mode > 0) && (num_lights > 0) && has_normals)
-            glEnable (GL_LIGHTING);
-
-          // NOTE: Push filled part of patch backwards to avoid Z-fighting with
-          // tesselator outline.  A value of 1.0 seems to work fine.  Value
-          // can't be too large or the patch will be pushed below the axes
-          // planes at +2.5.
-          patch_tesselator tess (this, fc_mode, fl_mode, 1.0);
-
-          for (int i = 0; i < nf; i++)
-            {
-              if (clip_f(i))
-                continue;
-
-              tess.begin_polygon (true);
-              tess.begin_contour ();
-
-              // Add vertices in reverse order for Matlab compatibility
-              for (int j = count_f(i)-1; j > 0; j--)
-                {
-                  vertex_data::vertex_data_rep *vv = vdata[i+j*fr].get_rep ();
-
-                  tess.add_vertex (vv->coords.fortran_vec (), vv);
-                }
-
-              if (count_f(i) > 0)
-                {
-                  vertex_data::vertex_data_rep *vv = vdata[i].get_rep ();
-
-                  if (fc_mode == FLAT)
-                    {
-                      // For "flat" shading, use color of 1st vertex.
-                      Matrix col = vv->color;
-
-                      if (col.numel () == 3)
-                        {
-                          glColor3dv (col.data ());
-                          if (fl_mode > 0)
-                            {
-                              float cb[4] = { 0, 0, 0, 1 };
-
-                              for (int k = 0; k < 3; k++)
-                                cb[k] = (vv->ambient * col(k));
-                              glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
-
-                              for (int k = 0; k < 3; k++)
-                                cb[k] = (vv->diffuse * col(k));
-                              glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
-
-                              for (int k = 0; k < 3; k++)
-                                cb[k] = vv->specular * (vv->specular_color_refl
-                                    + (1-vv->specular_color_refl) * col(k));
-                              glMaterialfv (LIGHT_MODE, GL_SPECULAR, cb);
-                            }
-                        }
-                    }
-
-                  tess.add_vertex (vv->coords.fortran_vec (), vv);
-                }
-
-              tess.end_contour ();
-              tess.end_polygon ();
-            }
-
-          if ((fl_mode > 0) && (num_lights > 0) && has_normals)
-            glDisable (GL_LIGHTING);
-        }
-      else
-        {
-          // FIXME: implement transparency
-        }
-    }
-
-  if (! props.edgecolor_is ("none"))
-    {
-      // FIXME: adapt to double-radio property
-      if (props.get_edgealpha_double () == 1)
-        {
-          if (ec_mode == UNIFORM)
-            {
-              glColor3dv (ecolor.data ());
-              if (el_mode > 0)
-                {
-                  float cb[4] = { 0, 0, 0, 1 };
-
-                  for (int i = 0; i < 3; i++)
-                    cb[i] = (as * ecolor(i));
-                  glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
-
-                  for (int i = 0; i < 3; i++)
-                    cb[i] = ds * ecolor(i);
-                  glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
-
-                  for (int i = 0; i < 3; i++)
-                    cb[i] = ss * (scr + (1-scr) * ecolor(i));
-                  glMaterialfv (LIGHT_MODE, GL_SPECULAR, cb);
-                }
-            }
-
-          if ((el_mode > 0) && (num_lights > 0) && has_normals)
-            glEnable (GL_LIGHTING);
-
-          set_linestyle (props.get_linestyle (), false);
-          set_linewidth (props.get_linewidth ());
-
-          // NOTE: patch contour cannot be offset.  Offset must occur with the
-          // filled portion of the patch above.  The tesselator uses
-          // GLU_TESS_BOUNDARY_ONLY to get the outline of the patch and OpenGL
-          // automatically sets the glType to GL_LINE_LOOP.  This primitive is
-          // not supported by glPolygonOffset which is used to do Z offsets.
-          patch_tesselator tess (this, ec_mode, el_mode);
-
-          for (int i = 0; i < nf; i++)
-            {
-              if (clip_f(i))
-                {
-                  // This is an unclosed contour.  Draw it as a line.
-                  bool flag = false;
-
-                  glShadeModel ((ec_mode == INTERP || el_mode == GOURAUD)
-                                ? GL_SMOOTH : GL_FLAT);
-
-                  // Add vertices in reverse order for Matlab compatibility
-                  for (int j = count_f(i)-1; j >= 0; j--)
-                    {
-                      if (! clip(int (f(i,j) - 1)))
-                        {
-                          vertex_data::vertex_data_rep *vv
-                            = vdata[i+j*fr].get_rep ();
-                          const Matrix m = vv->coords;
-                          if (! flag)
-                            {
-                              flag = true;
-                              glBegin (GL_LINE_STRIP);
-                            }
-                          if (ec_mode != UNIFORM)
-                            {
-                              Matrix col = vv->color;
-
-                              if (col.numel () == 3)
-                                glColor3dv (col.data ());
-                            }
-                          glVertex3d (m(0), m(1), m(2));
-                        }
-                      else if (flag)
-                        {
-                          flag = false;
-                          glEnd ();
-                        }
-                    }
-                  // Do loop body with vertex N to "close" GL_LINE_STRIP
-                  // from vertex 0 to vertex N.
-                  int j = count_f(i)-1;
-                  if (flag && ! clip(int (f(i,j) - 1)))
-                    {
-                      vertex_data::vertex_data_rep *vv
-                        = vdata[i+j*fr].get_rep ();
-                      const Matrix m = vv->coords;
-                      if (ec_mode != UNIFORM)
-                        {
-                          Matrix col = vv->color;
-
-                          if (col.numel () == 3)
-                            glColor3dv (col.data ());
-                        }
-                      glVertex3d (m(0), m(1), m(2));
-                    }
-
-                  if (flag)
-                    glEnd ();
-                }
-              else  // Normal edge contour drawn with tesselator
-                {
-                  tess.begin_polygon (false);
-                  tess.begin_contour ();
-
-                  for (int j = count_f(i)-1; j >= 0; j--)
-                    {
-                      vertex_data::vertex_data_rep *vv
-                        = vdata[i+j*fr].get_rep ();
-                      tess.add_vertex (vv->coords.fortran_vec (), vv);
-                    }
-
-                  tess.end_contour ();
-                  tess.end_polygon ();
-                }
-            }
-
-          set_linestyle ("-");
-          set_linewidth (0.5);
-
-          if ((el_mode > 0) && (num_lights > 0) && has_normals)
-            glDisable (GL_LIGHTING);
-        }
-      else
-        {
-          // FIXME: implement transparency
-        }
-    }
-
-  if (! props.marker_is ("none")
-      && ! (props.markeredgecolor_is ("none")
-            && props.markerfacecolor_is ("none")))
-    {
-      bool do_edge = ! props.markeredgecolor_is ("none");
-      bool do_face = ! props.markerfacecolor_is ("none");
-
-      Matrix mecolor = props.get_markeredgecolor_rgb ();
-      Matrix mfcolor = props.get_markerfacecolor_rgb ();
-
-      bool has_markerfacecolor = false;
-
-      if ((mecolor.is_empty () && ! props.markeredgecolor_is ("none"))
-          || (mfcolor.is_empty () && ! props.markerfacecolor_is ("none")))
-        {
-          Matrix mc = props.get_color_data ().matrix_value ();
-
-          if (mc.rows () == 1)
-            {
-              // Single color specifications, we can simplify a little bit
-              if (mfcolor.is_empty () && ! props.markerfacecolor_is ("none"))
-                mfcolor = mc;
-
-              if (mecolor.is_empty () && ! props.markeredgecolor_is ("none"))
-                mecolor = mc;
-            }
-          else
-            {
-              if (c.is_empty ())
-                c = props.get_color_data ().matrix_value ();
-              has_markerfacecolor = ((c.numel () > 0)
-                                     && (c.rows () == f.rows ()));
-            }
-        }
-
-      init_marker (props.get_marker (), props.get_markersize (),
-                   props.get_linewidth ());
-
-      for (int i = 0; i < nf; i++)
-        for (int j = 0; j < count_f(i); j++)
-          {
-            int idx = int (f(i,j) - 1);
-
-            if (clip(idx))
-              continue;
-
-            Matrix cc;
-            if (c.numel () > 0)
-              {
-                cc.resize (1, 3);
-                if (has_markerfacecolor)
-                  cc(0) = c(i,0), cc(1) = c(i,1), cc(2) = c(i,2);
-                else
-                  cc(0) = c(idx,0), cc(1) = c(idx,1), cc(2) = c(idx,2);
-              }
-
-            Matrix lc = (do_edge ? (mecolor.is_empty () ? cc : mecolor)
-                                 : Matrix ());
-            Matrix fc = (do_face ? (mfcolor.is_empty () ? cc : mfcolor)
-                                 : Matrix ());
-
-            draw_marker (v(idx,0), v(idx,1), (has_z ? v(idx,2) : 0), lc, fc);
-          }
-
-      end_marker ();
-    }
+    // enable light source
+    glEnable (current_light);
+
+    // light position
+    float pos[4] = { 0, 0, 0, 0 }; // X,Y,Z,infinite/local
+    Matrix lpos = props.get_position ().matrix_value ();
+    for (int i = 0; i < 3; i++)
+      pos[i] = lpos(i);
+    if (props.style_is ("local"))
+      pos[3] = 1;
+    glLightfv (current_light, GL_POSITION, pos);
+
+    // light color
+    float col[4] = { 1, 1, 1, 1 }; // R,G,B,ALPHA (the latter has no meaning)
+    Matrix lcolor = props.get_color ().matrix_value ();
+    for (int i = 0; i < 3; i++)
+      col[i] = lcolor(i);
+    glLightfv (current_light, GL_DIFFUSE,  col);
+    glLightfv (current_light, GL_SPECULAR, col);
 
 #else
 
-  octave_unused_parameter (props);
-
-  // This shouldn't happen because construction of opengl_renderer
-  // objects is supposed to be impossible if OpenGL is not available.
-
-  panic_impossible ();
+    octave_unused_parameter (props);
+
+    // This shouldn't happen because construction of opengl_renderer
+    // objects is supposed to be impossible if OpenGL is not available.
+
+    panic_impossible ();
 
 #endif
-}
-
-void
-opengl_renderer::draw_light (const light::properties &props)
-{
+  }
+
+  void
+  opengl_renderer::draw_hggroup (const hggroup::properties &props)
+  {
+    draw (props.get_children ());
+  }
+
+  void
+  opengl_renderer::draw_text (const text::properties& props)
+  {
 #if defined (HAVE_OPENGL)
 
-  // enable light source
-  glEnable (current_light);
-
-  // light position
-  float pos[4] = { 0, 0, 0, 0 }; // X,Y,Z,infinite/local
-  Matrix lpos = props.get_position ().matrix_value ();
-  for (int i = 0; i < 3; i++)
-    pos[i] = lpos(i);
-  if (props.style_is ("local"))
-    pos[3] = 1;
-  glLightfv (current_light, GL_POSITION, pos);
-
-  // light color
-  float col[4] = { 1, 1, 1, 1 }; // R,G,B,ALPHA (the latter has no meaning)
-  Matrix lcolor = props.get_color ().matrix_value ();
-  for (int i = 0; i < 3; i++)
-    col[i] = lcolor(i);
-  glLightfv (current_light, GL_DIFFUSE,  col);
-  glLightfv (current_light, GL_SPECULAR, col);
+    if (props.get_string ().is_empty ())
+      return;
+
+    set_font (props);
+
+    Matrix pos = xform.scale (props.get_data_position ());
+    const Matrix bbox = props.get_extent_matrix ();
+
+    // FIXME: handle margin and surrounding box
+    bool blend = glIsEnabled (GL_BLEND);
+
+    glEnable (GL_BLEND);
+    glEnable (GL_ALPHA_TEST);
+    glRasterPos3d (pos(0), pos(1), pos.numel () > 2 ? pos(2) : 0.0);
+    glBitmap (0, 0, 0, 0, bbox(0), bbox(1), 0);
+    glDrawPixels (bbox(2), bbox(3),
+                  GL_RGBA, GL_UNSIGNED_BYTE, props.get_pixels ().data ());
+    glDisable (GL_ALPHA_TEST);
+    if (! blend)
+      glDisable (GL_BLEND);
 
 #else
 
-  octave_unused_parameter (props);
-
-  // This shouldn't happen because construction of opengl_renderer
-  // objects is supposed to be impossible if OpenGL is not available.
-
-  panic_impossible ();
+    octave_unused_parameter (props);
+
+    // This shouldn't happen because construction of opengl_renderer
+    // objects is supposed to be impossible if OpenGL is not available.
+
+    panic_impossible ();
 
 #endif
-}
-
-void
-opengl_renderer::draw_hggroup (const hggroup::properties &props)
-{
-  draw (props.get_children ());
-}
-
-void
-opengl_renderer::draw_text (const text::properties& props)
-{
+  }
+
+  void
+  opengl_renderer::draw_image (const image::properties& props)
+  {
 #if defined (HAVE_OPENGL)
 
-  if (props.get_string ().is_empty ())
-    return;
-
-  set_font (props);
-
-  Matrix pos = xform.scale (props.get_data_position ());
-  const Matrix bbox = props.get_extent_matrix ();
-
-  // FIXME: handle margin and surrounding box
-  bool blend = glIsEnabled (GL_BLEND);
-
-  glEnable (GL_BLEND);
-  glEnable (GL_ALPHA_TEST);
-  glRasterPos3d (pos(0), pos(1), pos.numel () > 2 ? pos(2) : 0.0);
-  glBitmap (0, 0, 0, 0, bbox(0), bbox(1), 0);
-  glDrawPixels (bbox(2), bbox(3),
-                GL_RGBA, GL_UNSIGNED_BYTE, props.get_pixels ().data ());
-  glDisable (GL_ALPHA_TEST);
-  if (! blend)
-    glDisable (GL_BLEND);
+    octave_value cdata = props.get_color_data ();
+    dim_vector dv (cdata.dims ());
+    int h = dv(0);
+    int w = dv(1);
+
+    Matrix x = props.get_xdata ().matrix_value ();
+    Matrix y = props.get_ydata ().matrix_value ();
+
+    // Someone wants us to draw an empty image? No way.
+    if (x.is_empty () || y.is_empty ())
+      return;
+
+    if (w > 1 && x(1) == x(0))
+      x(1) = x(1) + (w-1);
+
+    if (h > 1 && y(1) == y(0))
+      y(1) = y(1) + (h-1);
+
+    const ColumnVector p0 = xform.transform (x(0), y(0), 0);
+    const ColumnVector p1 = xform.transform (x(1), y(1), 0);
+
+    if (octave::math::isnan (p0(0)) || octave::math::isnan (p0(1)) || octave::math::isnan (p1(0)) || octave::math::isnan (p1(1)))
+      {
+        warning ("opengl_renderer: image X,Y data too large to draw");
+        return;
+      }
+
+    // image pixel size in screen pixel units
+    float pix_dx, pix_dy;
+    // image pixel size in normalized units
+    float nor_dx, nor_dy;
+
+    if (w > 1)
+      {
+        pix_dx = (p1(0) - p0(0))/(w-1);
+        nor_dx = (x(1) - x(0))/(w-1);
+      }
+    else
+      {
+        const ColumnVector p1w = xform.transform (x(1) + 1, y(1), 0);
+        pix_dx = p1w(0) - p0(0);
+        nor_dx = 1;
+      }
+
+    if (h > 1)
+      {
+        pix_dy = (p1(1) - p0(1))/(h-1);
+        nor_dy = (y(1) - y(0))/(h-1);
+      }
+    else
+      {
+        const ColumnVector p1h = xform.transform (x(1), y(1) + 1, 0);
+        pix_dy = p1h(1) - p0(1);
+        nor_dy = 1;
+      }
+
+    // OpenGL won't draw any of the image if its origin is outside the
+    // viewport/clipping plane so we must do the clipping ourselves.
+
+    int j0, j1, i0, i1;
+    j0 = 0, j1 = w;
+    i0 = 0, i1 = h;
+
+    float im_xmin = x(0) - nor_dx/2;
+    float im_xmax = x(1) + nor_dx/2;
+    float im_ymin = y(0) - nor_dy/2;
+    float im_ymax = y(1) + nor_dy/2;
+    if (props.is_clipping ()) // clip to axes
+      {
+        if (im_xmin < xmin)
+          j0 += (xmin - im_xmin)/nor_dx + 1;
+        if (im_xmax > xmax)
+          j1 -= (im_xmax - xmax)/nor_dx;
+
+        if (im_ymin < ymin)
+          i0 += (ymin - im_ymin)/nor_dy + 1;
+        if (im_ymax > ymax)
+          i1 -= (im_ymax - ymax)/nor_dy;
+      }
+    else // clip to viewport
+      {
+        GLfloat vp[4];
+        glGetFloatv (GL_VIEWPORT, vp);
+        // FIXME: actually add the code to do it!
+
+      }
+
+    if (i0 >= i1 || j0 >= j1)
+      return;
+
+    glPixelZoom (pix_dx, -pix_dy);
+    glRasterPos3d (im_xmin + nor_dx*j0, im_ymin + nor_dy*i0, 0);
+
+    // by default this is 4
+    glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
+
+    // Expect RGB data
+    if (dv.ndims () == 3 && dv(2) == 3)
+      {
+        if (cdata.is_double_type ())
+          {
+            const NDArray xcdata = cdata.array_value ();
+
+            OCTAVE_LOCAL_BUFFER (GLfloat, a, 3*(j1-j0)*(i1-i0));
+
+            for (int i = i0; i < i1; i++)
+              {
+                for (int j = j0, idx = (i-i0)*(j1-j0)*3; j < j1; j++, idx += 3)
+                  {
+                    a[idx]   = xcdata(i,j,0);
+                    a[idx+1] = xcdata(i,j,1);
+                    a[idx+2] = xcdata(i,j,2);
+                  }
+              }
+
+            draw_pixels (j1-j0, i1-i0, a);
+
+          }
+        else if (cdata.is_single_type ())
+          {
+            const FloatNDArray xcdata = cdata.float_array_value ();
+
+            OCTAVE_LOCAL_BUFFER (GLfloat, a, 3*(j1-j0)*(i1-i0));
+
+            for (int i = i0; i < i1; i++)
+              {
+                for (int j = j0, idx = (i-i0)*(j1-j0)*3; j < j1; j++, idx += 3)
+                  {
+                    a[idx]   = xcdata(i,j,0);
+                    a[idx+1] = xcdata(i,j,1);
+                    a[idx+2] = xcdata(i,j,2);
+                  }
+              }
+
+            draw_pixels (j1-j0, i1-i0, a);
+
+          }
+        else if (cdata.is_uint8_type ())
+          {
+            const uint8NDArray xcdata = cdata.uint8_array_value ();
+
+            OCTAVE_LOCAL_BUFFER (GLubyte, a, 3*(j1-j0)*(i1-i0));
+
+            for (int i = i0; i < i1; i++)
+              {
+                for (int j = j0, idx = (i-i0)*(j1-j0)*3; j < j1; j++, idx += 3)
+                  {
+                    a[idx]   = xcdata(i,j,0);
+                    a[idx+1] = xcdata(i,j,1);
+                    a[idx+2] = xcdata(i,j,2);
+                  }
+              }
+
+            draw_pixels (j1-j0, i1-i0, a);
+
+          }
+        else if (cdata.is_uint16_type ())
+          {
+            const uint16NDArray xcdata = cdata.uint16_array_value ();
+
+            OCTAVE_LOCAL_BUFFER (GLushort, a, 3*(j1-j0)*(i1-i0));
+
+            for (int i = i0; i < i1; i++)
+              {
+                for (int j = j0, idx = (i-i0)*(j1-j0)*3; j < j1; j++, idx += 3)
+                  {
+                    a[idx]   = xcdata(i,j,0);
+                    a[idx+1] = xcdata(i,j,1);
+                    a[idx+2] = xcdata(i,j,2);
+                  }
+              }
+
+            draw_pixels (j1-j0, i1-i0, a);
+
+          }
+        else
+          warning ("opengl_renderer: invalid image data type (expected double, single, uint8, or uint16)");
+      }
+    else
+      warning ("opengl_renderer: invalid image size (expected MxNx3 or MxN)");
+
+    glPixelZoom (1, 1);
 
 #else
 
-  octave_unused_parameter (props);
-
-  // This shouldn't happen because construction of opengl_renderer
-  // objects is supposed to be impossible if OpenGL is not available.
-
-  panic_impossible ();
+    octave_unused_parameter (props);
+
+    // This shouldn't happen because construction of opengl_renderer
+    // objects is supposed to be impossible if OpenGL is not available.
+
+    panic_impossible ();
 
 #endif
-}
-
-void
-opengl_renderer::draw_image (const image::properties& props)
-{
+  }
+
+  void
+  opengl_renderer::set_viewport (int w, int h)
+  {
 #if defined (HAVE_OPENGL)
 
-  octave_value cdata = props.get_color_data ();
-  dim_vector dv (cdata.dims ());
-  int h = dv(0);
-  int w = dv(1);
-
-  Matrix x = props.get_xdata ().matrix_value ();
-  Matrix y = props.get_ydata ().matrix_value ();
-
-  // Someone wants us to draw an empty image? No way.
-  if (x.is_empty () || y.is_empty ())
-    return;
-
-  if (w > 1 && x(1) == x(0))
-    x(1) = x(1) + (w-1);
-
-  if (h > 1 && y(1) == y(0))
-    y(1) = y(1) + (h-1);
-
-  const ColumnVector p0 = xform.transform (x(0), y(0), 0);
-  const ColumnVector p1 = xform.transform (x(1), y(1), 0);
-
-  if (octave::math::isnan (p0(0)) || octave::math::isnan (p0(1)) || octave::math::isnan (p1(0)) || octave::math::isnan (p1(1)))
-    {
-      warning ("opengl_renderer: image X,Y data too large to draw");
-      return;
-    }
-
-  // image pixel size in screen pixel units
-  float pix_dx, pix_dy;
-  // image pixel size in normalized units
-  float nor_dx, nor_dy;
-
-  if (w > 1)
-    {
-      pix_dx = (p1(0) - p0(0))/(w-1);
-      nor_dx = (x(1) - x(0))/(w-1);
-    }
-  else
-    {
-      const ColumnVector p1w = xform.transform (x(1) + 1, y(1), 0);
-      pix_dx = p1w(0) - p0(0);
-      nor_dx = 1;
-    }
-
-  if (h > 1)
-    {
-      pix_dy = (p1(1) - p0(1))/(h-1);
-      nor_dy = (y(1) - y(0))/(h-1);
-    }
-  else
-    {
-      const ColumnVector p1h = xform.transform (x(1), y(1) + 1, 0);
-      pix_dy = p1h(1) - p0(1);
-      nor_dy = 1;
-    }
-
-  // OpenGL won't draw any of the image if its origin is outside the
-  // viewport/clipping plane so we must do the clipping ourselves.
-
-  int j0, j1, i0, i1;
-  j0 = 0, j1 = w;
-  i0 = 0, i1 = h;
-
-  float im_xmin = x(0) - nor_dx/2;
-  float im_xmax = x(1) + nor_dx/2;
-  float im_ymin = y(0) - nor_dy/2;
-  float im_ymax = y(1) + nor_dy/2;
-  if (props.is_clipping ()) // clip to axes
-    {
-      if (im_xmin < xmin)
-        j0 += (xmin - im_xmin)/nor_dx + 1;
-      if (im_xmax > xmax)
-        j1 -= (im_xmax - xmax)/nor_dx;
-
-      if (im_ymin < ymin)
-        i0 += (ymin - im_ymin)/nor_dy + 1;
-      if (im_ymax > ymax)
-        i1 -= (im_ymax - ymax)/nor_dy;
-    }
-  else // clip to viewport
-    {
-      GLfloat vp[4];
-      glGetFloatv (GL_VIEWPORT, vp);
-      // FIXME: actually add the code to do it!
-
-    }
-
-  if (i0 >= i1 || j0 >= j1)
-    return;
-
-  glPixelZoom (pix_dx, -pix_dy);
-  glRasterPos3d (im_xmin + nor_dx*j0, im_ymin + nor_dy*i0, 0);
-
-  // by default this is 4
-  glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
-
-  // Expect RGB data
-  if (dv.ndims () == 3 && dv(2) == 3)
-    {
-      if (cdata.is_double_type ())
-        {
-          const NDArray xcdata = cdata.array_value ();
-
-          OCTAVE_LOCAL_BUFFER (GLfloat, a, 3*(j1-j0)*(i1-i0));
-
-          for (int i = i0; i < i1; i++)
-            {
-              for (int j = j0, idx = (i-i0)*(j1-j0)*3; j < j1; j++, idx += 3)
-                {
-                  a[idx]   = xcdata(i,j,0);
-                  a[idx+1] = xcdata(i,j,1);
-                  a[idx+2] = xcdata(i,j,2);
-                }
-            }
-
-          draw_pixels (j1-j0, i1-i0, a);
-
-        }
-      else if (cdata.is_single_type ())
-        {
-          const FloatNDArray xcdata = cdata.float_array_value ();
-
-          OCTAVE_LOCAL_BUFFER (GLfloat, a, 3*(j1-j0)*(i1-i0));
-
-          for (int i = i0; i < i1; i++)
-            {
-              for (int j = j0, idx = (i-i0)*(j1-j0)*3; j < j1; j++, idx += 3)
-                {
-                  a[idx]   = xcdata(i,j,0);
-                  a[idx+1] = xcdata(i,j,1);
-                  a[idx+2] = xcdata(i,j,2);
-                }
-            }
-
-          draw_pixels (j1-j0, i1-i0, a);
-
-        }
-      else if (cdata.is_uint8_type ())
-        {
-          const uint8NDArray xcdata = cdata.uint8_array_value ();
-
-          OCTAVE_LOCAL_BUFFER (GLubyte, a, 3*(j1-j0)*(i1-i0));
-
-          for (int i = i0; i < i1; i++)
-            {
-              for (int j = j0, idx = (i-i0)*(j1-j0)*3; j < j1; j++, idx += 3)
-                {
-                  a[idx]   = xcdata(i,j,0);
-                  a[idx+1] = xcdata(i,j,1);
-                  a[idx+2] = xcdata(i,j,2);
-                }
-            }
-
-          draw_pixels (j1-j0, i1-i0, a);
-
-        }
-      else if (cdata.is_uint16_type ())
-        {
-          const uint16NDArray xcdata = cdata.uint16_array_value ();
-
-          OCTAVE_LOCAL_BUFFER (GLushort, a, 3*(j1-j0)*(i1-i0));
-
-          for (int i = i0; i < i1; i++)
-            {
-              for (int j = j0, idx = (i-i0)*(j1-j0)*3; j < j1; j++, idx += 3)
-                {
-                  a[idx]   = xcdata(i,j,0);
-                  a[idx+1] = xcdata(i,j,1);
-                  a[idx+2] = xcdata(i,j,2);
-                }
-            }
-
-          draw_pixels (j1-j0, i1-i0, a);
-
-        }
-      else
-        warning ("opengl_renderer: invalid image data type (expected double, single, uint8, or uint16)");
-    }
-  else
-    warning ("opengl_renderer: invalid image size (expected MxNx3 or MxN)");
-
-  glPixelZoom (1, 1);
+    glViewport (0, 0, w, h);
 
 #else
 
-  octave_unused_parameter (props);
-
-  // This shouldn't happen because construction of opengl_renderer
-  // objects is supposed to be impossible if OpenGL is not available.
-
-  panic_impossible ();
+    octave_unused_parameter (w);
+    octave_unused_parameter (h);
+
+    // This shouldn't happen because construction of opengl_renderer
+    // objects is supposed to be impossible if OpenGL is not available.
+
+    panic_impossible ();
 
 #endif
-}
-
-void
-opengl_renderer::set_viewport (int w, int h)
-{
+  }
+
+  void
+  opengl_renderer::draw_pixels (int width, int height, const float *data)
+  {
 #if defined (HAVE_OPENGL)
 
-  glViewport (0, 0, w, h);
+    glDrawPixels (width, height, GL_RGB, GL_FLOAT, data);
 
 #else
 
-  octave_unused_parameter (w);
-  octave_unused_parameter (h);
-
-  // This shouldn't happen because construction of opengl_renderer
-  // objects is supposed to be impossible if OpenGL is not available.
-
-  panic_impossible ();
+    octave_unused_parameter (width);
+    octave_unused_parameter (height);
+    octave_unused_parameter (data);
+
+    // This shouldn't happen because construction of opengl_renderer
+    // objects is supposed to be impossible if OpenGL is not available.
+
+    panic_impossible ();
 
 #endif
-}
-
-void
-opengl_renderer::draw_pixels (int width, int height, const float *data)
-{
+  }
+
+  void
+  opengl_renderer::draw_pixels (int width, int height, const uint8_t *data)
+  {
 #if defined (HAVE_OPENGL)
 
-  glDrawPixels (width, height, GL_RGB, GL_FLOAT, data);
-
-#else
-
-  octave_unused_parameter (width);
-  octave_unused_parameter (height);
-  octave_unused_parameter (data);
-
-  // This shouldn't happen because construction of opengl_renderer
-  // objects is supposed to be impossible if OpenGL is not available.
-
-  panic_impossible ();
-
-#endif
-}
-
-void
-opengl_renderer::draw_pixels (int width, int height, const uint8_t *data)
-{
-#if defined (HAVE_OPENGL)
-
-  glDrawPixels (width, height, GL_RGB, GL_UNSIGNED_BYTE, data);
+    glDrawPixels (width, height, GL_RGB, GL_UNSIGNED_BYTE, data);
 
 #else
 
-  octave_unused_parameter (width);
-  octave_unused_parameter (height);
-  octave_unused_parameter (data);
-
-  // This shouldn't happen because construction of opengl_renderer
-  // objects is supposed to be impossible if OpenGL is not available.
-
-  panic_impossible ();
+    octave_unused_parameter (width);
+    octave_unused_parameter (height);
+    octave_unused_parameter (data);
+
+    // This shouldn't happen because construction of opengl_renderer
+    // objects is supposed to be impossible if OpenGL is not available.
+
+    panic_impossible ();
 
 #endif
-}
-
-void
-opengl_renderer::draw_pixels (int width, int height, const uint16_t *data)
-{
+  }
+
+  void
+  opengl_renderer::draw_pixels (int width, int height, const uint16_t *data)
+  {
 #if defined (HAVE_OPENGL)
 
-  glDrawPixels (width, height, GL_RGB, GL_UNSIGNED_SHORT, data);
+    glDrawPixels (width, height, GL_RGB, GL_UNSIGNED_SHORT, data);
 
 #else
 
-  octave_unused_parameter (width);
-  octave_unused_parameter (height);
-  octave_unused_parameter (data);
-
-  // This shouldn't happen because construction of opengl_renderer
-  // objects is supposed to be impossible if OpenGL is not available.
-
-  panic_impossible ();
+    octave_unused_parameter (width);
+    octave_unused_parameter (height);
+    octave_unused_parameter (data);
+
+    // This shouldn't happen because construction of opengl_renderer
+    // objects is supposed to be impossible if OpenGL is not available.
+
+    panic_impossible ();
 
 #endif
-}
-
-void
-opengl_renderer::set_color (const Matrix& c)
-{
+  }
+
+  void
+  opengl_renderer::set_color (const Matrix& c)
+  {
 #if defined (HAVE_OPENGL)
 
-  glColor3dv (c.data ());
-
-  txt_renderer.set_color (c);
+    glColor3dv (c.data ());
+
+    txt_renderer.set_color (c);
 
 #else
 
-  octave_unused_parameter (c);
-
-  // This shouldn't happen because construction of opengl_renderer
-  // objects is supposed to be impossible if OpenGL is not available.
-
-  panic_impossible ();
+    octave_unused_parameter (c);
+
+    // This shouldn't happen because construction of opengl_renderer
+    // objects is supposed to be impossible if OpenGL is not available.
+
+    panic_impossible ();
 
 #endif
-}
-
-void
-opengl_renderer::set_font (const base_properties& props)
-{
-  txt_renderer.set_font (props.get ("fontname").string_value (),
-                         props.get ("fontweight").string_value (),
-                         props.get ("fontangle").string_value (),
-                         props.get ("fontsize_points").double_value ());
-}
-
-void
-opengl_renderer::set_polygon_offset (bool on, float offset)
-{
+  }
+
+  void
+  opengl_renderer::set_font (const base_properties& props)
+  {
+    txt_renderer.set_font (props.get ("fontname").string_value (),
+                           props.get ("fontweight").string_value (),
+                           props.get ("fontangle").string_value (),
+                           props.get ("fontsize_points").double_value ());
+  }
+
+  void
+  opengl_renderer::set_polygon_offset (bool on, float offset)
+  {
 #if defined (HAVE_OPENGL)
 
-  if (on)
-    {
-      glEnable (GL_POLYGON_OFFSET_FILL);
-      glEnable (GL_POLYGON_OFFSET_LINE);
-      glPolygonOffset (offset, offset);
-    }
-  else
-    {
-      glDisable (GL_POLYGON_OFFSET_FILL);
-      glDisable (GL_POLYGON_OFFSET_LINE);
-    }
+    if (on)
+      {
+        glEnable (GL_POLYGON_OFFSET_FILL);
+        glEnable (GL_POLYGON_OFFSET_LINE);
+        glPolygonOffset (offset, offset);
+      }
+    else
+      {
+        glDisable (GL_POLYGON_OFFSET_FILL);
+        glDisable (GL_POLYGON_OFFSET_LINE);
+      }
 
 #else
 
-  octave_unused_parameter (on);
-  octave_unused_parameter (offset);
-
-  // This shouldn't happen because construction of opengl_renderer
-  // objects is supposed to be impossible if OpenGL is not available.
-
-  panic_impossible ();
+    octave_unused_parameter (on);
+    octave_unused_parameter (offset);
+
+    // This shouldn't happen because construction of opengl_renderer
+    // objects is supposed to be impossible if OpenGL is not available.
+
+    panic_impossible ();
 
 #endif
-}
-
-void
-opengl_renderer::set_linewidth (float w)
-{
+  }
+
+  void
+  opengl_renderer::set_linewidth (float w)
+  {
 #if defined (HAVE_OPENGL)
 
-  glLineWidth (w);
+    glLineWidth (w);
 
 #else
 
-  octave_unused_parameter (w);
-
-  // This shouldn't happen because construction of opengl_renderer
-  // objects is supposed to be impossible if OpenGL is not available.
-
-  panic_impossible ();
+    octave_unused_parameter (w);
+
+    // This shouldn't happen because construction of opengl_renderer
+    // objects is supposed to be impossible if OpenGL is not available.
+
+    panic_impossible ();
 
 #endif
-}
-
-void
-opengl_renderer::set_linestyle (const std::string& s, bool use_stipple)
-{
+  }
+
+  void
+  opengl_renderer::set_linestyle (const std::string& s, bool use_stipple)
+  {
 #if defined (HAVE_OPENGL)
 
-  bool solid = false;
-
-  if (s == "-")
-    {
-      glLineStipple (1, static_cast<unsigned short> (0xFFFF));
-      solid = true;
-    }
-  else if (s == ":")
-    glLineStipple (1, static_cast<unsigned short> (0x8888));
-  else if (s == "--")
-    glLineStipple (1, static_cast<unsigned short> (0xF0F0));
-  else if (s == "-.")
-    glLineStipple (1, static_cast<unsigned short> (0x020F));
-  else
-    glLineStipple (1, static_cast<unsigned short> (0x0000));
-
-  if (solid && ! use_stipple)
-    glDisable (GL_LINE_STIPPLE);
-  else
-    glEnable (GL_LINE_STIPPLE);
+    bool solid = false;
+
+    if (s == "-")
+      {
+        glLineStipple (1, static_cast<unsigned short> (0xFFFF));
+        solid = true;
+      }
+    else if (s == ":")
+      glLineStipple (1, static_cast<unsigned short> (0x8888));
+    else if (s == "--")
+      glLineStipple (1, static_cast<unsigned short> (0xF0F0));
+    else if (s == "-.")
+      glLineStipple (1, static_cast<unsigned short> (0x020F));
+    else
+      glLineStipple (1, static_cast<unsigned short> (0x0000));
+
+    if (solid && ! use_stipple)
+      glDisable (GL_LINE_STIPPLE);
+    else
+      glEnable (GL_LINE_STIPPLE);
 
 #else
 
-  octave_unused_parameter (s);
-  octave_unused_parameter (use_stipple);
-
-  // This shouldn't happen because construction of opengl_renderer
-  // objects is supposed to be impossible if OpenGL is not available.
-
-  panic_impossible ();
+    octave_unused_parameter (s);
+    octave_unused_parameter (use_stipple);
+
+    // This shouldn't happen because construction of opengl_renderer
+    // objects is supposed to be impossible if OpenGL is not available.
+
+    panic_impossible ();
 
 #endif
-}
-
-void
-opengl_renderer::set_clipbox (double x1, double x2, double y1, double y2,
-                              double z1, double z2)
-{
+  }
+
+  void
+  opengl_renderer::set_clipbox (double x1, double x2, double y1, double y2,
+                                double z1, double z2)
+  {
 #if defined (HAVE_OPENGL)
 
-  double dx = (x2-x1);
-  double dy = (y2-y1);
-  double dz = (z2-z1);
-
-  x1 -= 0.001*dx; x2 += 0.001*dx;
-  y1 -= 0.001*dy; y2 += 0.001*dy;
-  z1 -= 0.001*dz; z2 += 0.001*dz;
-
-  ColumnVector p (4, 0.0);
-
-  p(0) = -1; p(3) = x2;
-  glClipPlane (GL_CLIP_PLANE0, p.data ());
-  p(0) = 1; p(3) = -x1;
-  glClipPlane (GL_CLIP_PLANE1, p.data ());
-  p(0) = 0; p(1) = -1; p(3) = y2;
-  glClipPlane (GL_CLIP_PLANE2, p.data ());
-  p(1) = 1; p(3) = -y1;
-  glClipPlane (GL_CLIP_PLANE3, p.data ());
-  p(1) = 0; p(2) = -1; p(3) = z2;
-  glClipPlane (GL_CLIP_PLANE4, p.data ());
-  p(2) = 1; p(3) = -z1;
-  glClipPlane (GL_CLIP_PLANE5, p.data ());
-
-  xmin = x1; xmax = x2;
-  ymin = y1; ymax = y2;
-  zmin = z1; zmax = z2;
+    double dx = (x2-x1);
+    double dy = (y2-y1);
+    double dz = (z2-z1);
+
+    x1 -= 0.001*dx; x2 += 0.001*dx;
+    y1 -= 0.001*dy; y2 += 0.001*dy;
+    z1 -= 0.001*dz; z2 += 0.001*dz;
+
+    ColumnVector p (4, 0.0);
+
+    p(0) = -1; p(3) = x2;
+    glClipPlane (GL_CLIP_PLANE0, p.data ());
+    p(0) = 1; p(3) = -x1;
+    glClipPlane (GL_CLIP_PLANE1, p.data ());
+    p(0) = 0; p(1) = -1; p(3) = y2;
+    glClipPlane (GL_CLIP_PLANE2, p.data ());
+    p(1) = 1; p(3) = -y1;
+    glClipPlane (GL_CLIP_PLANE3, p.data ());
+    p(1) = 0; p(2) = -1; p(3) = z2;
+    glClipPlane (GL_CLIP_PLANE4, p.data ());
+    p(2) = 1; p(3) = -z1;
+    glClipPlane (GL_CLIP_PLANE5, p.data ());
+
+    xmin = x1; xmax = x2;
+    ymin = y1; ymax = y2;
+    zmin = z1; zmax = z2;
 
 #else
 
-  octave_unused_parameter (x1);
-  octave_unused_parameter (x2);
-  octave_unused_parameter (y1);
-  octave_unused_parameter (y2);
-  octave_unused_parameter (z1);
-  octave_unused_parameter (z2);
-
-  // This shouldn't happen because construction of opengl_renderer
-  // objects is supposed to be impossible if OpenGL is not available.
-
-  panic_impossible ();
+    octave_unused_parameter (x1);
+    octave_unused_parameter (x2);
+    octave_unused_parameter (y1);
+    octave_unused_parameter (y2);
+    octave_unused_parameter (z1);
+    octave_unused_parameter (z2);
+
+    // This shouldn't happen because construction of opengl_renderer
+    // objects is supposed to be impossible if OpenGL is not available.
+
+    panic_impossible ();
 
 #endif
-}
-
-void
-opengl_renderer::set_clipping (bool enable)
-{
+  }
+
+  void
+  opengl_renderer::set_clipping (bool enable)
+  {
 #if defined (HAVE_OPENGL)
 
-  bool has_clipping = (glIsEnabled (GL_CLIP_PLANE0) == GL_TRUE);
-
-  if (enable != has_clipping)
-    {
-      if (enable)
-        for (int i = 0; i < 6; i++)
-          glEnable (GL_CLIP_PLANE0+i);
-      else
-        for (int i = 0; i < 6; i++)
-          glDisable (GL_CLIP_PLANE0+i);
-    }
+    bool has_clipping = (glIsEnabled (GL_CLIP_PLANE0) == GL_TRUE);
+
+    if (enable != has_clipping)
+      {
+        if (enable)
+          for (int i = 0; i < 6; i++)
+            glEnable (GL_CLIP_PLANE0+i);
+        else
+          for (int i = 0; i < 6; i++)
+            glDisable (GL_CLIP_PLANE0+i);
+      }
 
 #else
 
-  octave_unused_parameter (enable);
-
-  // This shouldn't happen because construction of opengl_renderer
-  // objects is supposed to be impossible if OpenGL is not available.
-
-  panic_impossible ();
+    octave_unused_parameter (enable);
+
+    // This shouldn't happen because construction of opengl_renderer
+    // objects is supposed to be impossible if OpenGL is not available.
+
+    panic_impossible ();
 
 #endif
-}
-
-void
-opengl_renderer::init_marker (const std::string& m, double size, float width)
-{
+  }
+
+  void
+  opengl_renderer::init_marker (const std::string& m, double size, float width)
+  {
 #if defined (HAVE_OPENGL)
 
 #  if defined (HAVE_FRAMEWORK_OPENGL)
-  GLint vw[4];
+    GLint vw[4];
 #  else
-  int vw[4];
+    int vw[4];
 #  endif
 
-  glGetIntegerv (GL_VIEWPORT, vw);
-
-  glMatrixMode (GL_PROJECTION);
-  glPushMatrix ();
-  glLoadIdentity ();
-  glOrtho (0, vw[2], vw[3], 0, xZ1, xZ2);
-  glMatrixMode (GL_MODELVIEW);
-  glPushMatrix ();
-
-  set_clipping (false);
-  set_linewidth (width);
-
-  marker_id = make_marker_list (m, size, false);
-  filled_marker_id = make_marker_list (m, size, true);
+    glGetIntegerv (GL_VIEWPORT, vw);
+
+    glMatrixMode (GL_PROJECTION);
+    glPushMatrix ();
+    glLoadIdentity ();
+    glOrtho (0, vw[2], vw[3], 0, xZ1, xZ2);
+    glMatrixMode (GL_MODELVIEW);
+    glPushMatrix ();
+
+    set_clipping (false);
+    set_linewidth (width);
+
+    marker_id = make_marker_list (m, size, false);
+    filled_marker_id = make_marker_list (m, size, true);
 
 #else
 
-  octave_unused_parameter (m);
-  octave_unused_parameter (size);
-  octave_unused_parameter (width);
-
-  // This shouldn't happen because construction of opengl_renderer
-  // objects is supposed to be impossible if OpenGL is not available.
-
-  panic_impossible ();
+    octave_unused_parameter (m);
+    octave_unused_parameter (size);
+    octave_unused_parameter (width);
+
+    // This shouldn't happen because construction of opengl_renderer
+    // objects is supposed to be impossible if OpenGL is not available.
+
+    panic_impossible ();
 
 #endif
-}
-
-void
-opengl_renderer::end_marker (void)
-{
+  }
+
+  void
+  opengl_renderer::end_marker (void)
+  {
 #if defined (HAVE_OPENGL)
 
-  glDeleteLists (marker_id, 1);
-  glDeleteLists (filled_marker_id, 1);
-
-  glMatrixMode (GL_MODELVIEW);
-  glPopMatrix ();
-  glMatrixMode (GL_PROJECTION);
-  glPopMatrix ();
-  set_linewidth (0.5f);
+    glDeleteLists (marker_id, 1);
+    glDeleteLists (filled_marker_id, 1);
+
+    glMatrixMode (GL_MODELVIEW);
+    glPopMatrix ();
+    glMatrixMode (GL_PROJECTION);
+    glPopMatrix ();
+    set_linewidth (0.5f);
 
 #else
 
-  // This shouldn't happen because construction of opengl_renderer
-  // objects is supposed to be impossible if OpenGL is not available.
-
-  panic_impossible ();
+    // This shouldn't happen because construction of opengl_renderer
+    // objects is supposed to be impossible if OpenGL is not available.
+
+    panic_impossible ();
 
 #endif
-}
-
-void
-opengl_renderer::draw_marker (double x, double y, double z,
-                              const Matrix& lc, const Matrix& fc)
-{
+  }
+
+  void
+  opengl_renderer::draw_marker (double x, double y, double z,
+                                const Matrix& lc, const Matrix& fc)
+  {
 #if defined (HAVE_OPENGL)
 
-  ColumnVector tmp = xform.transform (x, y, z, false);
-
-  glLoadIdentity ();
-  glTranslated (tmp(0), tmp(1), -tmp(2));
-
-  if (filled_marker_id > 0 && fc.numel () > 0)
-    {
-      glColor3dv (fc.data ());
-      set_polygon_offset (true, -1.0);
-      glCallList (filled_marker_id);
-      if (lc.numel () > 0)
-        {
-          glColor3dv (lc.data ());
-          glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
-          glEdgeFlag (GL_TRUE);
-          set_polygon_offset (true, -2.0);
-          glCallList (filled_marker_id);
-          glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
-        }
-      set_polygon_offset (false);
-    }
-  else if (marker_id > 0 && lc.numel () > 0)
-    {
-      glColor3dv (lc.data ());
-      glCallList (marker_id);
-    }
+    ColumnVector tmp = xform.transform (x, y, z, false);
+
+    glLoadIdentity ();
+    glTranslated (tmp(0), tmp(1), -tmp(2));
+
+    if (filled_marker_id > 0 && fc.numel () > 0)
+      {
+        glColor3dv (fc.data ());
+        set_polygon_offset (true, -1.0);
+        glCallList (filled_marker_id);
+        if (lc.numel () > 0)
+          {
+            glColor3dv (lc.data ());
+            glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
+            glEdgeFlag (GL_TRUE);
+            set_polygon_offset (true, -2.0);
+            glCallList (filled_marker_id);
+            glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
+          }
+        set_polygon_offset (false);
+      }
+    else if (marker_id > 0 && lc.numel () > 0)
+      {
+        glColor3dv (lc.data ());
+        glCallList (marker_id);
+      }
 
 #else
 
-  octave_unused_parameter (x);
-  octave_unused_parameter (y);
-  octave_unused_parameter (z);
-  octave_unused_parameter (lc);
-  octave_unused_parameter (fc);
-
-  // This shouldn't happen because construction of opengl_renderer
-  // objects is supposed to be impossible if OpenGL is not available.
-
-  panic_impossible ();
+    octave_unused_parameter (x);
+    octave_unused_parameter (y);
+    octave_unused_parameter (z);
+    octave_unused_parameter (lc);
+    octave_unused_parameter (fc);
+
+    // This shouldn't happen because construction of opengl_renderer
+    // objects is supposed to be impossible if OpenGL is not available.
+
+    panic_impossible ();
 
 #endif
-}
-
-void
-opengl_renderer::set_normal (int bfl_mode, const NDArray& n, int j, int i)
-{
+  }
+
+  void
+  opengl_renderer::set_normal (int bfl_mode, const NDArray& n, int j, int i)
+  {
 #if defined (HAVE_OPENGL)
 
-  double x = n(j,i,0);
-  double y = n(j,i,1);
-  double z = n(j,i,2);
-
-  double d = sqrt (x*x + y*y + z*z);
-
-  double dir = 1.0;
-
-  if (bfl_mode > 0)
-    dir = ((x * view_vector(0) + y * view_vector(1) + z * view_vector(2) < 0)
-           ? ((bfl_mode > 1) ? 0.0 : -1.0) : 1.0);
-
-  glNormal3d (dir*x/d, dir*y/d, dir*z/d);
+    double x = n(j,i,0);
+    double y = n(j,i,1);
+    double z = n(j,i,2);
+
+    double d = sqrt (x*x + y*y + z*z);
+
+    double dir = 1.0;
+
+    if (bfl_mode > 0)
+      dir = ((x * view_vector(0) + y * view_vector(1) + z * view_vector(2) < 0)
+             ? ((bfl_mode > 1) ? 0.0 : -1.0) : 1.0);
+
+    glNormal3d (dir*x/d, dir*y/d, dir*z/d);
 
 #else
 
-  octave_unused_parameter (bfl_mode);
-  octave_unused_parameter (n);
-  octave_unused_parameter (j);
-  octave_unused_parameter (i);
-
-  // This shouldn't happen because construction of opengl_renderer
-  // objects is supposed to be impossible if OpenGL is not available.
-
-  panic_impossible ();
+    octave_unused_parameter (bfl_mode);
+    octave_unused_parameter (n);
+    octave_unused_parameter (j);
+    octave_unused_parameter (i);
+
+    // This shouldn't happen because construction of opengl_renderer
+    // objects is supposed to be impossible if OpenGL is not available.
+
+    panic_impossible ();
 
 #endif
-}
-
-unsigned int
-opengl_renderer::make_marker_list (const std::string& marker, double size,
-                                   bool filled) const
-{
+  }
+
+  unsigned int
+  opengl_renderer::make_marker_list (const std::string& marker, double size,
+                                     bool filled) const
+  {
 #if defined (HAVE_OPENGL)
 
-  char c = marker[0];
-
-  if (filled && (c == '+' || c == 'x' || c == '*' || c == '.'))
-    return 0;
-
-  unsigned int ID = glGenLists (1);
-  double sz = size * toolkit.get_screen_resolution () / 72.0;
-
-  // constants for the * marker
-  const double sqrt2d4 = 0.35355339059327;
-  double tt = sz*sqrt2d4;
-
-  glNewList (ID, GL_COMPILE);
-
-  switch (marker[0])
-    {
-    case '+':
-      glBegin (GL_LINES);
-      glVertex2d (-sz/2, 0);
-      glVertex2d (sz/2, 0);
-      glVertex2d (0, -sz/2);
-      glVertex2d (0, sz/2);
-      glEnd ();
-      break;
-    case 'x':
-      glBegin (GL_LINES);
-      glVertex2d (-sz/2, -sz/2);
-      glVertex2d (sz/2, sz/2);
-      glVertex2d (-sz/2, sz/2);
-      glVertex2d (sz/2, -sz/2);
-      glEnd ();
-      break;
-    case '*':
-      glBegin (GL_LINES);
-      glVertex2d (-sz/2, 0);
-      glVertex2d (sz/2, 0);
-      glVertex2d (0, -sz/2);
-      glVertex2d (0, sz/2);
-      glVertex2d (-tt, -tt);
-      glVertex2d (+tt, +tt);
-      glVertex2d (-tt, +tt);
-      glVertex2d (+tt, -tt);
-      glEnd ();
-      break;
-    case '.':
-      {
-        // The dot marker is special and is drawn at 1/3rd the specified size
-
-        // Ensure that something is drawn even at very small markersizes
-        if (sz > 0 && sz < 3)
-          sz = 3;
-
-        int div = static_cast <int> (M_PI * sz / 12);
-        if (! (div % 2))
-          div += 1;               // ensure odd number for left/right symmetry
-        div = std::max (div, 3);  // ensure at least a few vertices are drawn
-        double ang_step = M_PI / div;
-
-        glBegin (GL_POLYGON);
-        for (double ang = 0; ang < 2*M_PI; ang += ang_step)
-          glVertex2d (sz/6*cos (ang), sz/6*sin (ang));
-        glEnd ();
-      }
-      break;
-    case 's':
-      glBegin (filled ? GL_POLYGON : GL_LINE_LOOP);
-      glVertex2d (-sz/2, -sz/2);
-      glVertex2d (-sz/2, sz/2);
-      glVertex2d (sz/2, sz/2);
-      glVertex2d (sz/2, -sz/2);
-      glEnd ();
-      break;
-    case 'o':
+    char c = marker[0];
+
+    if (filled && (c == '+' || c == 'x' || c == '*' || c == '.'))
+      return 0;
+
+    unsigned int ID = glGenLists (1);
+    double sz = size * toolkit.get_screen_resolution () / 72.0;
+
+    // constants for the * marker
+    const double sqrt2d4 = 0.35355339059327;
+    double tt = sz*sqrt2d4;
+
+    glNewList (ID, GL_COMPILE);
+
+    switch (marker[0])
       {
-        int div = static_cast <int> (M_PI * sz / 4);
-        if (! (div % 2))
-          div += 1;               // ensure odd number for left/right symmetry
-        div = std::max (div, 5);  // ensure at least a few vertices are drawn
-        double ang_step = M_PI / div;
-
+      case '+':
+        glBegin (GL_LINES);
+        glVertex2d (-sz/2, 0);
+        glVertex2d (sz/2, 0);
+        glVertex2d (0, -sz/2);
+        glVertex2d (0, sz/2);
+        glEnd ();
+        break;
+      case 'x':
+        glBegin (GL_LINES);
+        glVertex2d (-sz/2, -sz/2);
+        glVertex2d (sz/2, sz/2);
+        glVertex2d (-sz/2, sz/2);
+        glVertex2d (sz/2, -sz/2);
+        glEnd ();
+        break;
+      case '*':
+        glBegin (GL_LINES);
+        glVertex2d (-sz/2, 0);
+        glVertex2d (sz/2, 0);
+        glVertex2d (0, -sz/2);
+        glVertex2d (0, sz/2);
+        glVertex2d (-tt, -tt);
+        glVertex2d (+tt, +tt);
+        glVertex2d (-tt, +tt);
+        glVertex2d (+tt, -tt);
+        glEnd ();
+        break;
+      case '.':
+        {
+          // The dot marker is special and is drawn at 1/3rd the specified size
+
+          // Ensure that something is drawn even at very small markersizes
+          if (sz > 0 && sz < 3)
+            sz = 3;
+
+          int div = static_cast <int> (M_PI * sz / 12);
+          if (! (div % 2))
+            div += 1;               // ensure odd number for left/right symmetry
+          div = std::max (div, 3);  // ensure at least a few vertices are drawn
+          double ang_step = M_PI / div;
+
+          glBegin (GL_POLYGON);
+          for (double ang = 0; ang < 2*M_PI; ang += ang_step)
+            glVertex2d (sz/6*cos (ang), sz/6*sin (ang));
+          glEnd ();
+        }
+        break;
+      case 's':
         glBegin (filled ? GL_POLYGON : GL_LINE_LOOP);
-        for (double ang = 0; ang < 2*M_PI; ang += ang_step)
-          glVertex2d (sz/2*cos (ang), sz/2*sin (ang));
+        glVertex2d (-sz/2, -sz/2);
+        glVertex2d (-sz/2, sz/2);
+        glVertex2d (sz/2, sz/2);
+        glVertex2d (sz/2, -sz/2);
+        glEnd ();
+        break;
+      case 'o':
+        {
+          int div = static_cast <int> (M_PI * sz / 4);
+          if (! (div % 2))
+            div += 1;               // ensure odd number for left/right symmetry
+          div = std::max (div, 5);  // ensure at least a few vertices are drawn
+          double ang_step = M_PI / div;
+
+          glBegin (filled ? GL_POLYGON : GL_LINE_LOOP);
+          for (double ang = 0; ang < 2*M_PI; ang += ang_step)
+            glVertex2d (sz/2*cos (ang), sz/2*sin (ang));
+          glEnd ();
+        }
+        break;
+      case 'd':
+        glBegin (filled ? GL_POLYGON : GL_LINE_LOOP);
+        glVertex2d (0, -sz/2);
+        glVertex2d (sz/2, 0);
+        glVertex2d (0, sz/2);
+        glVertex2d (-sz/2, 0);
+        glEnd ();
+        break;
+      case 'v':
+        glBegin (filled ? GL_POLYGON : GL_LINE_LOOP);
+        glVertex2d (0, sz/2);
+        glVertex2d (sz/2, -sz/2);
+        glVertex2d (-sz/2, -sz/2);
+        glEnd ();
+        break;
+      case '^':
+        glBegin (filled ? GL_POLYGON : GL_LINE_LOOP);
+        glVertex2d (0, -sz/2);
+        glVertex2d (-sz/2, sz/2);
+        glVertex2d (sz/2, sz/2);
         glEnd ();
+        break;
+      case '>':
+        glBegin (filled ? GL_POLYGON : GL_LINE_LOOP);
+        glVertex2d (sz/2, 0);
+        glVertex2d (-sz/2, sz/2);
+        glVertex2d (-sz/2, -sz/2);
+        glEnd ();
+        break;
+      case '<':
+        glBegin (filled ? GL_POLYGON : GL_LINE_LOOP);
+        glVertex2d (-sz/2, 0);
+        glVertex2d (sz/2, -sz/2);
+        glVertex2d (sz/2, sz/2);
+        glEnd ();
+        break;
+      case 'p':
+        {
+          double ang, r, dr;
+          dr = 1.0 - sin (M_PI/10)/sin (3*M_PI/10)*1.02;
+
+          glBegin (filled ? GL_POLYGON : GL_LINE_LOOP);
+          for (int i = 0; i < 2*5; i++)
+            {
+              ang = (-0.5 + double (i+1) / 5) * M_PI;
+              r = 1.0 - (dr * fmod (double (i+1), 2.0));
+              glVertex2d (sz/2*r*cos (ang), sz/2*r*sin (ang));
+            }
+          glEnd ();
+        }
+        break;
+      case 'h':
+        {
+          double ang, r, dr;
+          dr = 1.0 - 0.5/sin (M_PI/3)*1.02;
+
+          glBegin (filled ? GL_POLYGON : GL_LINE_LOOP);
+          for (int i = 0; i < 2*6; i++)
+            {
+              ang = (0.5 + double (i+1) / 6.0) * M_PI;
+              r = 1.0 - (dr * fmod (double (i+1), 2.0));
+              glVertex2d (sz/2*r*cos (ang), sz/2*r*sin (ang));
+            }
+          glEnd ();
+        }
+        break;
+      default:
+        warning ("opengl_renderer: unsupported marker '%s'", marker.c_str ());
+        break;
       }
-      break;
-    case 'd':
-      glBegin (filled ? GL_POLYGON : GL_LINE_LOOP);
-      glVertex2d (0, -sz/2);
-      glVertex2d (sz/2, 0);
-      glVertex2d (0, sz/2);
-      glVertex2d (-sz/2, 0);
-      glEnd ();
-      break;
-    case 'v':
-      glBegin (filled ? GL_POLYGON : GL_LINE_LOOP);
-      glVertex2d (0, sz/2);
-      glVertex2d (sz/2, -sz/2);
-      glVertex2d (-sz/2, -sz/2);
-      glEnd ();
-      break;
-    case '^':
-      glBegin (filled ? GL_POLYGON : GL_LINE_LOOP);
-      glVertex2d (0, -sz/2);
-      glVertex2d (-sz/2, sz/2);
-      glVertex2d (sz/2, sz/2);
-      glEnd ();
-      break;
-    case '>':
-      glBegin (filled ? GL_POLYGON : GL_LINE_LOOP);
-      glVertex2d (sz/2, 0);
-      glVertex2d (-sz/2, sz/2);
-      glVertex2d (-sz/2, -sz/2);
-      glEnd ();
-      break;
-    case '<':
-      glBegin (filled ? GL_POLYGON : GL_LINE_LOOP);
-      glVertex2d (-sz/2, 0);
-      glVertex2d (sz/2, -sz/2);
-      glVertex2d (sz/2, sz/2);
-      glEnd ();
-      break;
-    case 'p':
-      {
-        double ang, r, dr;
-        dr = 1.0 - sin (M_PI/10)/sin (3*M_PI/10)*1.02;
-
-        glBegin (filled ? GL_POLYGON : GL_LINE_LOOP);
-        for (int i = 0; i < 2*5; i++)
-          {
-            ang = (-0.5 + double (i+1) / 5) * M_PI;
-            r = 1.0 - (dr * fmod (double (i+1), 2.0));
-            glVertex2d (sz/2*r*cos (ang), sz/2*r*sin (ang));
-          }
-        glEnd ();
-      }
-      break;
-    case 'h':
-      {
-        double ang, r, dr;
-        dr = 1.0 - 0.5/sin (M_PI/3)*1.02;
-
-        glBegin (filled ? GL_POLYGON : GL_LINE_LOOP);
-        for (int i = 0; i < 2*6; i++)
-          {
-            ang = (0.5 + double (i+1) / 6.0) * M_PI;
-            r = 1.0 - (dr * fmod (double (i+1), 2.0));
-            glVertex2d (sz/2*r*cos (ang), sz/2*r*sin (ang));
-          }
-        glEnd ();
-      }
-      break;
-    default:
-      warning ("opengl_renderer: unsupported marker '%s'", marker.c_str ());
-      break;
-    }
-
-  glEndList ();
-
-  return ID;
+
+    glEndList ();
+
+    return ID;
 
 #else
 
-  octave_unused_parameter (marker);
-  octave_unused_parameter (size);
-  octave_unused_parameter (filled);
-
-  // This shouldn't happen because construction of opengl_renderer
-  // objects is supposed to be impossible if OpenGL is not available.
-
-  panic_impossible ();
+    octave_unused_parameter (marker);
+    octave_unused_parameter (size);
+    octave_unused_parameter (filled);
+
+    // This shouldn't happen because construction of opengl_renderer
+    // objects is supposed to be impossible if OpenGL is not available.
+
+    panic_impossible ();
 
 #endif
-}
-
-void
-opengl_renderer::text_to_pixels (const std::string& txt,
-                                 uint8NDArray& pixels,
-                                 Matrix& bbox,
-                                 int halign, int valign, double rotation)
-{
-  txt_renderer.text_to_pixels (txt, pixels, bbox, halign, valign,
-                               rotation, interpreter);
-}
-
-void
-opengl_renderer::text_to_strlist (const std::string& txt,
-                                  std::list<text_renderer::string>& lst,
-                                  Matrix& bbox,
-                                  int halign, int valign, double rotation)
-{
-  txt_renderer.text_to_strlist (txt, lst, bbox, halign, valign,
-                                rotation, interpreter);
-}
-
-Matrix
-opengl_renderer::render_text (const std::string& txt,
-                              double x, double y, double z,
-                              int halign, int valign, double rotation)
-{
+  }
+
+  void
+  opengl_renderer::text_to_pixels (const std::string& txt,
+                                   uint8NDArray& pixels,
+                                   Matrix& bbox,
+                                   int halign, int valign, double rotation)
+  {
+    txt_renderer.text_to_pixels (txt, pixels, bbox, halign, valign,
+                                 rotation, interpreter);
+  }
+
+  void
+  opengl_renderer::text_to_strlist (const std::string& txt,
+                                    std::list<text_renderer::string>& lst,
+                                    Matrix& bbox,
+                                    int halign, int valign, double rotation)
+  {
+    txt_renderer.text_to_strlist (txt, lst, bbox, halign, valign,
+                                  rotation, interpreter);
+  }
+
+  Matrix
+  opengl_renderer::render_text (const std::string& txt,
+                                double x, double y, double z,
+                                int halign, int valign, double rotation)
+  {
 #if defined (HAVE_OPENGL)
 
-  Matrix bbox (1, 4, 0.0);
-
-  if (txt.empty ())
+    Matrix bbox (1, 4, 0.0);
+
+    if (txt.empty ())
+      return bbox;
+
+    if (txt_renderer.ok ())
+      {
+        uint8NDArray pixels;
+        text_to_pixels (txt, pixels, bbox, halign, valign, rotation);
+
+        bool blend = glIsEnabled (GL_BLEND);
+
+        glEnable (GL_BLEND);
+        glEnable (GL_ALPHA_TEST);
+        glRasterPos3d (x, y, z);
+        glBitmap(0, 0, 0, 0, bbox(0), bbox(1), 0);
+        glDrawPixels (bbox(2), bbox(3),
+                      GL_RGBA, GL_UNSIGNED_BYTE, pixels.data ());
+        glDisable (GL_ALPHA_TEST);
+
+        if (! blend)
+          glDisable (GL_BLEND);
+      }
+
     return bbox;
 
-  if (txt_renderer.ok ())
-    {
-      uint8NDArray pixels;
-      text_to_pixels (txt, pixels, bbox, halign, valign, rotation);
-
-      bool blend = glIsEnabled (GL_BLEND);
-
-      glEnable (GL_BLEND);
-      glEnable (GL_ALPHA_TEST);
-      glRasterPos3d (x, y, z);
-      glBitmap(0, 0, 0, 0, bbox(0), bbox(1), 0);
-      glDrawPixels (bbox(2), bbox(3),
-                    GL_RGBA, GL_UNSIGNED_BYTE, pixels.data ());
-      glDisable (GL_ALPHA_TEST);
-
-      if (! blend)
-        glDisable (GL_BLEND);
-    }
-
-  return bbox;
-
 #else
 
-  octave_unused_parameter (txt);
-  octave_unused_parameter (x);
-  octave_unused_parameter (y);
-  octave_unused_parameter (z);
-  octave_unused_parameter (halign);
-  octave_unused_parameter (valign);
-  octave_unused_parameter (rotation);
-
-  // This shouldn't happen because construction of opengl_renderer
-  // objects is supposed to be impossible if OpenGL is not available.
-
-  panic_impossible ();
+    octave_unused_parameter (txt);
+    octave_unused_parameter (x);
+    octave_unused_parameter (y);
+    octave_unused_parameter (z);
+    octave_unused_parameter (halign);
+    octave_unused_parameter (valign);
+    octave_unused_parameter (rotation);
+
+    // This shouldn't happen because construction of opengl_renderer
+    // objects is supposed to be impossible if OpenGL is not available.
+
+    panic_impossible ();
 
 #endif
+  }
 }
-
-}
--- a/libinterp/corefcn/gl-render.h	Wed Aug 17 08:20:26 2016 -0700
+++ b/libinterp/corefcn/gl-render.h	Wed Aug 17 11:43:27 2016 -0400
@@ -30,185 +30,183 @@
 
 namespace octave
 {
-
-class
-OCTINTERP_API
-opengl_renderer
-{
-public:
-
-  opengl_renderer (void);
-
-  virtual ~opengl_renderer (void) { }
-
-  virtual void draw (const graphics_object& go, bool toplevel = true);
-
-  virtual void draw (const Matrix& hlist, bool toplevel = false)
+  class
+  OCTINTERP_API
+  opengl_renderer
   {
-    int len = hlist.numel ();
+  public:
+
+    opengl_renderer (void);
+
+    virtual ~opengl_renderer (void) { }
 
-    for (int i = len-1; i >= 0; i--)
-      {
-        graphics_object obj = gh_manager::get_object (hlist(i));
+    virtual void draw (const graphics_object& go, bool toplevel = true);
+
+    virtual void draw (const Matrix& hlist, bool toplevel = false)
+    {
+      int len = hlist.numel ();
 
-        if (obj)
-          draw (obj, toplevel);
-      }
-  }
+      for (int i = len-1; i >= 0; i--)
+        {
+          graphics_object obj = gh_manager::get_object (hlist(i));
 
-  virtual void set_viewport (int w, int h);
-  virtual graphics_xform get_transform (void) const { return xform; }
+          if (obj)
+            draw (obj, toplevel);
+        }
+    }
 
-  virtual void finish (void);
+    virtual void set_viewport (int w, int h);
+    virtual graphics_xform get_transform (void) const { return xform; }
+
+    virtual void finish (void);
 
-protected:
-  virtual void draw_figure (const figure::properties& props);
-  virtual void draw_axes (const axes::properties& props);
-  virtual void draw_line (const line::properties& props);
-  virtual void draw_surface (const surface::properties& props);
-  virtual void draw_patch (const patch::properties& props);
-  virtual void draw_light (const light::properties& props);
-  virtual void draw_hggroup (const hggroup::properties& props);
-  virtual void draw_text (const text::properties& props);
-  virtual void draw_image (const image::properties& props);
-  virtual void draw_uipanel (const uipanel::properties& props,
-                             const graphics_object& go);
-  virtual void draw_uibuttongroup (const uibuttongroup::properties& props,
-                                   const graphics_object& go);
-  virtual void init_gl_context (bool enhanced, const Matrix& backgroundColor);
-  virtual void setup_opengl_transformation (const axes::properties& props);
+  protected:
+    virtual void draw_figure (const figure::properties& props);
+    virtual void draw_axes (const axes::properties& props);
+    virtual void draw_line (const line::properties& props);
+    virtual void draw_surface (const surface::properties& props);
+    virtual void draw_patch (const patch::properties& props);
+    virtual void draw_light (const light::properties& props);
+    virtual void draw_hggroup (const hggroup::properties& props);
+    virtual void draw_text (const text::properties& props);
+    virtual void draw_image (const image::properties& props);
+    virtual void draw_uipanel (const uipanel::properties& props,
+                               const graphics_object& go);
+    virtual void draw_uibuttongroup (const uibuttongroup::properties& props,
+                                     const graphics_object& go);
+    virtual void init_gl_context (bool enhanced, const Matrix& backgroundColor);
+    virtual void setup_opengl_transformation (const axes::properties& props);
 
-  virtual void set_color (const Matrix& c);
-  virtual void set_polygon_offset (bool on, float offset = 0.0f);
-  virtual void set_linewidth (float w);
-  virtual void set_linestyle (const std::string& s, bool stipple = false);
-  virtual void set_clipbox (double x1, double x2, double y1, double y2,
-                            double z1, double z2);
-  virtual void set_clipping (bool on);
-  virtual void set_font (const base_properties& props);
-  virtual void set_interpreter (const caseless_str& interp)
-  {
-    interpreter = interp;
-  }
+    virtual void set_color (const Matrix& c);
+    virtual void set_polygon_offset (bool on, float offset = 0.0f);
+    virtual void set_linewidth (float w);
+    virtual void set_linestyle (const std::string& s, bool stipple = false);
+    virtual void set_clipbox (double x1, double x2, double y1, double y2,
+                              double z1, double z2);
+    virtual void set_clipping (bool on);
+    virtual void set_font (const base_properties& props);
+    virtual void set_interpreter (const caseless_str& interp)
+    {
+      interpreter = interp;
+    }
 
-  virtual void init_marker (const std::string& m, double size, float width);
-  virtual void end_marker (void);
-  virtual void draw_marker (double x, double y, double z,
-                            const Matrix& lc, const Matrix& fc);
+    virtual void init_marker (const std::string& m, double size, float width);
+    virtual void end_marker (void);
+    virtual void draw_marker (double x, double y, double z,
+                              const Matrix& lc, const Matrix& fc);
 
-  virtual void text_to_pixels (const std::string& txt,
-                               uint8NDArray& pixels,
-                               Matrix& bbox,
-                               int halign = 0, int valign = 0,
-                               double rotation = 0.0);
+    virtual void text_to_pixels (const std::string& txt,
+                                 uint8NDArray& pixels,
+                                 Matrix& bbox,
+                                 int halign = 0, int valign = 0,
+                                 double rotation = 0.0);
 
-  virtual void text_to_strlist (const std::string& txt,
-                                std::list<text_renderer::string>& lst,
-                                Matrix& bbox,
-                                int halign = 0, int valign = 0,
-                                double rotation = 0.0);
+    virtual void text_to_strlist (const std::string& txt,
+                                  std::list<text_renderer::string>& lst,
+                                  Matrix& bbox,
+                                  int halign = 0, int valign = 0,
+                                  double rotation = 0.0);
 
-  virtual Matrix render_text (const std::string& txt,
-                              double x, double y, double z,
-                              int halign, int valign, double rotation = 0.0);
+    virtual Matrix render_text (const std::string& txt,
+                                double x, double y, double z,
+                                int halign, int valign, double rotation = 0.0);
 
-  virtual void draw_pixels (int w, int h, const float *data);
-  virtual void draw_pixels (int w, int h, const uint8_t *data);
-  virtual void draw_pixels (int w, int h, const uint16_t *data);
+    virtual void draw_pixels (int w, int h, const float *data);
+    virtual void draw_pixels (int w, int h, const uint8_t *data);
+    virtual void draw_pixels (int w, int h, const uint16_t *data);
 
-  virtual void render_grid (const std::string& gridstyle, const Matrix& ticks,
-                            double lim1, double lim2,
-                            double p1, double p1N, double p2, double p2N,
-                            int xyz, bool is_3D);
+    virtual void render_grid (const std::string& gridstyle, const Matrix& ticks,
+                              double lim1, double lim2,
+                              double p1, double p1N, double p2, double p2N,
+                              int xyz, bool is_3D);
 
-  virtual void render_tickmarks (const Matrix& ticks, double lim1, double lim2,
-                                 double p1, double p1N, double p2, double p2N,
-                                 double dx, double dy, double dz,
-                                 int xyz, bool doubleside);
+    virtual void render_tickmarks (const Matrix& ticks, double lim1, double lim2,
+                                   double p1, double p1N, double p2, double p2N,
+                                   double dx, double dy, double dz,
+                                   int xyz, bool doubleside);
 
-  virtual void render_ticktexts (const Matrix& ticks,
-                                 const string_vector& ticklabels,
-                                 double lim1, double lim2,
-                                 double p1, double p2,
-                                 int xyz, int ha, int va,
-                                 int& wmax, int& hmax);
+    virtual void render_ticktexts (const Matrix& ticks,
+                                   const string_vector& ticklabels,
+                                   double lim1, double lim2,
+                                   double p1, double p2,
+                                   int xyz, int ha, int va,
+                                   int& wmax, int& hmax);
 
-private:
+  private:
 
-  // No copying!
-
-  opengl_renderer (const opengl_renderer&);
+    // No copying!
 
-  opengl_renderer& operator = (const opengl_renderer&);
+    opengl_renderer (const opengl_renderer&);
+
+    opengl_renderer& operator = (const opengl_renderer&);
 
-  bool is_nan_or_inf (double x, double y, double z) const
-  {
-    return (octave::math::isnan (x) || octave::math::isnan (y) || octave::math::isnan (z)
-            || octave::math::isinf (x) || octave::math::isinf (y) || octave::math::isinf (z));
-  }
+    bool is_nan_or_inf (double x, double y, double z) const
+    {
+      return (octave::math::isnan (x) || octave::math::isnan (y) || octave::math::isnan (z)
+              || octave::math::isinf (x) || octave::math::isinf (y) || octave::math::isinf (z));
+    }
 
-  octave_uint8 clip_code (double x, double y, double z) const
-  {
-    return ((x < xmin ? 1 : 0)
-            | (x > xmax ? 1 : 0) << 1
-            | (y < ymin ? 1 : 0) << 2
-            | (y > ymax ? 1 : 0) << 3
-            | (z < zmin ? 1 : 0) << 4
-            | (z > zmax ? 1 : 0) << 5
-            | (is_nan_or_inf (x, y, z) ? 0 : 1) << 6);
-  }
+    octave_uint8 clip_code (double x, double y, double z) const
+    {
+      return ((x < xmin ? 1 : 0)
+              | (x > xmax ? 1 : 0) << 1
+              | (y < ymin ? 1 : 0) << 2
+              | (y > ymax ? 1 : 0) << 3
+              | (z < zmin ? 1 : 0) << 4
+              | (z > zmax ? 1 : 0) << 5
+              | (is_nan_or_inf (x, y, z) ? 0 : 1) << 6);
+    }
 
-  void set_normal (int bfl_mode, const NDArray& n, int j, int i);
-
-  unsigned int make_marker_list (const std::string& m, double size,
-                                 bool filled) const;
+    void set_normal (int bfl_mode, const NDArray& n, int j, int i);
 
-  void draw_axes_planes (const axes::properties& props);
-  void draw_axes_boxes (const axes::properties& props);
+    unsigned int make_marker_list (const std::string& m, double size,
+                                   bool filled) const;
 
-  void draw_axes_x_grid (const axes::properties& props);
-  void draw_axes_y_grid (const axes::properties& props);
-  void draw_axes_z_grid (const axes::properties& props);
+    void draw_axes_planes (const axes::properties& props);
+    void draw_axes_boxes (const axes::properties& props);
 
-  void draw_axes_children (const axes::properties& props);
-
-  void draw_all_lights (const base_properties& props, std::list<graphics_object>& obj_list);
+    void draw_axes_x_grid (const axes::properties& props);
+    void draw_axes_y_grid (const axes::properties& props);
+    void draw_axes_z_grid (const axes::properties& props);
 
-private:
-  // The graphics toolkit associated with the figure being rendered.
-  graphics_toolkit toolkit;
+    void draw_axes_children (const axes::properties& props);
+
+    void draw_all_lights (const base_properties& props, std::list<graphics_object>& obj_list);
 
-  // axes transformation data
-  graphics_xform xform;
+  private:
+    // The graphics toolkit associated with the figure being rendered.
+    graphics_toolkit toolkit;
 
-  // axis limits in model scaled coordinate
-  double xmin, xmax;
-  double ymin, ymax;
-  double zmin, zmax;
+    // axes transformation data
+    graphics_xform xform;
 
-  // Z projection limits in windows coordinate
-  double xZ1, xZ2;
-
-  // call lists identifiers for markers
-  unsigned int marker_id, filled_marker_id;
+    // axis limits in model scaled coordinate
+    double xmin, xmax;
+    double ymin, ymax;
+    double zmin, zmax;
 
-  // camera information for primitive sorting and lighting
-  ColumnVector camera_pos, camera_dir, view_vector;
+    // Z projection limits in windows coordinate
+    double xZ1, xZ2;
 
-  // interpreter to be used by text_to_pixels
-  caseless_str interpreter;
+    // call lists identifiers for markers
+    unsigned int marker_id, filled_marker_id;
+
+    // camera information for primitive sorting and lighting
+    ColumnVector camera_pos, camera_dir, view_vector;
 
-  text_renderer txt_renderer;
+    // interpreter to be used by text_to_pixels
+    caseless_str interpreter;
+
+    text_renderer txt_renderer;
 
-  // light object present and visible
-  int num_lights;
-  unsigned int current_light;
-  int max_lights;
+    // light object present and visible
+    int num_lights;
+    unsigned int current_light;
+    int max_lights;
 
-private:
-  class patch_tesselator;
-};
-
+  private:
+    class patch_tesselator;
+  };
 }
 
 #endif
--- a/libinterp/corefcn/gl2ps-print.cc	Wed Aug 17 08:20:26 2016 -0700
+++ b/libinterp/corefcn/gl2ps-print.cc	Wed Aug 17 11:43:27 2016 -0400
@@ -50,314 +50,312 @@
 
 namespace octave
 {
+  class
+  OCTINTERP_API
+  gl2ps_renderer : public opengl_renderer
+  {
+  public:
 
-class
-OCTINTERP_API
-gl2ps_renderer : public opengl_renderer
-{
-public:
+    gl2ps_renderer (FILE *_fp, const std::string& _term)
+      : octave::opengl_renderer () , fp (_fp), term (_term), fontsize (),
+      fontname (), buffer_overflow (false)
+      { }
+
+    ~gl2ps_renderer (void) { }
+
+    // FIXME: should we import the functions from the base class and
+    // overload them here, or should we use a different name so we don't
+    // have to do this?  Without the using declaration or a name change,
+    // the base class functions will be hidden.  That may be OK, but it
+    // can also cause some confusion.
+    using octave::opengl_renderer::draw;
+
+    void draw (const graphics_object& go, const std::string& print_cmd);
+
+  protected:
+
+    Matrix render_text (const std::string& txt,
+                        double x, double y, double z,
+                        int halign, int valign, double rotation = 0.0);
 
-  gl2ps_renderer (FILE *_fp, const std::string& _term)
-    : octave::opengl_renderer () , fp (_fp), term (_term), fontsize (),
-      fontname (), buffer_overflow (false)
-  { }
+    void set_font (const base_properties& props);
+
+    void draw_axes (const axes::properties& props)
+    {
+      // Initialize a sorting tree (viewport) in gl2ps for each axes
+      GLint vp[4];
+      glGetIntegerv (GL_VIEWPORT, vp);
+      gl2psBeginViewport (vp);
+
+      // Draw and finish () or there may primitives missing in the gl2ps output.
+      octave::opengl_renderer::draw_axes (props);
+      finish ();
 
-  ~gl2ps_renderer (void) { }
+      // Finalize viewport
+      GLint state = gl2psEndViewport ();
+      if (state == GL2PS_NO_FEEDBACK)
+        warning ("gl2ps_renderer::draw_axes: empty feedback buffer and/or nothing else to print");
+      else if (state == GL2PS_ERROR)
+        error ("gl2ps_renderer::draw_axes: gl2psEndPage returned GL2PS_ERROR");
+
+      buffer_overflow |= (state == GL2PS_OVERFLOW);
+
+      // Don't draw background for subsequent viewports (legends, subplots, etc.)
+      GLint opts;
+      gl2psGetOptions (&opts);
+      opts &= ~GL2PS_DRAW_BACKGROUND;
+      gl2psSetOptions (opts);
+    }
+
+    void draw_text (const text::properties& props);
 
-  // FIXME: should we import the functions from the base class and
-  // overload them here, or should we use a different name so we don't
-  // have to do this?  Without the using declaration or a name change,
-  // the base class functions will be hidden.  That may be OK, but it
-  // can also cause some confusion.
-  using octave::opengl_renderer::draw;
+    void draw_pixels (int w, int h, const float *data);
+    void draw_pixels (int w, int h, const uint8_t *data);
+    void draw_pixels (int w, int h, const uint16_t *data);
+
+    void set_linestyle (const std::string& s, bool use_stipple = false)
+    {
+      octave::opengl_renderer::set_linestyle (s, use_stipple);
+
+      if (s == "-" && ! use_stipple)
+        gl2psDisable (GL2PS_LINE_STIPPLE);
+      else
+        gl2psEnable (GL2PS_LINE_STIPPLE);
+    }
 
-  void draw (const graphics_object& go, const std::string& print_cmd);
-
-protected:
+    void set_polygon_offset (bool on, float offset = 0.0f)
+    {
+      if (on)
+        {
+          octave::opengl_renderer::set_polygon_offset (on, offset);
+          gl2psEnable (GL2PS_POLYGON_OFFSET_FILL);
+        }
+      else
+        {
+          gl2psDisable (GL2PS_POLYGON_OFFSET_FILL);
+          octave::opengl_renderer::set_polygon_offset (on, offset);
+        }
+    }
 
-  Matrix render_text (const std::string& txt,
-                      double x, double y, double z,
-                      int halign, int valign, double rotation = 0.0);
+    void set_linewidth (float w)
+    {
+      gl2psLineWidth (w);
+    }
 
-  void set_font (const base_properties& props);
+  private:
+
+    // Use xform to compute the coordinates of the string list
+    // that have been parsed by freetype
+    void fix_strlist_position (double x, double y, double z,
+                               Matrix box, double rotation,
+                               std::list<octave::text_renderer::string>& lst);
 
-  void draw_axes (const axes::properties& props)
+    int alignment_to_mode (int ha, int va) const;
+    FILE *fp;
+    caseless_str term;
+    double fontsize;
+    std::string fontname;
+    bool buffer_overflow;
+  };
+
+  void
+  gl2ps_renderer::draw (const graphics_object& go, const std::string& print_cmd)
   {
-    // Initialize a sorting tree (viewport) in gl2ps for each axes
-    GLint vp[4];
-    glGetIntegerv (GL_VIEWPORT, vp);
-    gl2psBeginViewport (vp);
+    static bool in_draw = false;
+    static std::string old_print_cmd;
+
+    if (! in_draw)
+      {
+        octave::unwind_protect frame;
 
-    // Draw and finish () or there may primitives missing in the gl2ps output.
-    octave::opengl_renderer::draw_axes (props);
-    finish ();
+        frame.protect_var (in_draw);
+
+        in_draw = true;
+
+        GLint gl2ps_term;
+        if (term.find ("eps") != std::string::npos)
+          gl2ps_term = GL2PS_EPS;
+        else if (term.find ("pdf") != std::string::npos)
+          gl2ps_term = GL2PS_PDF;
+        else if (term.find ("ps") != std::string::npos)
+          gl2ps_term = GL2PS_PS;
+        else if (term.find ("svg") != std::string::npos)
+          gl2ps_term = GL2PS_SVG;
+        else if (term.find ("pgf") != std::string::npos)
+          gl2ps_term = GL2PS_PGF;
+        else if (term.find ("tex") != std::string::npos)
+          gl2ps_term = GL2PS_TEX;
+        else
+          error ("gl2ps_renderer::draw: Unknown terminal %s", term.c_str ());
+
+        GLint gl2ps_text = 0;
+        if (term.find ("notxt") != std::string::npos)
+          gl2ps_text = GL2PS_NO_TEXT;
+
+        // Default sort order optimizes for 3D plots
+        GLint gl2ps_sort = GL2PS_BSP_SORT;
 
-    // Finalize viewport
-    GLint state = gl2psEndViewport ();
-    if (state == GL2PS_NO_FEEDBACK)
-      warning ("gl2ps_renderer::draw_axes: empty feedback buffer and/or nothing else to print");
-    else if (state == GL2PS_ERROR)
-      error ("gl2ps_renderer::draw_axes: gl2psEndPage returned GL2PS_ERROR");
+        // For 2D plots we can use a simpler Z-depth sorting algorithm
+        if (term.find ("is2D") != std::string::npos)
+          gl2ps_sort = GL2PS_SIMPLE_SORT;
+
+        // Use a temporary file in case an overflow happens
+        FILE* tmpf = octave_tmpfile_wrapper ();
+
+        if (! tmpf)
+          error ("gl2ps_renderer::draw: couldn't open temporary file for printing");
+
+        GLint buffsize = 2*1024*1024;
+        buffer_overflow = true;
 
-    buffer_overflow |= (state == GL2PS_OVERFLOW);
+        while (buffer_overflow)
+          {
+            buffer_overflow = false;
+            buffsize *= 2;
+            std::fseek (tmpf, 0, SEEK_SET);
+            octave_ftruncate_wrapper (fileno (tmpf), 0);
 
-    // Don't draw background for subsequent viewports (legends, subplots, etc.)
-    GLint opts;
-    gl2psGetOptions (&opts);
-    opts &= ~GL2PS_DRAW_BACKGROUND;
-    gl2psSetOptions (opts);
-  }
+            // For LaTeX output the fltk print process uses 2 drawnow() commands.
+            // The first one is for the pdf/ps/eps graph to be included.  The
+            // print_cmd is saved as old_print_cmd.  Then the second drawnow()
+            // outputs the tex-file and the graphic filename to be included is
+            // extracted from old_print_cmd.
+
+            std::string include_graph;
+
+            size_t found_redirect = old_print_cmd.find (">");
 
-  void draw_text (const text::properties& props);
+            if (found_redirect != std::string::npos)
+              include_graph = old_print_cmd.substr (found_redirect + 1);
+            else
+              include_graph = old_print_cmd;
+
+            size_t n_begin = include_graph.find_first_not_of (" ");
 
-  void draw_pixels (int w, int h, const float *data);
-  void draw_pixels (int w, int h, const uint8_t *data);
-  void draw_pixels (int w, int h, const uint16_t *data);
-
-  void set_linestyle (const std::string& s, bool use_stipple = false)
-  {
-    octave::opengl_renderer::set_linestyle (s, use_stipple);
+            if (n_begin != std::string::npos)
+              {
+                size_t n_end = include_graph.find_last_not_of (" ");
+                include_graph = include_graph.substr (n_begin,
+                                                      n_end - n_begin + 1);
+              }
+            else
+              include_graph = "foobar-inc";
 
-    if (s == "-" && ! use_stipple)
-      gl2psDisable (GL2PS_LINE_STIPPLE);
-    else
-      gl2psEnable (GL2PS_LINE_STIPPLE);
-  }
+            // GL2PS_SILENT was removed to allow gl2ps to print errors on stderr
+            GLint ret = gl2psBeginPage ("gl2ps_renderer figure", "Octave", 0,
+                                        gl2ps_term, gl2ps_sort,
+                                        (GL2PS_NO_BLENDING
+                                         | GL2PS_OCCLUSION_CULL
+                                         | GL2PS_BEST_ROOT
+                                         | gl2ps_text
+                                         | GL2PS_DRAW_BACKGROUND
+                                         | GL2PS_NO_PS3_SHADING
+                                         | GL2PS_USE_CURRENT_VIEWPORT),
+                                        GL_RGBA, 0, 0, 0, 0, 0,
+                                        buffsize, tmpf, include_graph.c_str ());
+            if (ret == GL2PS_ERROR)
+              {
+                old_print_cmd.clear ();
+                error ("gl2ps_renderer::draw: gl2psBeginPage returned GL2PS_ERROR");
+              }
+
+            octave::opengl_renderer::draw (go);
+
+            if (! buffer_overflow)
+              old_print_cmd = print_cmd;
 
-  void set_polygon_offset (bool on, float offset = 0.0f)
-  {
-    if (on)
-      {
-        octave::opengl_renderer::set_polygon_offset (on, offset);
-        gl2psEnable (GL2PS_POLYGON_OFFSET_FILL);
+            // Don't check return value of gl2psEndPage, it is not meaningful.
+            // Errors and warnings are checked after gl2psEndViewport in
+            // gl2ps_renderer::draw_axes instead.
+            gl2psEndPage ();
+          }
+
+        // Copy temporary file to pipe
+        std::fseek (tmpf, 0, SEEK_SET);
+        char str[256];
+        size_t nread, nwrite;
+        nread = 1;
+        while (! feof (tmpf) && nread)
+          {
+            nread = std::fread (str, 1, 256, tmpf);
+            if (nread)
+              {
+                nwrite = std::fwrite (str, 1, nread, fp);
+                if (nwrite != nread)
+                  {
+                    octave::signal_handler ();   // Clear SIGPIPE signal
+                    error ("gl2ps_renderer::draw: internal pipe error");
+                  }
+              }
+          }
       }
     else
-      {
-        gl2psDisable (GL2PS_POLYGON_OFFSET_FILL);
-        octave::opengl_renderer::set_polygon_offset (on, offset);
-      }
-  }
-
-  void set_linewidth (float w)
-  {
-    gl2psLineWidth (w);
+      octave::opengl_renderer::draw (go);
   }
 
-private:
-
-  // Use xform to compute the coordinates of the string list
-  // that have been parsed by freetype
-  void fix_strlist_position (double x, double y, double z,
-                             Matrix box, double rotation,
-                             std::list<octave::text_renderer::string>& lst);
-
-  int alignment_to_mode (int ha, int va) const;
-  FILE *fp;
-  caseless_str term;
-  double fontsize;
-  std::string fontname;
-  bool buffer_overflow;
-};
-
-void
-gl2ps_renderer::draw (const graphics_object& go, const std::string& print_cmd)
-{
-  static bool in_draw = false;
-  static std::string old_print_cmd;
-
-  if (! in_draw)
-    {
-      octave::unwind_protect frame;
-
-      frame.protect_var (in_draw);
-
-      in_draw = true;
-
-      GLint gl2ps_term;
-      if (term.find ("eps") != std::string::npos)
-        gl2ps_term = GL2PS_EPS;
-      else if (term.find ("pdf") != std::string::npos)
-        gl2ps_term = GL2PS_PDF;
-      else if (term.find ("ps") != std::string::npos)
-        gl2ps_term = GL2PS_PS;
-      else if (term.find ("svg") != std::string::npos)
-        gl2ps_term = GL2PS_SVG;
-      else if (term.find ("pgf") != std::string::npos)
-        gl2ps_term = GL2PS_PGF;
-      else if (term.find ("tex") != std::string::npos)
-        gl2ps_term = GL2PS_TEX;
-      else
-        error ("gl2ps_renderer::draw: Unknown terminal %s", term.c_str ());
-
-      GLint gl2ps_text = 0;
-      if (term.find ("notxt") != std::string::npos)
-        gl2ps_text = GL2PS_NO_TEXT;
-
-      // Default sort order optimizes for 3D plots
-      GLint gl2ps_sort = GL2PS_BSP_SORT;
-
-      // For 2D plots we can use a simpler Z-depth sorting algorithm
-      if (term.find ("is2D") != std::string::npos)
-        gl2ps_sort = GL2PS_SIMPLE_SORT;
-
-      // Use a temporary file in case an overflow happens
-      FILE* tmpf = octave_tmpfile_wrapper ();
-
-      if (! tmpf)
-        error ("gl2ps_renderer::draw: couldn't open temporary file for printing");
-
-      GLint buffsize = 2*1024*1024;
-      buffer_overflow = true;
-
-      while (buffer_overflow)
-        {
-          buffer_overflow = false;
-          buffsize *= 2;
-          std::fseek (tmpf, 0, SEEK_SET);
-          octave_ftruncate_wrapper (fileno (tmpf), 0);
-
-          // For LaTeX output the fltk print process uses 2 drawnow() commands.
-          // The first one is for the pdf/ps/eps graph to be included.  The
-          // print_cmd is saved as old_print_cmd.  Then the second drawnow()
-          // outputs the tex-file and the graphic filename to be included is
-          // extracted from old_print_cmd.
-
-          std::string include_graph;
-
-          size_t found_redirect = old_print_cmd.find (">");
-
-          if (found_redirect != std::string::npos)
-            include_graph = old_print_cmd.substr (found_redirect + 1);
-          else
-            include_graph = old_print_cmd;
-
-          size_t n_begin = include_graph.find_first_not_of (" ");
-
-          if (n_begin != std::string::npos)
-            {
-              size_t n_end = include_graph.find_last_not_of (" ");
-              include_graph = include_graph.substr (n_begin,
-                                                    n_end - n_begin + 1);
-            }
-          else
-            include_graph = "foobar-inc";
+  int
+  gl2ps_renderer::alignment_to_mode (int ha, int va) const
+  {
+    int gl2psa = GL2PS_TEXT_BL;
 
-          // GL2PS_SILENT was removed to allow gl2ps to print errors on stderr
-          GLint ret = gl2psBeginPage ("gl2ps_renderer figure", "Octave", 0,
-                                      gl2ps_term, gl2ps_sort,
-                                      (GL2PS_NO_BLENDING
-                                       | GL2PS_OCCLUSION_CULL
-                                       | GL2PS_BEST_ROOT
-                                       | gl2ps_text
-                                       | GL2PS_DRAW_BACKGROUND
-                                       | GL2PS_NO_PS3_SHADING
-                                       | GL2PS_USE_CURRENT_VIEWPORT),
-                                      GL_RGBA, 0, 0, 0, 0, 0,
-                                      buffsize, tmpf, include_graph.c_str ());
-          if (ret == GL2PS_ERROR)
-            {
-              old_print_cmd.clear ();
-              error ("gl2ps_renderer::draw: gl2psBeginPage returned GL2PS_ERROR");
-            }
-
-          octave::opengl_renderer::draw (go);
-
-          if (! buffer_overflow)
-            old_print_cmd = print_cmd;
-
-          // Don't check return value of gl2psEndPage, it is not meaningful.
-          // Errors and warnings are checked after gl2psEndViewport in
-          // gl2ps_renderer::draw_axes instead.
-          gl2psEndPage ();
-        }
-
-      // Copy temporary file to pipe
-      std::fseek (tmpf, 0, SEEK_SET);
-      char str[256];
-      size_t nread, nwrite;
-      nread = 1;
-      while (! feof (tmpf) && nread)
-        {
-          nread = std::fread (str, 1, 256, tmpf);
-          if (nread)
-            {
-              nwrite = std::fwrite (str, 1, nread, fp);
-              if (nwrite != nread)
-                {
-                  octave::signal_handler ();   // Clear SIGPIPE signal
-                  error ("gl2ps_renderer::draw: internal pipe error");
-                }
-            }
-        }
-    }
-  else
-    octave::opengl_renderer::draw (go);
-}
-
-int
-gl2ps_renderer::alignment_to_mode (int ha, int va) const
-{
-  int gl2psa = GL2PS_TEXT_BL;
+    if (ha == 0)
+      {
+        if (va == 0 || va == 3)
+          gl2psa=GL2PS_TEXT_BL;
+        else if (va == 2)
+          gl2psa=GL2PS_TEXT_TL;
+        else if (va == 1)
+          gl2psa=GL2PS_TEXT_CL;
+      }
+    else if (ha == 2)
+      {
+        if (va == 0 || va == 3)
+          gl2psa=GL2PS_TEXT_BR;
+        else if (va == 2)
+          gl2psa=GL2PS_TEXT_TR;
+        else if (va == 1)
+          gl2psa=GL2PS_TEXT_CR;
+      }
+    else if (ha == 1)
+      {
+        if (va == 0 || va == 3)
+          gl2psa=GL2PS_TEXT_B;
+        else if (va == 2)
+          gl2psa=GL2PS_TEXT_T;
+        else if (va == 1)
+          gl2psa=GL2PS_TEXT_C;
+      }
 
-  if (ha == 0)
-    {
-      if (va == 0 || va == 3)
-        gl2psa=GL2PS_TEXT_BL;
-      else if (va == 2)
-        gl2psa=GL2PS_TEXT_TL;
-      else if (va == 1)
-        gl2psa=GL2PS_TEXT_CL;
-    }
-  else if (ha == 2)
-    {
-      if (va == 0 || va == 3)
-        gl2psa=GL2PS_TEXT_BR;
-      else if (va == 2)
-        gl2psa=GL2PS_TEXT_TR;
-      else if (va == 1)
-        gl2psa=GL2PS_TEXT_CR;
-    }
-  else if (ha == 1)
-    {
-      if (va == 0 || va == 3)
-        gl2psa=GL2PS_TEXT_B;
-      else if (va == 2)
-        gl2psa=GL2PS_TEXT_T;
-      else if (va == 1)
-        gl2psa=GL2PS_TEXT_C;
-    }
+    return gl2psa;
+  }
+
+  void
+  gl2ps_renderer::fix_strlist_position (double x, double y, double z,
+                                        Matrix box, double rotation,
+                                        std::list<octave::text_renderer::string>& lst)
+  {
+    for (std::list<octave::text_renderer::string>::iterator p = lst.begin ();
+         p != lst.end (); p++)
+      {
+        // Get pixel coordinates
+        ColumnVector coord_pix = get_transform ().transform (x, y, z, false);
 
-  return gl2psa;
-}
-
-void
-gl2ps_renderer::fix_strlist_position (double x, double y, double z,
-                                      Matrix box, double rotation,
-                                      std::list<octave::text_renderer::string>& lst)
-{
-  for (std::list<octave::text_renderer::string>::iterator p = lst.begin ();
-       p != lst.end (); p++)
-    {
-      // Get pixel coordinates
-      ColumnVector coord_pix = get_transform ().transform (x, y, z, false);
+        // Translate and rotate
+        double rot = rotation * 4.0 * atan (1.0) / 180;
+        coord_pix(0) += ((*p).get_x () + box(0))*cos (rot)
+          - ((*p).get_y () + box(1))*sin (rot);
+        coord_pix(1) -= ((*p).get_y () + box(1))*cos (rot)
+          + ((*p).get_x () + box(0))*sin (rot);;
 
-      // Translate and rotate
-      double rot = rotation * 4.0 * atan (1.0) / 180;
-      coord_pix(0) += ((*p).get_x () + box(0))*cos (rot)
-                      - ((*p).get_y () + box(1))*sin (rot);
-      coord_pix(1) -= ((*p).get_y () + box(1))*cos (rot)
-                      + ((*p).get_x () + box(0))*sin (rot);;
-
-      // Turn coordinates back into current gl coordinates
-      ColumnVector coord =
-        get_transform ().untransform (coord_pix(0), coord_pix(1),
-                                      coord_pix(2), false);
-      (*p).set_x (coord(0));
-      (*p).set_y (coord(1));
-      (*p).set_z (coord(2));
-    }
-}
-
+        // Turn coordinates back into current gl coordinates
+        ColumnVector coord =
+          get_transform ().untransform (coord_pix(0), coord_pix(1),
+                                        coord_pix(2), false);
+        (*p).set_x (coord(0));
+        (*p).set_y (coord(1));
+        (*p).set_z (coord(2));
+      }
+  }
 }
 
 static std::string
@@ -414,7 +412,7 @@
   else if (code == 8730)
     retval = std::string ("\xd6");
   else if (code == 8707)
-  retval = std::string ("\x24");
+    retval = std::string ("\x24");
   else if (code == 9830)
     retval = std::string ("\xa8");
   else if (code == 8747)
@@ -572,199 +570,198 @@
 
 namespace octave
 {
-
-Matrix
-gl2ps_renderer::render_text (const std::string& txt,
-                            double x, double y, double z,
-                            int ha, int va, double rotation)
-{
-  std::string saved_font = fontname;
+  Matrix
+  gl2ps_renderer::render_text (const std::string& txt,
+                               double x, double y, double z,
+                               int ha, int va, double rotation)
+  {
+    std::string saved_font = fontname;
 
-  if (txt.empty ())
-    return Matrix (1, 4, 0.0);
+    if (txt.empty ())
+      return Matrix (1, 4, 0.0);
 
-  // We have no way to get a bounding box from gl2ps, so we parse the raw
-  // string using freetype
-  Matrix bbox;
-  std::string str = txt;
-  std::list<octave::text_renderer::string> lst;
+    // We have no way to get a bounding box from gl2ps, so we parse the raw
+    // string using freetype
+    Matrix bbox;
+    std::string str = txt;
+    std::list<octave::text_renderer::string> lst;
 
-  text_to_strlist (str, lst, bbox, ha, va, rotation);
+    text_to_strlist (str, lst, bbox, ha, va, rotation);
 
-  // When using "tex" or when the string has only one line and no
-  // special characters, use gl2ps for alignment
-  if (lst.empty () || term.find ("tex") != std::string::npos
-      || (lst.size () == 1 && ! lst.front ().get_code ()))
-    {
-      std::string name = fontname;
-      int sz = fontsize;
-      if (! lst.empty () && term.find ("tex") == std::string::npos)
-        {
-          octave::text_renderer::string s = lst.front ();
-          name = select_font (s.get_name (), s.get_weight () == "bold",
-                              s.get_angle () == "italic");
-          set_color (s.get_color ());
-          str = s.get_string ();
-          sz = s.get_size ();
-        }
+    // When using "tex" or when the string has only one line and no
+    // special characters, use gl2ps for alignment
+    if (lst.empty () || term.find ("tex") != std::string::npos
+        || (lst.size () == 1 && ! lst.front ().get_code ()))
+      {
+        std::string name = fontname;
+        int sz = fontsize;
+        if (! lst.empty () && term.find ("tex") == std::string::npos)
+          {
+            octave::text_renderer::string s = lst.front ();
+            name = select_font (s.get_name (), s.get_weight () == "bold",
+                                s.get_angle () == "italic");
+            set_color (s.get_color ());
+            str = s.get_string ();
+            sz = s.get_size ();
+          }
 
-      glRasterPos3d (x, y, z);
+        glRasterPos3d (x, y, z);
 
-      // Escape parenthesis until gl2ps does it (see bug ##45301).
-      if (term.find ("svg") == std::string::npos
-          && term.find ("tex") == std::string::npos)
-        {
-          escape_character ("(", str);
-          escape_character (")", str);
-        }
+        // Escape parenthesis until gl2ps does it (see bug ##45301).
+        if (term.find ("svg") == std::string::npos
+            && term.find ("tex") == std::string::npos)
+          {
+            escape_character ("(", str);
+            escape_character (")", str);
+          }
 
-      gl2psTextOpt (str.c_str (), name.c_str (), sz,
-                    alignment_to_mode (ha, va), rotation);
-      return bbox;
-    }
+        gl2psTextOpt (str.c_str (), name.c_str (), sz,
+                      alignment_to_mode (ha, va), rotation);
+        return bbox;
+      }
 
-  // Translate and rotate coordinates in order to use bottom-left alignment
-  fix_strlist_position (x, y, z, bbox, rotation, lst);
+    // Translate and rotate coordinates in order to use bottom-left alignment
+    fix_strlist_position (x, y, z, bbox, rotation, lst);
 
-  for (std::list<octave::text_renderer::string>::iterator p = lst.begin ();
-       p != lst.end (); p++)
-    {
-      fontname = select_font ((*p).get_name (),
-                              (*p).get_weight () == "bold",
-                              (*p).get_angle () == "italic");
-      if ((*p).get_code ())
-        {
-          // This is only one character represented by a uint32 (utf8) code.
-          // We replace it by the corresponding character in the
-          // "Symbol" font except for svg which has built-in utf8 support.
-          if (term.find ("svg") == std::string::npos)
-            {
-              fontname = "Symbol";
-              str = code_to_symbol ((*p).get_code ());
-            }
-          else
-            {
-              std::stringstream ss;
-              ss << (*p).get_code ();
-              str = "&#" + ss.str () + ";";
-            }
-        }
-      else
-        {
-          str = (*p).get_string ();
-          // Escape parenthesis until gl2ps does it (see bug ##45301).
-          if (term.find ("svg") == std::string::npos)
-            {
-              escape_character ("(", str);
-              escape_character (")", str);
-            }
-        }
+    for (std::list<octave::text_renderer::string>::iterator p = lst.begin ();
+         p != lst.end (); p++)
+      {
+        fontname = select_font ((*p).get_name (),
+                                (*p).get_weight () == "bold",
+                                (*p).get_angle () == "italic");
+        if ((*p).get_code ())
+          {
+            // This is only one character represented by a uint32 (utf8) code.
+            // We replace it by the corresponding character in the
+            // "Symbol" font except for svg which has built-in utf8 support.
+            if (term.find ("svg") == std::string::npos)
+              {
+                fontname = "Symbol";
+                str = code_to_symbol ((*p).get_code ());
+              }
+            else
+              {
+                std::stringstream ss;
+                ss << (*p).get_code ();
+                str = "&#" + ss.str () + ";";
+              }
+          }
+        else
+          {
+            str = (*p).get_string ();
+            // Escape parenthesis until gl2ps does it (see bug ##45301).
+            if (term.find ("svg") == std::string::npos)
+              {
+                escape_character ("(", str);
+                escape_character (")", str);
+              }
+          }
 
-      set_color ((*p).get_color ());
-      glRasterPos3d ((*p).get_x (), (*p).get_y (), (*p).get_z ());
-      gl2psTextOpt (str.c_str (), fontname.c_str (), (*p).get_size (),
-                    GL2PS_TEXT_BL, rotation);
-    }
+        set_color ((*p).get_color ());
+        glRasterPos3d ((*p).get_x (), (*p).get_y (), (*p).get_z ());
+        gl2psTextOpt (str.c_str (), fontname.c_str (), (*p).get_size (),
+                      GL2PS_TEXT_BL, rotation);
+      }
 
-  fontname = saved_font;
-  return bbox;
-}
+    fontname = saved_font;
+    return bbox;
+  }
 
-void
-gl2ps_renderer::set_font (const base_properties& props)
-{
-  octave::opengl_renderer::set_font (props);
+  void
+  gl2ps_renderer::set_font (const base_properties& props)
+  {
+    octave::opengl_renderer::set_font (props);
 
-  // Set the interpreter so that text_to_pixels can parse strings properly
-  if (props.has_property ("interpreter"))
-    set_interpreter (props.get ("interpreter").string_value ());
+    // Set the interpreter so that text_to_pixels can parse strings properly
+    if (props.has_property ("interpreter"))
+      set_interpreter (props.get ("interpreter").string_value ());
 
-  fontsize = props.get ("fontsize_points").double_value ();
+    fontsize = props.get ("fontsize_points").double_value ();
 
-  caseless_str fn = props.get ("fontname").xtolower ().string_value ();
-  bool isbold =
-    (props.get ("fontweight").xtolower ().string_value () == "bold");
-  bool isitalic =
-    (props.get ("fontangle").xtolower ().string_value () == "italic");
+    caseless_str fn = props.get ("fontname").xtolower ().string_value ();
+    bool isbold =
+      (props.get ("fontweight").xtolower ().string_value () == "bold");
+    bool isitalic =
+      (props.get ("fontangle").xtolower ().string_value () == "italic");
 
-  fontname = select_font (fn, isbold, isitalic);
-}
+    fontname = select_font (fn, isbold, isitalic);
+  }
 
-void
-gl2ps_renderer::draw_pixels (int w, int h, const float *data)
-{
-  gl2psDrawPixels (w, h, 0, 0, GL_RGB, GL_FLOAT, data);
-}
+  void
+  gl2ps_renderer::draw_pixels (int w, int h, const float *data)
+  {
+    gl2psDrawPixels (w, h, 0, 0, GL_RGB, GL_FLOAT, data);
+  }
 
-void
-gl2ps_renderer::draw_pixels (int w, int h, const uint8_t *data)
-{
-  // gl2psDrawPixels only supports the GL_FLOAT type.
+  void
+  gl2ps_renderer::draw_pixels (int w, int h, const uint8_t *data)
+  {
+    // gl2psDrawPixels only supports the GL_FLOAT type.
 
-  OCTAVE_LOCAL_BUFFER (float, tmp_data, 3*w*h);
+    OCTAVE_LOCAL_BUFFER (float, tmp_data, 3*w*h);
 
-  static const float maxval = std::numeric_limits<float>::max ();
+    static const float maxval = std::numeric_limits<float>::max ();
 
-  for (int i = 0; i < 3*w*h; i++)
-    tmp_data[i] = data[i] / maxval;
+    for (int i = 0; i < 3*w*h; i++)
+      tmp_data[i] = data[i] / maxval;
 
-  draw_pixels (w, h, tmp_data);
-}
+    draw_pixels (w, h, tmp_data);
+  }
 
-void
-gl2ps_renderer::draw_pixels (int w, int h, const uint16_t *data)
-{
-  // gl2psDrawPixels only supports the GL_FLOAT type.
+  void
+  gl2ps_renderer::draw_pixels (int w, int h, const uint16_t *data)
+  {
+    // gl2psDrawPixels only supports the GL_FLOAT type.
 
-  OCTAVE_LOCAL_BUFFER (float, tmp_data, 3*w*h);
+    OCTAVE_LOCAL_BUFFER (float, tmp_data, 3*w*h);
 
-  static const float maxval = std::numeric_limits<float>::max ();
+    static const float maxval = std::numeric_limits<float>::max ();
 
-  for (int i = 0; i < 3*w*h; i++)
-    tmp_data[i] = data[i] / maxval;
+    for (int i = 0; i < 3*w*h; i++)
+      tmp_data[i] = data[i] / maxval;
 
-  draw_pixels (w, h, tmp_data);
-}
+    draw_pixels (w, h, tmp_data);
+  }
 
-void
-gl2ps_renderer::draw_text (const text::properties& props)
-{
-  if (props.get_string ().is_empty ())
-    return;
+  void
+  gl2ps_renderer::draw_text (const text::properties& props)
+  {
+    if (props.get_string ().is_empty ())
+      return;
 
-  // First set font properties: freetype will use them to compute
-  // coordinates and gl2ps will retrieve the color directly from the
-  // feedback buffer
-  set_font (props);
-  set_color (props.get_color_rgb ());
+    // First set font properties: freetype will use them to compute
+    // coordinates and gl2ps will retrieve the color directly from the
+    // feedback buffer
+    set_font (props);
+    set_color (props.get_color_rgb ());
 
-  std::string saved_font = fontname;
+    std::string saved_font = fontname;
 
-  // Alignment
-  int halign = 0;
-  int valign = 0;
+    // Alignment
+    int halign = 0;
+    int valign = 0;
 
-  if (props.horizontalalignment_is ("center"))
-    halign = 1;
-  else if (props.horizontalalignment_is ("right"))
-    halign = 2;
+    if (props.horizontalalignment_is ("center"))
+      halign = 1;
+    else if (props.horizontalalignment_is ("right"))
+      halign = 2;
 
-  if (props.verticalalignment_is ("top"))
-    valign = 2;
-  else if (props.verticalalignment_is ("baseline"))
-    valign = 3;
-  else if (props.verticalalignment_is ("middle"))
-    valign = 1;
+    if (props.verticalalignment_is ("top"))
+      valign = 2;
+    else if (props.verticalalignment_is ("baseline"))
+      valign = 3;
+    else if (props.verticalalignment_is ("middle"))
+      valign = 1;
 
-  // FIXME: handle margin and surrounding box
-  // Matrix bbox;
+    // FIXME: handle margin and surrounding box
+    // Matrix bbox;
 
-  const Matrix pos = get_transform ().scale (props.get_data_position ());
-  std::string str = props.get_string ().string_vector_value ().join ("\n");
+    const Matrix pos = get_transform ().scale (props.get_data_position ());
+    std::string str = props.get_string ().string_vector_value ().join ("\n");
 
-  render_text (str, pos(0), pos(1), pos.numel () > 2 ? pos(2) : 0.0,
-               halign, valign, props.get_rotation ());
-}
+    render_text (str, pos(0), pos(1), pos.numel () > 2 ? pos(2) : 0.0,
+                 halign, valign, props.get_rotation ());
+  }
 
 }
 
@@ -787,59 +784,58 @@
 namespace octave
 {
 
-// If the name of the stream begins with '|', open a pipe to the command
-// named by the rest of the string.  Otherwise, write to the named file.
+  // If the name of the stream begins with '|', open a pipe to the command
+  // named by the rest of the string.  Otherwise, write to the named file.
 
-void
-gl2ps_print (const graphics_object& fig, const std::string& stream,
-             const std::string& term)
-{
+  void
+  gl2ps_print (const graphics_object& fig, const std::string& stream,
+               const std::string& term)
+  {
 #if defined (HAVE_GL2PS_H)
 
-  // FIXME: should we have a way to create a file that begins with the
-  // character '|'?
+    // FIXME: should we have a way to create a file that begins with the
+    // character '|'?
 
-  bool have_cmd = stream.length () > 1 && stream[0] == '|';
+    bool have_cmd = stream.length () > 1 && stream[0] == '|';
 
-  FILE *fp = 0;
+    FILE *fp = 0;
 
-  octave::unwind_protect frame;
+    octave::unwind_protect frame;
 
-  if (have_cmd)
-    {
-      // Create process and pipe gl2ps output to it.
+    if (have_cmd)
+      {
+        // Create process and pipe gl2ps output to it.
 
-      std::string cmd = stream.substr (1);
+        std::string cmd = stream.substr (1);
 
-      fp = octave_popen (cmd.c_str (), "w");
+        fp = octave_popen (cmd.c_str (), "w");
 
-      if (! fp)
-        error ("print: failed to open pipe \"%s\"", stream.c_str ());
+        if (! fp)
+          error ("print: failed to open pipe \"%s\"", stream.c_str ());
 
-      frame.add_fcn (safe_pclose, fp);
-    }
-  else
-    {
-      // Write gl2ps output directly to file.
+        frame.add_fcn (safe_pclose, fp);
+      }
+    else
+      {
+        // Write gl2ps output directly to file.
 
-      fp = std::fopen (stream.c_str (), "w");
+        fp = std::fopen (stream.c_str (), "w");
 
-      if (! fp)
-        error ("gl2ps_print: failed to create file \"%s\"", stream.c_str ());
+        if (! fp)
+          error ("gl2ps_print: failed to create file \"%s\"", stream.c_str ());
 
-      frame.add_fcn (safe_fclose, fp);
-    }
+        frame.add_fcn (safe_fclose, fp);
+      }
 
-  gl2ps_renderer rend (fp, term);
+    gl2ps_renderer rend (fp, term);
 
-  rend.draw (fig, stream);
+    rend.draw (fig, stream);
 
-  // Make sure buffered commands are finished!!!
-  rend.finish ();
+    // Make sure buffered commands are finished!!!
+    rend.finish ();
 
 #else
-  err_disabled_feature ("gl2ps_print", "gl2ps");
+    err_disabled_feature ("gl2ps_print", "gl2ps");
 #endif
+  }
 }
-
-}
--- a/libinterp/corefcn/text-renderer.cc	Wed Aug 17 08:20:26 2016 -0700
+++ b/libinterp/corefcn/text-renderer.cc	Wed Aug 17 11:43:27 2016 -0400
@@ -41,105 +41,103 @@
 
 namespace octave
 {
-
-text_renderer::text_renderer (void)
-  : rep (make_text_renderer ())
-{ }
+  text_renderer::text_renderer (void)
+    : rep (make_text_renderer ())
+  { }
 
-text_renderer::~text_renderer (void)
-{
-  delete rep;
-}
+  text_renderer::~text_renderer (void)
+  {
+    delete rep;
+  }
 
-bool
-text_renderer::ok (void) const
-{
-  static bool warned = false;
+  bool
+  text_renderer::ok (void) const
+  {
+    static bool warned = false;
 
-  if (! rep)
-    {
-      if (! warned)
-        {
-          warn_disabled_feature ("opengl_renderer::render_text",
-                                 "rendering text (FreeType)");
+    if (! rep)
+      {
+        if (! warned)
+          {
+            warn_disabled_feature ("opengl_renderer::render_text",
+                                   "rendering text (FreeType)");
 
-          warned = true;
-        }
-    }
+            warned = true;
+          }
+      }
 
-  return rep != 0;
-}
+    return rep != 0;
+  }
 
-Matrix
-text_renderer::get_extent (text_element *elt, double rotation)
-{
-  static Matrix empty_extent (1, 4, 0.0);
+  Matrix
+  text_renderer::get_extent (text_element *elt, double rotation)
+  {
+    static Matrix empty_extent (1, 4, 0.0);
 
-  return ok () ? rep->get_extent (elt, rotation) : empty_extent;
-}
+    return ok () ? rep->get_extent (elt, rotation) : empty_extent;
+  }
 
-Matrix
-text_renderer::get_extent (const std::string& txt, double rotation,
-                           const caseless_str& interpreter)
-{
-  static Matrix empty_extent (1, 4, 0.0);
+  Matrix
+  text_renderer::get_extent (const std::string& txt, double rotation,
+                             const caseless_str& interpreter)
+  {
+    static Matrix empty_extent (1, 4, 0.0);
 
-  return ok () ? rep->get_extent (txt, rotation, interpreter) : empty_extent;
-}
+    return ok () ? rep->get_extent (txt, rotation, interpreter) : empty_extent;
+  }
 
-void
-text_renderer::set_font (const std::string& name, const std::string& weight,
-                         const std::string& angle, double size)
-{
-  if (ok ())
-    rep->set_font (name, weight, angle, size);
-}
+  void
+  text_renderer::set_font (const std::string& name, const std::string& weight,
+                           const std::string& angle, double size)
+  {
+    if (ok ())
+      rep->set_font (name, weight, angle, size);
+  }
 
-void
-text_renderer::set_color (const Matrix& c)
-{
-  if (ok ())
-    rep->set_color (c);
-}
+  void
+  text_renderer::set_color (const Matrix& c)
+  {
+    if (ok ())
+      rep->set_color (c);
+  }
 
-void
-text_renderer::text_to_pixels (const std::string& txt,
-                               uint8NDArray& pxls, Matrix& bbox,
-                               int halign, int valign, double rotation,
-                               const caseless_str& interpreter,
-                               bool handle_rotation)
-{
-  static Matrix empty_bbox (1, 4, 0.0);
-  static uint8NDArray empty_pxls;
+  void
+  text_renderer::text_to_pixels (const std::string& txt,
+                                 uint8NDArray& pxls, Matrix& bbox,
+                                 int halign, int valign, double rotation,
+                                 const caseless_str& interpreter,
+                                 bool handle_rotation)
+  {
+    static Matrix empty_bbox (1, 4, 0.0);
+    static uint8NDArray empty_pxls;
 
-  if (ok ())
-    rep->text_to_pixels (txt, pxls, bbox, halign, valign, rotation,
-                         interpreter, handle_rotation);
-  else
-    {
-      bbox = empty_bbox;
-      pxls = empty_pxls;
-    }
-}
+    if (ok ())
+      rep->text_to_pixels (txt, pxls, bbox, halign, valign, rotation,
+                           interpreter, handle_rotation);
+    else
+      {
+        bbox = empty_bbox;
+        pxls = empty_pxls;
+      }
+  }
 
-void
-text_renderer::text_to_strlist (const std::string& txt,
-                                std::list<text_renderer::string>& lst,
-                                Matrix& bbox, int halign, int valign,
-                                double rotation,
-                                const caseless_str& interpreter)
-{
-  static Matrix empty_bbox (1, 4, 0.0);
-  static std::list<text_renderer::string> empty_lst;
+  void
+  text_renderer::text_to_strlist (const std::string& txt,
+                                  std::list<text_renderer::string>& lst,
+                                  Matrix& bbox, int halign, int valign,
+                                  double rotation,
+                                  const caseless_str& interpreter)
+  {
+    static Matrix empty_bbox (1, 4, 0.0);
+    static std::list<text_renderer::string> empty_lst;
 
-  if (ok ())
-    rep->text_to_strlist (txt, lst, bbox, halign, valign, rotation,
-                          interpreter);
-  else
-    {
-      bbox = empty_bbox;
-      lst = empty_lst;
-    }
+    if (ok ())
+      rep->text_to_strlist (txt, lst, bbox, halign, valign, rotation,
+                            interpreter);
+    else
+      {
+        bbox = empty_bbox;
+        lst = empty_lst;
+      }
+  }
 }
-
-}
--- a/libinterp/corefcn/text-renderer.h	Wed Aug 17 08:20:26 2016 -0700
+++ b/libinterp/corefcn/text-renderer.h	Wed Aug 17 11:43:27 2016 -0400
@@ -37,181 +37,179 @@
 
 namespace octave
 {
-
-class base_text_renderer;
-
-class
-OCTINTERP_API
-text_renderer
-{
-public:
-
-  text_renderer (void);
-
-  ~text_renderer (void);
-
-  bool ok (void) const;
-
-  Matrix get_extent (text_element *elt, double rotation = 0.0);
-
-  Matrix get_extent (const std::string& txt, double rotation = 0.0,
-                     const caseless_str& interpreter = "tex");
-
-  void set_font (const std::string& name, const std::string& weight,
-                 const std::string& angle, double size);
-
-  void set_color (const Matrix& c);
-
-  void text_to_pixels (const std::string& txt,
-                       uint8NDArray& pxls, Matrix& bbox,
-                       int halign, int valign, double rotation = 0.0,
-                       const caseless_str& interpreter = "tex",
-                       bool handle_rotation = true);
-
-  class font
-  {
-  public:
-
-    font (void)
-      : name (), weight (), angle (), size (0)
-    { }
+  class base_text_renderer;
 
-    font (const std::string& nm, const std::string& wt,
-          const std::string& ang, double sz)
-      : name (nm), weight (wt), angle (ang), size (sz)
-    { }
-
-    font (const font& ft)
-      : name (ft.name), weight (ft.weight), angle (ft.angle),
-        size (ft.size)
-    { }
-
-    ~font (void) { }
-
-    font& operator = (const font& ft)
-    {
-      if (&ft != this)
-        {
-          name = ft.name;
-          weight = ft.weight;
-          angle = ft.angle;
-          size = ft.size;
-        }
-
-      return *this;
-    }
-
-    std::string get_name (void) const { return name; }
-
-    std::string get_weight (void) const { return weight; }
-
-    std::string get_angle (void) const { return angle; }
-
-    double get_size (void) const { return size; }
-
-  protected:
-
-    std::string name;
-    std::string weight;
-    std::string angle;
-    double size;
-  };
-
-  // Container for substrings after parsing.
-
-  class string
+  class
+  OCTINTERP_API
+  text_renderer
   {
   public:
 
-    string (const std::string& s, font& f, const double x0, const double y0)
-      : str (s), fnt (f), x (x0), y (y0), z (0.0), code (0),
-        color (Matrix (1,3,0.0))
-    { }
+    text_renderer (void);
+
+    ~text_renderer (void);
+
+    bool ok (void) const;
+
+    Matrix get_extent (text_element *elt, double rotation = 0.0);
+
+    Matrix get_extent (const std::string& txt, double rotation = 0.0,
+                       const caseless_str& interpreter = "tex");
 
-    string (const string& s)
-      : str (s.str), fnt (s.fnt), x (s.x), y (s.y), code (s.code),
-        color (s.color)
-    { }
+    void set_font (const std::string& name, const std::string& weight,
+                   const std::string& angle, double size);
+
+    void set_color (const Matrix& c);
 
-    ~string (void) { }
+    void text_to_pixels (const std::string& txt,
+                         uint8NDArray& pxls, Matrix& bbox,
+                         int halign, int valign, double rotation = 0.0,
+                         const caseless_str& interpreter = "tex",
+                         bool handle_rotation = true);
 
-    string& operator = (const string& s)
+    class font
     {
-      if (&s != this)
-        {
-          str = s.str;
-          fnt = s.fnt;
-          x = s.x;
-          y = s.y;
-          code = s.code;
-          color = s.color;
-        }
+    public:
+
+      font (void)
+        : name (), weight (), angle (), size (0)
+      { }
+
+      font (const std::string& nm, const std::string& wt,
+            const std::string& ang, double sz)
+        : name (nm), weight (wt), angle (ang), size (sz)
+      { }
+
+      font (const font& ft)
+        : name (ft.name), weight (ft.weight), angle (ft.angle),
+          size (ft.size)
+      { }
+
+      ~font (void) { }
 
-      return *this;
-    }
+      font& operator = (const font& ft)
+      {
+        if (&ft != this)
+          {
+            name = ft.name;
+            weight = ft.weight;
+            angle = ft.angle;
+            size = ft.size;
+          }
+
+        return *this;
+      }
+
+      std::string get_name (void) const { return name; }
+
+      std::string get_weight (void) const { return weight; }
 
-    void set_string (const std::string& s) { str = s; }
+      std::string get_angle (void) const { return angle; }
+
+      double get_size (void) const { return size; }
+
+    protected:
 
-    std::string get_string (void) const { return str; }
+      std::string name;
+      std::string weight;
+      std::string angle;
+      double size;
+    };
+
+    // Container for substrings after parsing.
+
+    class string
+    {
+    public:
 
-    std::string get_name (void) const { return fnt.get_name (); }
-
-    std::string get_weight (void) const { return fnt.get_weight (); }
+      string (const std::string& s, font& f, const double x0, const double y0)
+        : str (s), fnt (f), x (x0), y (y0), z (0.0), code (0),
+          color (Matrix (1,3,0.0))
+      { }
 
-    std::string get_angle (void) const { return fnt.get_angle (); }
+      string (const string& s)
+        : str (s.str), fnt (s.fnt), x (s.x), y (s.y), code (s.code),
+          color (s.color)
+      { }
 
-    double get_size (void) const { return fnt.get_size (); }
+      ~string (void) { }
 
-    void set_x (const double x0) { x = x0; }
-
-    double get_x (void) const { return x; }
+      string& operator = (const string& s)
+      {
+        if (&s != this)
+          {
+            str = s.str;
+            fnt = s.fnt;
+            x = s.x;
+            y = s.y;
+            code = s.code;
+            color = s.color;
+          }
 
-    void set_y (const double y0) { y = y0; }
+        return *this;
+      }
+
+      void set_string (const std::string& s) { str = s; }
+
+      std::string get_string (void) const { return str; }
 
-    double get_y (void) const { return y; }
+      std::string get_name (void) const { return fnt.get_name (); }
+
+      std::string get_weight (void) const { return fnt.get_weight (); }
+
+      std::string get_angle (void) const { return fnt.get_angle (); }
+
+      double get_size (void) const { return fnt.get_size (); }
 
-    void set_z (const double z0) { z = z0; }
+      void set_x (const double x0) { x = x0; }
+
+      double get_x (void) const { return x; }
 
-    double get_z (void) const { return z; }
+      void set_y (const double y0) { y = y0; }
+
+      double get_y (void) const { return y; }
 
-    void set_code (const uint32_t c) { code = c; }
+      void set_z (const double z0) { z = z0; }
+
+      double get_z (void) const { return z; }
 
-    uint32_t get_code (void) const { return code; }
+      void set_code (const uint32_t c) { code = c; }
+
+      uint32_t get_code (void) const { return code; }
 
-    void set_color (const uint8NDArray& c)
-    {
-      color(0) = static_cast<double> (c(0)) / 255;
-      color(1) = static_cast<double> (c(1)) / 255;
-      color(2) = static_cast<double> (c(2)) / 255;
-    }
+      void set_color (const uint8NDArray& c)
+      {
+        color(0) = static_cast<double> (c(0)) / 255;
+        color(1) = static_cast<double> (c(1)) / 255;
+        color(2) = static_cast<double> (c(2)) / 255;
+      }
+
+      Matrix get_color (void) const { return color; }
+
+    private:
 
-    Matrix get_color (void) const { return color; }
+      std::string str;
+      font fnt;
+      double x, y, z;
+      uint32_t code;
+      Matrix color;
+    };
+
+    void text_to_strlist (const std::string& txt,
+                          std::list<string>& lst, Matrix& box,
+                          int halign, int valign, double rotation = 0.0,
+                          const caseless_str& interpreter = "tex");
 
   private:
 
-    std::string str;
-    font fnt;
-    double x, y, z;
-    uint32_t code;
-    Matrix color;
-  };
+    base_text_renderer *rep;
 
-  void text_to_strlist (const std::string& txt,
-                        std::list<string>& lst, Matrix& box,
-                        int halign, int valign, double rotation = 0.0,
-                        const caseless_str& interpreter = "tex");
+    // No copying!
 
-private:
-
-  base_text_renderer *rep;
-
-  // No copying!
+    text_renderer (const text_renderer&);
 
-  text_renderer (const text_renderer&);
-
-  text_renderer& operator = (const text_renderer&);
-};
-
+    text_renderer& operator = (const text_renderer&);
+  };
 }
 
 #endif
--- a/libinterp/octave-value/ov-java.cc	Wed Aug 17 08:20:26 2016 -0700
+++ b/libinterp/octave-value/ov-java.cc	Wed Aug 17 11:43:27 2016 -0400
@@ -184,100 +184,99 @@
 
 namespace octave
 {
-class JVMArgs
-{
-public:
-
-  JVMArgs (void)
-  {
-    vm_args.version = JNI_VERSION_1_2;
-    vm_args.nOptions = 0;
-    vm_args.options = 0;
-    vm_args.ignoreUnrecognized = false;
-  }
-
-  ~JVMArgs (void)
-  {
-    clean ();
-  }
-
-  JavaVMInitArgs *to_args ()
-  {
-    update ();
-    return &vm_args;
-  }
-
-  void add (const std::string& opt)
-  {
-    java_opts.push_back (opt);
-  }
-
-  void read_java_opts (const std::string& filename)
+  class JVMArgs
   {
-    std::ifstream js (filename.c_str ());
-
-    if (! js.bad () && ! js.fail ())
-      {
-        std::string line;
-
-        while (! js.eof () && ! js.fail ())
-          {
-            std::getline (js, line);
-
-            if (line.find ("-") == 0)
-              java_opts.push_back (line);
-            else if (line.length () > 0 && Vdebug_java)
-              std::cerr << "invalid JVM option, skipping: " << line << std::endl;
-          }
-      }
-  }
-
-private:
-
-  void clean (void)
-  {
-    if (vm_args.options != 0)
-      {
-        for (int i = 0; i < vm_args.nOptions; i++)
-          delete [] vm_args.options[i].optionString;
-
-        delete [] vm_args.options;
-
-        vm_args.options = 0;
-        vm_args.nOptions = 0;
-      }
-  }
-
-  void update (void)
-  {
-    clean ();
-
-    if (java_opts.size () > 0)
-      {
-        int index = 0;
-
-        vm_args.nOptions = java_opts.size ();
-        vm_args.options = new JavaVMOption [vm_args.nOptions];
-
-        for (std::list<std::string>::const_iterator it = java_opts.begin ();
-             it != java_opts.end (); ++it)
-          {
-            if (Vdebug_java)
-              std::cout << *it << std::endl;
-            vm_args.options[index++].optionString = strsave ((*it).c_str ());
-          }
-
-        java_opts.clear ();
-      }
-  }
-
-private:
-
-  JavaVMInitArgs vm_args;
-
-  std::list<std::string> java_opts;
-};
-
+  public:
+
+    JVMArgs (void)
+    {
+      vm_args.version = JNI_VERSION_1_2;
+      vm_args.nOptions = 0;
+      vm_args.options = 0;
+      vm_args.ignoreUnrecognized = false;
+    }
+
+    ~JVMArgs (void)
+    {
+      clean ();
+    }
+
+    JavaVMInitArgs *to_args ()
+    {
+      update ();
+      return &vm_args;
+    }
+
+    void add (const std::string& opt)
+    {
+      java_opts.push_back (opt);
+    }
+
+    void read_java_opts (const std::string& filename)
+    {
+      std::ifstream js (filename.c_str ());
+
+      if (! js.bad () && ! js.fail ())
+        {
+          std::string line;
+
+          while (! js.eof () && ! js.fail ())
+            {
+              std::getline (js, line);
+
+              if (line.find ("-") == 0)
+                java_opts.push_back (line);
+              else if (line.length () > 0 && Vdebug_java)
+                std::cerr << "invalid JVM option, skipping: " << line << std::endl;
+            }
+        }
+    }
+
+  private:
+
+    void clean (void)
+    {
+      if (vm_args.options != 0)
+        {
+          for (int i = 0; i < vm_args.nOptions; i++)
+            delete [] vm_args.options[i].optionString;
+
+          delete [] vm_args.options;
+
+          vm_args.options = 0;
+          vm_args.nOptions = 0;
+        }
+    }
+
+    void update (void)
+    {
+      clean ();
+
+      if (java_opts.size () > 0)
+        {
+          int index = 0;
+
+          vm_args.nOptions = java_opts.size ();
+          vm_args.options = new JavaVMOption [vm_args.nOptions];
+
+          for (std::list<std::string>::const_iterator it = java_opts.begin ();
+               it != java_opts.end (); ++it)
+            {
+              if (Vdebug_java)
+                std::cout << *it << std::endl;
+              vm_args.options[index++].optionString = strsave ((*it).c_str ());
+            }
+
+          java_opts.clear ();
+        }
+    }
+
+  private:
+
+    JavaVMInitArgs vm_args;
+
+    std::list<std::string> java_opts;
+  };
 }
 
 #if defined (OCTAVE_USE_WINDOWS_API)