GNU Octave  6.2.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
gl-render.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 2008-2021 The Octave Project Developers
4 //
5 // See the file COPYRIGHT.md in the top-level directory of this
6 // distribution or <https://octave.org/copyright/>.
7 //
8 // This file is part of Octave.
9 //
10 // Octave is free software: you can redistribute it and/or modify it
11 // under the terms of the GNU General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // Octave is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with Octave; see the file COPYING. If not, see
22 // <https://www.gnu.org/licenses/>.
23 //
24 ////////////////////////////////////////////////////////////////////////
25 
26 #if defined (HAVE_CONFIG_H)
27 # include "config.h"
28 #endif
29 
30 #include <sstream>
31 
32 #if defined (HAVE_WINDOWS_H)
33 # define WIN32_LEAN_AND_MEAN
34 # include <windows.h>
35 #endif
36 
37 #include "lo-mappers.h"
38 #include "oct-locbuf.h"
39 #include "oct-refcount.h"
40 
41 #include "errwarn.h"
42 #include "gl-render.h"
43 #include "interpreter-private.h"
44 #include "oct-opengl.h"
45 #include "text-renderer.h"
46 
47 namespace octave
48 {
49 #if defined (HAVE_OPENGL)
50 
51  static int
53  {
54  int m = 1;
55 
56  while (m < n && m < std::numeric_limits<int>::max ())
57  m <<= 1;
58 
59  return m;
60  }
61 
62 #define LIGHT_MODE GL_FRONT_AND_BACK
63 
64  // Use symbolic names for axes
65  enum
66  {
69  Z_AXIS
70  };
71 
72  // Use symbolic names for color mode
73  enum
74  {
78  TEXTURE
79  };
80 
81  // Use symbolic names for lighting
82  enum
83  {
85  //FLAT, // Already declared in anonymous enum for color mode
86  GOURAUD = 2
87  };
88 
89  // Win32 API requires the CALLBACK attributes for
90  // GLU callback functions. Define it to empty on
91  // other platforms.
92 #if ! defined (CALLBACK)
93 # define CALLBACK
94 #endif
95 
96  class
98  {
99  protected:
101  {
102  public:
104  : m_glfcns (glfcns), id (), w (), h (), tw (), th (), tx (), ty (),
105  valid (false), count (1)
106  { }
107 
108  texture_rep (opengl_functions& glfcns, GLuint id_arg,
109  int w_arg, int h_arg, int tw_arg, int th_arg)
110  : m_glfcns (glfcns), id (id_arg), w (w_arg), h (h_arg),
111  tw (tw_arg), th (th_arg), tx (double(w)/tw), ty (double(h)/th),
112  valid (true), count (1)
113  { }
114 
116  {
117  if (valid)
118  m_glfcns.glDeleteTextures (1, &id);
119  }
120 
121  void bind (int mode) const
122  { if (valid) m_glfcns.glBindTexture (mode, id); }
123 
124  void tex_coord (double q, double r) const
125  { if (valid) m_glfcns.glTexCoord2d (q*tx, r*ty); }
126 
128  GLuint id;
129  int w, h;
130  int tw, th;
131  double tx, ty;
132  bool valid;
134  };
135 
137 
138  private:
139  opengl_texture (texture_rep *_rep) : rep (_rep) { }
140 
141  public:
143  : rep (new texture_rep (glfcns)) { }
144 
146  : rep (tx.rep)
147  {
148  rep->count++;
149  }
150 
152  {
153  if (--rep->count == 0)
154  delete rep;
155  }
156 
157  opengl_texture& operator = (const opengl_texture& tx)
158  {
159  if (&tx != this)
160  {
161  if (--rep->count == 0)
162  delete rep;
163 
164  rep = tx.rep;
165  rep->count++;
166  }
167 
168  return *this;
169  }
170 
171  static opengl_texture create (opengl_functions& glfcns,
172  const octave_value& data);
173 
174  void bind (int mode = GL_TEXTURE_2D) const
175  { rep->bind (mode); }
176 
177  void tex_coord (double q, double r) const
178  { rep->tex_coord (q, r); }
179 
180  bool is_valid (void) const
181  { return rep->valid; }
182  };
183 
184  opengl_texture
186  {
187  opengl_texture retval (glfcns);
188 
189  dim_vector dv (data.dims ());
190 
191  // Expect RGB data
192  if (dv.ndims () == 3 && dv(2) == 3)
193  {
194  // FIXME: dim_vectors hold octave_idx_type values.
195  // Should we check for dimensions larger than intmax?
196  int h, w, tw, th;
197  h = dv(0), w = dv(1);
198 
199  // Return early if the image data are larger than the texture
200  // can hold
201  int max_size;
202  glGetIntegerv (GL_MAX_TEXTURE_SIZE, &max_size);
203  static bool warned = false;
204  if (h > max_size || w > max_size)
205  {
206  if (! warned)
207  {
208  warning ("opengl_texture::create: the opengl library in use "
209  "doesn't support images with either dimension larger "
210  "than %d. Not rendering.", max_size);
211  warned = true;
212  }
213 
214  return opengl_texture (glfcns);
215  }
216 
217  GLuint id;
218  bool ok = true;
219 
220  tw = next_power_of_2 (w);
221  th = next_power_of_2 (h);
222 
223  glfcns.glGenTextures (1, &id);
224  glfcns.glBindTexture (GL_TEXTURE_2D, id);
225 
226  if (data.is_double_type ())
227  {
228  const NDArray xdata = data.array_value ();
229 
230  OCTAVE_LOCAL_BUFFER (GLfloat, a, (3*tw*th));
231 
232  for (int i = 0; i < h; i++)
233  {
234  for (int j = 0, idx = i*tw*3; j < w; j++, idx += 3)
235  {
236  a[idx] = xdata(i,j,0);
237  a[idx+1] = xdata(i,j,1);
238  a[idx+2] = xdata(i,j,2);
239  }
240  }
241 
242  glfcns.glTexImage2D (GL_TEXTURE_2D, 0, 3, tw, th, 0, GL_RGB,
243  GL_FLOAT, a);
244  }
245 
246  else if (data.is_single_type ())
247  {
248  const FloatNDArray xdata = data.float_array_value ();
249 
250  OCTAVE_LOCAL_BUFFER (GLfloat, a, (3*tw*th));
251 
252  for (int i = 0; i < h; i++)
253  {
254  for (int j = 0, idx = i*tw*3; j < w; j++, idx += 3)
255  {
256  a[idx] = xdata(i,j,0);
257  a[idx+1] = xdata(i,j,1);
258  a[idx+2] = xdata(i,j,2);
259  }
260  }
261 
262  glfcns.glTexImage2D (GL_TEXTURE_2D, 0, 3, tw, th, 0, GL_RGB,
263  GL_FLOAT, a);
264  }
265  else if (data.is_uint16_type ())
266  {
267  const uint16NDArray xdata = data.uint16_array_value ();
268 
269  OCTAVE_LOCAL_BUFFER (GLushort, a, (3*tw*th));
270 
271  for (int i = 0; i < h; i++)
272  {
273  for (int j = 0, idx = i*tw*3; j < w; j++, idx += 3)
274  {
275  a[idx] = xdata(i,j,0);
276  a[idx+1] = xdata(i,j,1);
277  a[idx+2] = xdata(i,j,2);
278  }
279  }
280 
281  glfcns.glTexImage2D (GL_TEXTURE_2D, 0, 3, tw, th, 0,
282  GL_RGB, GL_UNSIGNED_SHORT, a);
283  }
284  else if (data.is_uint8_type ())
285  {
286  const uint8NDArray xdata = data.uint8_array_value ();
287 
288  OCTAVE_LOCAL_BUFFER (GLubyte, a, (3*tw*th));
289 
290  for (int i = 0; i < h; i++)
291  {
292  for (int j = 0, idx = i*tw*3; j < w; j++, idx += 3)
293  {
294  a[idx] = xdata(i,j,0);
295  a[idx+1] = xdata(i,j,1);
296  a[idx+2] = xdata(i,j,2);
297  }
298  }
299 
300  glfcns.glTexImage2D (GL_TEXTURE_2D, 0, 3, tw, th, 0,
301  GL_RGB, GL_UNSIGNED_BYTE, a);
302  }
303  else
304  {
305  ok = false;
306  warning ("opengl_texture::create: invalid image data type, expected double, single, uint8, or uint16");
307  }
308 
309  if (ok)
310  {
311  glfcns.glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
312  glfcns.glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
313 
314  if (glfcns.glGetError () != GL_NO_ERROR)
315  warning ("opengl_texture::create: OpenGL error while generating texture data");
316  else
317  retval = opengl_texture (new texture_rep (glfcns, id, w, h, tw, th));
318  }
319  }
320  else
321  warning ("opengl_texture::create: invalid texture data size");
322 
323  return retval;
324  }
325 
326  class
328  {
329  public:
330 #if defined (HAVE_FRAMEWORK_OPENGL) && defined (HAVE_GLUTESSCALLBACK_THREEDOTS)
331  typedef GLvoid (CALLBACK *fcn) (...);
332 #else
333  typedef void (CALLBACK *fcn) (void);
334 #endif
335 
336  public:
337 
338  opengl_tessellator (void) : glu_tess (nullptr), fill () { init (); }
339 
340  // No copying!
341 
343 
344  opengl_tessellator operator = (const opengl_tessellator&) = delete;
345 
346  virtual ~opengl_tessellator (void)
347  { if (glu_tess) gluDeleteTess (glu_tess); }
348 
349  void begin_polygon (bool filled = true)
350  {
351  gluTessProperty (glu_tess, GLU_TESS_BOUNDARY_ONLY,
352  (filled ? GL_FALSE : GL_TRUE));
353  fill = filled;
354  gluTessBeginPolygon (glu_tess, this);
355  }
356 
357  void end_polygon (void) const
358  { gluTessEndPolygon (glu_tess); }
359 
360  void begin_contour (void) const
361  { gluTessBeginContour (glu_tess); }
362 
363  void end_contour (void) const
364  { gluTessEndContour (glu_tess); }
365 
366  void add_vertex (double *loc, void *data) const
367  { gluTessVertex (glu_tess, loc, data); }
368 
369  protected:
370  virtual void begin (GLenum /*type*/) { }
371 
372  virtual void end (void) { }
373 
374  virtual void vertex (void * /*data*/) { }
375 
376  virtual void combine (GLdouble [3] /*c*/, void * [4] /*data*/,
377  GLfloat [4] /*w*/, void ** /*out_data*/) { }
378 
379  virtual void edge_flag (GLboolean /*flag*/) { }
380 
381  virtual void error (GLenum err)
382  { ::error ("OpenGL tessellation error (%d)", err); }
383 
384  virtual void init (void)
385  {
386  glu_tess = gluNewTess ();
387 
388  gluTessCallback (glu_tess, GLU_TESS_BEGIN_DATA,
389  reinterpret_cast<fcn> (tess_begin));
390  gluTessCallback (glu_tess, GLU_TESS_END_DATA,
391  reinterpret_cast<fcn> (tess_end));
392  gluTessCallback (glu_tess, GLU_TESS_VERTEX_DATA,
393  reinterpret_cast<fcn> (tess_vertex));
394  gluTessCallback (glu_tess, GLU_TESS_COMBINE_DATA,
395  reinterpret_cast<fcn> (tess_combine));
396  gluTessCallback (glu_tess, GLU_TESS_EDGE_FLAG_DATA,
397  reinterpret_cast<fcn> (tess_edge_flag));
398  gluTessCallback (glu_tess, GLU_TESS_ERROR_DATA,
399  reinterpret_cast<fcn> (tess_error));
400  }
401 
402  bool is_filled (void) const { return fill; }
403 
404  private:
405  static void CALLBACK tess_begin (GLenum type, void *t)
406  { reinterpret_cast<opengl_tessellator *> (t)->begin (type); }
407 
408  static void CALLBACK tess_end (void *t)
409  { reinterpret_cast<opengl_tessellator *> (t)->end (); }
410 
411  static void CALLBACK tess_vertex (void *v, void *t)
412  { reinterpret_cast<opengl_tessellator *> (t)->vertex (v); }
413 
414  static void CALLBACK tess_combine (GLdouble c[3], void *v[4], GLfloat w[4],
415  void **out, void *t)
416  { reinterpret_cast<opengl_tessellator *> (t)->combine (c, v, w, out); }
417 
418  static void CALLBACK tess_edge_flag (GLboolean flag, void *t)
419  { reinterpret_cast<opengl_tessellator *> (t)->edge_flag (flag); }
420 
421  static void CALLBACK tess_error (GLenum err, void *t)
422  { reinterpret_cast<opengl_tessellator *> (t)->error (err); }
423 
424  private:
425 
426  GLUtesselator *glu_tess;
427  bool fill;
428  };
429 
430  class
432  {
433  public:
435  {
436  public:
441  double alpha;
442  float ambient;
443  float diffuse;
444  float specular;
447 
448  // reference counter
450 
452  : coords (), color (), vertex_normal (), face_normal (), alpha (),
453  ambient (), diffuse (), specular (), specular_exp (),
454  specular_color_refl (), count (1) { }
455 
456  vertex_data_rep (const Matrix& c, const Matrix& col, const Matrix& vn,
457  const Matrix& fn, double a, float as, float ds, float ss,
458  float se, float scr)
459  : coords (c), color (col), vertex_normal (vn), face_normal (fn),
460  alpha (a), ambient (as), diffuse (ds), specular (ss),
461  specular_exp (se), specular_color_refl (scr), count (1) { }
462  };
463 
464  private:
466 
467  vertex_data_rep * nil_rep (void) const
468  {
469  static vertex_data_rep *nr = new vertex_data_rep ();
470 
471  return nr;
472  }
473 
474  public:
475  vertex_data (void) : rep (nil_rep ())
476  { rep->count++; }
477 
478  vertex_data (const vertex_data& v) : rep (v.rep)
479  { rep->count++; }
480 
481  vertex_data (const Matrix& c, const Matrix& col, const Matrix& vn,
482  const Matrix& fn, double a, float as, float ds, float ss,
483  float se, float scr)
484  : rep (new vertex_data_rep (c, col, vn, fn, a, as, ds, ss, se, scr))
485  { }
486 
488  : rep (new_rep) { }
489 
491  {
492  if (--rep->count == 0)
493  delete rep;
494  }
495 
496  vertex_data& operator = (const vertex_data& v)
497  {
498  if (&v != this)
499  {
500  if (--rep->count == 0)
501  delete rep;
502 
503  rep = v.rep;
504  rep->count++;
505  }
506 
507  return *this;
508  }
509 
510  vertex_data_rep * get_rep (void) const { return rep; }
511  };
512 
513  class
515  {
516  public:
517  patch_tessellator (opengl_renderer *r, int cmode, int lmode, bool fl,
518  float idx = 0.0)
519  : opengl_tessellator (), renderer (r),
520  color_mode (cmode), light_mode (lmode), face_lighting (fl), index (idx),
521  first (true), tmp_vdata ()
522  { }
523 
524  protected:
525  void begin (GLenum type)
526  {
527  opengl_functions& glfcns = renderer->get_opengl_functions ();
528 
529  //printf ("patch_tessellator::begin (%d)\n", type);
530  first = true;
531 
532  if (color_mode == INTERP || light_mode == GOURAUD)
533  glfcns.glShadeModel (GL_SMOOTH);
534  else
535  glfcns.glShadeModel (GL_FLAT);
536 
537  if (is_filled ())
538  renderer->set_polygon_offset (true, index);
539 
540  glfcns.glBegin (type);
541  }
542 
543  void end (void)
544  {
545  opengl_functions& glfcns = renderer->get_opengl_functions ();
546 
547  //printf ("patch_tessellator::end\n");
548  glfcns.glEnd ();
549  renderer->set_polygon_offset (false);
550  }
551 
552  void vertex (void *data)
553  {
554  opengl_functions& glfcns = renderer->get_opengl_functions ();
555 
557  = reinterpret_cast<vertex_data::vertex_data_rep *> (data);
558  //printf ("patch_tessellator::vertex (%g, %g, %g)\n", v->coords(0), v->coords(1), v->coords(2));
559 
560  // NOTE: OpenGL can re-order vertices. For "flat" coloring of FaceColor
561  // the first vertex must be identified in the draw_patch routine.
562 
563  if (color_mode == INTERP || (color_mode == FLAT && ! is_filled ()))
564  {
565  Matrix col = v->color;
566 
567  if (col.numel () == 3)
568  {
569  glfcns.glColor4d (col(0), col(1), col(2), v->alpha);
570  if (light_mode > 0)
571  {
572  // edge lighting only uses ambient light
573  float buf[4] = { 0.0f, 0.0f, 0.0f, 1.0f };;
574 
575  if (face_lighting)
576  for (int k = 0; k < 3; k++)
577  buf[k] = v->specular * (v->specular_color_refl +
578  (1 - v->specular_color_refl) * col(k));
579  glfcns.glMaterialfv (LIGHT_MODE, GL_SPECULAR, buf);
580 
581  if (face_lighting)
582  for (int k = 0; k < 3; k++)
583  buf[k] = (v->diffuse * col(k));
584  glfcns.glMaterialfv (LIGHT_MODE, GL_DIFFUSE, buf);
585 
586  for (int k = 0; k < 3; k++)
587  buf[k] = (v->ambient * col(k));
588  glfcns.glMaterialfv (LIGHT_MODE, GL_AMBIENT, buf);
589  }
590  }
591  }
592 
593  if (light_mode == FLAT && first)
594  glfcns.glNormal3dv (v->face_normal.data ());
595  else if (light_mode == GOURAUD)
596  glfcns.glNormal3dv (v->vertex_normal.data ());
597 
598  glfcns.glVertex3dv (v->coords.data ());
599 
600  first = false;
601  }
602 
603  void combine (GLdouble xyz[3], void *data[4], GLfloat w[4], void **out_data)
604  {
605  //printf ("patch_tessellator::combine\n");
606 
608  int vmax = 4;
609 
610  for (int i = 0; i < 4; i++)
611  {
612  v[i] = reinterpret_cast<vertex_data::vertex_data_rep *> (data[i]);
613 
614  if (vmax == 4 && ! v[i])
615  vmax = i;
616  }
617 
618  Matrix vv (1, 3, 0.0);
619  Matrix cc;
620  Matrix vnn (1, 3, 0.0);
621  Matrix fnn (1, 3, 0.0);
622  double aa = 0.0;
623 
624  vv(0) = xyz[0];
625  vv(1) = xyz[1];
626  vv(2) = xyz[2];
627 
628  if (v[0]->color.numel ())
629  {
630  cc.resize (1, 3, 0.0);
631  for (int ic = 0; ic < 3; ic++)
632  for (int iv = 0; iv < vmax; iv++)
633  cc(ic) += (w[iv] * v[iv]->color (ic));
634  }
635 
636  if (v[0]->vertex_normal.numel () > 0)
637  {
638  for (int in = 0; in < 3; in++)
639  for (int iv = 0; iv < vmax; iv++)
640  vnn(in) += (w[iv] * v[iv]->vertex_normal (in));
641  }
642 
643  if (v[0]->face_normal.numel () > 0)
644  {
645  for (int in = 0; in < 3; in++)
646  for (int iv = 0; iv < vmax; iv++)
647  fnn(in) += (w[iv] * v[iv]->face_normal (in));
648  }
649 
650  for (int iv = 0; iv < vmax; iv++)
651  aa += (w[iv] * v[iv]->alpha);
652 
653  vertex_data new_v (vv, cc, vnn, fnn, aa, v[0]->ambient, v[0]->diffuse,
654  v[0]->specular, v[0]->specular_exp,
655  v[0]->specular_color_refl);
656  tmp_vdata.push_back (new_v);
657 
658  *out_data = new_v.get_rep ();
659  }
660 
661  private:
662 
663  // No copying!
664 
666 
667  patch_tessellator& operator = (const patch_tessellator&) = delete;
668 
673  int index;
674  bool first;
675  std::list<vertex_data> tmp_vdata;
676  };
677 
678 #else
679 
680  class
682  {
683  // Dummy class.
684  };
685 
686 #endif
687 
689  : m_glfcns (glfcns), xmin (), xmax (), ymin (), ymax (), zmin (), zmax (),
690  m_devpixratio (1.0), xform (), toolkit (), xZ1 (), xZ2 (), marker_id (),
691  filled_marker_id (), camera_pos (), camera_dir (), view_vector (),
692  interpreter ("none"), txt_renderer (), m_current_light (0),
693  m_max_lights (0), selecting (false), m_printing (false)
694  {
695  // This constructor will fail if we don't have OpenGL or if the data
696  // types we assumed in our public interface aren't compatible with the
697  // OpenGL types.
698 
699 #if defined (HAVE_OPENGL)
700 
701  // Ensure that we can't request an image larger than OpenGL can handle.
702  // FIXME: should we check signed vs. unsigned?
703 
704  static bool ok = (sizeof (int) <= sizeof (GLsizei));
705 
706  if (! ok)
707  error ("the size of GLsizei is smaller than the size of int");
708 
709 #else
710 
711  err_disabled_feature ("opengl_renderer", "OpenGL");
712 
713 #endif
714  }
715 
716  void
717  opengl_renderer::draw (const graphics_object& go, bool toplevel)
718  {
719  if (! go.valid_object ())
720  return;
721 
722  const base_properties& props = go.get_properties ();
723 
724  if (! toolkit)
725  toolkit = props.get_toolkit ();
726 
727  if (go.isa ("figure"))
728  draw_figure (dynamic_cast<const figure::properties&> (props));
729  else if (go.isa ("axes"))
730  draw_axes (dynamic_cast<const axes::properties&> (props));
731  else if (go.isa ("line"))
732  draw_line (dynamic_cast<const line::properties&> (props));
733  else if (go.isa ("surface"))
734  draw_surface (dynamic_cast<const surface::properties&> (props));
735  else if (go.isa ("patch"))
736  draw_patch (dynamic_cast<const patch::properties&> (props));
737  else if (go.isa ("light"))
738  draw_light (dynamic_cast<const light::properties&> (props));
739  else if (go.isa ("hggroup"))
740  draw_hggroup (dynamic_cast<const hggroup::properties&> (props));
741  else if (go.isa ("text"))
742  draw_text (dynamic_cast<const text::properties&> (props));
743  else if (go.isa ("image"))
744  draw_image (dynamic_cast<const image::properties&> (props));
745  else if (go.isa ("uimenu") || go.isa ("uicontrol")
746  || go.isa ("uicontextmenu") || go.isa ("uitoolbar")
747  || go.isa ("uipushtool") || go.isa ("uitoggletool")
748  || go.isa ("uitable"))
749  ; // SKIP
750  else if (go.isa ("uipanel"))
751  {
752  if (toplevel)
753  draw_uipanel (dynamic_cast<const uipanel::properties&> (props), go);
754  }
755  else if (go.isa ("uibuttongroup"))
756  {
757  if (toplevel)
758  draw_uibuttongroup (dynamic_cast<const uibuttongroup::properties&> (props), go);
759  }
760  else
761  {
762  warning ("opengl_renderer: cannot render object of type '%s'",
763  props.graphics_object_name ().c_str ());
764  }
765 
766 #if defined (HAVE_OPENGL)
767 
768  GLenum gl_error = m_glfcns.glGetError ();
769  if (gl_error)
770  warning ("opengl_renderer: Error '%s' (%d) occurred drawing '%s' object",
771  gluErrorString (gl_error), gl_error, props.graphics_object_name ().c_str ());
772 
773 #endif
774  }
775 
776  void
778  {
779  m_printing = props.is___printing__ ();
780 
781  // Initialize OpenGL context
782  init_gl_context (props.is_graphicssmoothing (), props.get_color_rgb ());
783 
784 #if defined (HAVE_OPENGL)
785 
786  props.set___gl_extensions__ (get_string (GL_EXTENSIONS));
787  props.set___gl_renderer__ (get_string (GL_RENDERER));
788  props.set___gl_vendor__ (get_string (GL_VENDOR));
789  props.set___gl_version__ (get_string (GL_VERSION));
790 
791 #endif
792 
793  // Draw children
794 
795  draw (props.get_all_children (), false);
796  }
797 
798  void
800  const graphics_object& go)
801  {
802  graphics_object fig = go.get_ancestor ("figure");
803  const figure::properties& figProps
804  = dynamic_cast<const figure::properties&> (fig.get_properties ());
805 
806  // Initialize OpenGL context
807 
808  init_gl_context (figProps.is_graphicssmoothing (),
809  props.get_backgroundcolor_rgb ());
810 
811  // Draw children
812 
813  draw (props.get_all_children (), false);
814  }
815 
816  void
818  const graphics_object& go)
819  {
820  graphics_object fig = go.get_ancestor ("figure");
821  const figure::properties& figProps
822  = dynamic_cast<const figure::properties&> (fig.get_properties ());
823 
824  // Initialize OpenGL context
825 
826  init_gl_context (figProps.is_graphicssmoothing (),
827  props.get_backgroundcolor_rgb ());
828 
829  // Draw children
830 
831  draw (props.get_all_children (), false);
832  }
833 
834  void
835  opengl_renderer::init_gl_context (bool enhanced, const Matrix& c)
836  {
837 #if defined (HAVE_OPENGL)
838 
839  // Initialize OpenGL context
840 
841  m_glfcns.glEnable (GL_DEPTH_TEST);
842  m_glfcns.glDepthFunc (GL_LEQUAL);
843  m_glfcns.glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
844  m_glfcns.glAlphaFunc (GL_GREATER, 0.0f);
845  m_glfcns.glEnable (GL_NORMALIZE);
846  m_glfcns.glEnable (GL_BLEND);
847 
848  if (enhanced)
849  {
850  m_glfcns.glEnable (GL_MULTISAMPLE);
851  bool has_multisample = false;
852  if (! m_glfcns.glGetError ())
853  {
854  GLint iMultiSample, iNumSamples;
855  m_glfcns.glGetIntegerv (GL_SAMPLE_BUFFERS, &iMultiSample);
856  m_glfcns.glGetIntegerv (GL_SAMPLES, &iNumSamples);
857  if (iMultiSample == GL_TRUE && iNumSamples > 0)
858  has_multisample = true;
859  }
860 
861  if (! has_multisample)
862  {
863  // MultiSample not implemented. Use old-style anti-aliasing
864  m_glfcns.glDisable (GL_MULTISAMPLE);
865  // Disabling GL_MULTISAMPLE will raise a gl error if it is not
866  // implemented. Thus, call glGetError to reset the error state.
867  m_glfcns.glGetError ();
868 
869  m_glfcns.glEnable (GL_LINE_SMOOTH);
870  m_glfcns.glHint (GL_LINE_SMOOTH_HINT, GL_NICEST);
871  }
872  }
873  else
874  {
875  m_glfcns.glDisable (GL_LINE_SMOOTH);
876  }
877 
878  // Clear background
879 
880  if (c.numel () >= 3)
881  {
882  m_glfcns.glClearColor (c(0), c(1), c(2), 1);
883  m_glfcns.glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
884  }
885 
886  GLenum gl_error = m_glfcns.glGetError ();
887  if (gl_error)
888  warning ("opengl_renderer: Error '%s' (%d) occurred in init_gl_context",
889  gluErrorString (gl_error), gl_error);
890 
891 #else
892 
893  octave_unused_parameter (enhanced);
894  octave_unused_parameter (c);
895 
896  // This shouldn't happen because construction of opengl_renderer
897  // objects is supposed to be impossible if OpenGL is not available.
898 
899  panic_impossible ();
900 
901 #endif
902  }
903 
904  void
905  opengl_renderer::render_grid (const double linewidth,
906  const std::string& gridstyle,
907  const Matrix& gridcolor, const double gridalpha,
908  const Matrix& ticks, double lim1, double lim2,
909  double p1, double p1N, double p2, double p2N,
910  int xyz, bool is_3D)
911  {
912 #if defined (HAVE_OPENGL)
913 
914  m_glfcns.glColor4d (gridcolor(0), gridcolor(1), gridcolor(2), gridalpha);
915  set_linestyle (gridstyle, true, linewidth);
916  m_glfcns.glBegin (GL_LINES);
917  for (int i = 0; i < ticks.numel (); i++)
918  {
919  double val = ticks(i);
920  if (lim1 <= val && val <= lim2)
921  {
922  if (xyz == X_AXIS)
923  {
924  m_glfcns.glVertex3d (val, p1N, p2);
925  m_glfcns.glVertex3d (val, p1, p2);
926  if (is_3D)
927  {
928  m_glfcns.glVertex3d (val, p1, p2N);
929  m_glfcns.glVertex3d (val, p1, p2);
930  }
931  }
932  else if (xyz == Y_AXIS)
933  {
934  m_glfcns.glVertex3d (p1N, val, p2);
935  m_glfcns.glVertex3d (p1, val, p2);
936  if (is_3D)
937  {
938  m_glfcns.glVertex3d (p1, val, p2N);
939  m_glfcns.glVertex3d (p1, val, p2);
940  }
941  }
942  else if (xyz == Z_AXIS)
943  {
944  m_glfcns.glVertex3d (p1N, p2, val);
945  m_glfcns.glVertex3d (p1, p2, val);
946  m_glfcns.glVertex3d (p1, p2N, val);
947  m_glfcns.glVertex3d (p1, p2, val);
948  }
949  }
950  }
951  m_glfcns.glEnd ();
952  set_linestyle ("-"); // Disable LineStipple
953  double black[3] = {0, 0, 0};
954  m_glfcns.glColor3dv (black);
955 
956 #else
957 
958  octave_unused_parameter (linewidth);
959  octave_unused_parameter (gridstyle);
960  octave_unused_parameter (gridcolor);
961  octave_unused_parameter (gridalpha);
962  octave_unused_parameter (ticks);
963  octave_unused_parameter (lim1);
964  octave_unused_parameter (lim2);
965  octave_unused_parameter (p1);
966  octave_unused_parameter (p1N);
967  octave_unused_parameter (p2);
968  octave_unused_parameter (p2N);
969  octave_unused_parameter (xyz);
970  octave_unused_parameter (is_3D);
971 
972  // This shouldn't happen because construction of opengl_renderer
973  // objects is supposed to be impossible if OpenGL is not available.
974 
975  panic_impossible ();
976 
977 #endif
978  }
979 
980  void
982  double lim1, double lim2,
983  double p1, double p1N,
984  double p2, double p2N,
985  double dx, double dy, double dz,
986  int xyz, bool mirror)
987  {
988 #if defined (HAVE_OPENGL)
989 
990  m_glfcns.glBegin (GL_LINES);
991 
992  for (int i = 0; i < ticks.numel (); i++)
993  {
994  double val = ticks(i);
995 
996  if (lim1 <= val && val <= lim2)
997  {
998  if (xyz == X_AXIS)
999  {
1000  m_glfcns.glVertex3d (val, p1, p2);
1001  m_glfcns.glVertex3d (val, p1+dy, p2+dz);
1002  if (mirror)
1003  {
1004  m_glfcns.glVertex3d (val, p1N, p2N);
1005  m_glfcns.glVertex3d (val, p1N-dy, p2N-dz);
1006  }
1007  }
1008  else if (xyz == Y_AXIS)
1009  {
1010  m_glfcns.glVertex3d (p1, val, p2);
1011  m_glfcns.glVertex3d (p1+dx, val, p2+dz);
1012  if (mirror)
1013  {
1014  m_glfcns.glVertex3d (p1N, val, p2N);
1015  m_glfcns.glVertex3d (p1N-dx, val, p2N-dz);
1016  }
1017  }
1018  else if (xyz == Z_AXIS)
1019  {
1020  m_glfcns.glVertex3d (p1, p2, val);
1021  m_glfcns.glVertex3d (p1+dx, p2+dy, val);
1022  if (mirror)
1023  {
1024  m_glfcns.glVertex3d (p1N, p2N, val);
1025  m_glfcns.glVertex3d (p1N-dx, p2N-dy, val);
1026  }
1027  }
1028  }
1029  }
1030 
1031  m_glfcns.glEnd ();
1032 
1033 #else
1034 
1035  octave_unused_parameter (ticks);
1036  octave_unused_parameter (lim1);
1037  octave_unused_parameter (lim2);
1038  octave_unused_parameter (p1);
1039  octave_unused_parameter (p1N);
1040  octave_unused_parameter (p2);
1041  octave_unused_parameter (p2N);
1042  octave_unused_parameter (dx);
1043  octave_unused_parameter (dy);
1044  octave_unused_parameter (dz);
1045  octave_unused_parameter (xyz);
1046  octave_unused_parameter (mirror);
1047 
1048  // This shouldn't happen because construction of opengl_renderer
1049  // objects is supposed to be impossible if OpenGL is not available.
1050 
1051  panic_impossible ();
1052 
1053 #endif
1054  }
1055 
1056  void
1058  const string_vector& ticklabels,
1059  double lim1, double lim2,
1060  double p1, double p2,
1061  int xyz, int ha, int va,
1062  int& wmax, int& hmax)
1063  {
1064 #if defined (HAVE_OPENGL)
1065 
1066  int nticks = ticks.numel ();
1067  int nlabels = ticklabels.numel ();
1068 
1069  if (nlabels == 0)
1070  return;
1071 
1072  for (int i = 0; i < nticks; i++)
1073  {
1074  double val = ticks(i);
1075 
1076  if (lim1 <= val && val <= lim2)
1077  {
1078  Matrix b;
1079 
1080  std::string label (ticklabels(i % nlabels));
1081  label.erase (0, label.find_first_not_of (' '));
1082  label = label.substr (0, label.find_last_not_of (' ')+1);
1083 
1084  // FIXME: As tick text is transparent, shouldn't it be
1085  // drawn after axes object, for correct rendering?
1086  if (xyz == X_AXIS)
1087  {
1088  b = render_text (label, val, p1, p2, ha, va);
1089  }
1090  else if (xyz == Y_AXIS)
1091  {
1092  b = render_text (label, p1, val, p2, ha, va);
1093  }
1094  else if (xyz == Z_AXIS)
1095  {
1096  b = render_text (label, p1, p2, val, ha, va);
1097  }
1098 
1099  wmax = std::max (wmax, static_cast<int> (b(2)));
1100  hmax = std::max (hmax, static_cast<int> (b(3)));
1101  }
1102  }
1103 
1104 #else
1105 
1106  octave_unused_parameter (ticks);
1107  octave_unused_parameter (ticklabels);
1108  octave_unused_parameter (lim1);
1109  octave_unused_parameter (lim2);
1110  octave_unused_parameter (p1);
1111  octave_unused_parameter (p2);
1112  octave_unused_parameter (xyz);
1113  octave_unused_parameter (ha);
1114  octave_unused_parameter (va);
1115  octave_unused_parameter (wmax);
1116  octave_unused_parameter (hmax);
1117 
1118  // This shouldn't happen because construction of opengl_renderer
1119  // objects is supposed to be impossible if OpenGL is not available.
1120 
1121  panic_impossible ();
1122 
1123 #endif
1124  }
1125 
1126  void
1127  opengl_renderer::draw_zoom_rect (int x1, int y1, int x2, int y2)
1128  {
1129 #if defined (HAVE_OPENGL)
1130 
1131  m_glfcns.glVertex2d (x1, y1);
1132  m_glfcns.glVertex2d (x2, y1);
1133  m_glfcns.glVertex2d (x2, y2);
1134  m_glfcns.glVertex2d (x1, y2);
1135  m_glfcns.glVertex2d (x1, y1);
1136 
1137 #else
1138 
1139  octave_unused_parameter (x1);
1140  octave_unused_parameter (x2);
1141  octave_unused_parameter (y1);
1142  octave_unused_parameter (y2);
1143 
1144  // This shouldn't happen because construction of opengl_renderer
1145  // objects is supposed to be impossible if OpenGL is not available.
1146 
1147  panic_impossible ();
1148 
1149 #endif
1150  }
1151 
1152  void
1153  opengl_renderer::draw_zoom_box (int width, int height,
1154  int x1, int y1, int x2, int y2,
1155  const Matrix& overlaycolor,
1156  double overlayalpha,
1157  const Matrix& bordercolor,
1158  double borderalpha, double borderwidth)
1159  {
1160 #if defined (HAVE_OPENGL)
1161 
1162  m_glfcns.glMatrixMode (GL_MODELVIEW);
1165 
1166  m_glfcns.glMatrixMode (GL_PROJECTION);
1169  m_glfcns.glOrtho (0, width, height, 0, 1, -1);
1170 
1171  m_glfcns.glPushAttrib (GL_DEPTH_BUFFER_BIT | GL_CURRENT_BIT);
1172  m_glfcns.glDisable (GL_DEPTH_TEST);
1173 
1174  m_glfcns.glBegin (GL_POLYGON);
1175  m_glfcns.glColor4f (overlaycolor(0), overlaycolor(1), overlaycolor(2),
1176  overlayalpha);
1177  draw_zoom_rect (x1, y1, x2, y2);
1178  m_glfcns.glEnd ();
1179 
1180  m_glfcns.glLineWidth (borderwidth);
1181  m_glfcns.glBegin (GL_LINE_STRIP);
1182  m_glfcns.glColor4f (bordercolor(0), bordercolor(1), bordercolor(2),
1183  borderalpha);
1184  draw_zoom_rect (x1, y1, x2, y2);
1185  m_glfcns.glEnd ();
1186 
1187  m_glfcns.glPopAttrib ();
1188 
1189  m_glfcns.glMatrixMode (GL_MODELVIEW);
1190  m_glfcns.glPopMatrix ();
1191 
1192  m_glfcns.glMatrixMode (GL_PROJECTION);
1193  m_glfcns.glPopMatrix ();
1194 
1195 #else
1196 
1197  octave_unused_parameter (width);
1198  octave_unused_parameter (height);
1199  octave_unused_parameter (x1);
1200  octave_unused_parameter (x2);
1201  octave_unused_parameter (y1);
1202  octave_unused_parameter (y2);
1203  octave_unused_parameter (overlaycolor);
1204  octave_unused_parameter (overlayalpha);
1205  octave_unused_parameter (bordercolor);
1206  octave_unused_parameter (borderalpha);
1207  octave_unused_parameter (borderwidth);
1208 
1209  // This shouldn't happen because construction of opengl_renderer
1210  // objects is supposed to be impossible if OpenGL is not available.
1211 
1212  panic_impossible ();
1213 
1214 #endif
1215  }
1216 
1217  uint8NDArray
1218  opengl_renderer::get_pixels (int width, int height)
1219  {
1220 #if defined (HAVE_OPENGL)
1221 
1222  m_glfcns.glPixelStorei (GL_PACK_ALIGNMENT, 1);
1223  uint8NDArray pix(dim_vector (3, width, height), 0);
1224 
1225  m_glfcns.glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE,
1226  pix.fortran_vec ());
1227 
1228  // Permute and flip data
1229  Array<octave_idx_type> perm (dim_vector (3, 1));
1230  perm(0) = 2;
1231  perm(1) = 1;
1232  perm(2) = 0;
1233 
1234  Array<idx_vector> idx (dim_vector (3, 1));
1235  idx(0) = idx_vector::make_range (height - 1, -1, height);
1236  idx(1) = idx_vector::colon;
1237  idx(2) = idx_vector::colon;
1238 
1239  return pix.permute (perm).index (idx);
1240 
1241 #else
1242 
1243  // This shouldn't happen because construction of opengl_renderer
1244  // objects is supposed to be impossible if OpenGL is not available.
1245 
1246  octave_unused_parameter (width);
1247  octave_unused_parameter (height);
1248 
1249  panic_impossible ();
1250 
1251 #endif
1252  }
1253 
1254  void
1256  {
1257 #if defined (HAVE_OPENGL)
1258 
1259  m_glfcns.glFinish ();
1260 
1261 #else
1262 
1263  // This shouldn't happen because construction of opengl_renderer
1264  // objects is supposed to be impossible if OpenGL is not available.
1265 
1266  panic_impossible ();
1267 
1268 #endif
1269  }
1270 
1271  void
1273  {
1274 #if defined (HAVE_OPENGL)
1275 
1276  // setup OpenGL transformation
1277 
1278  Matrix x_zlim = props.get_transform_zlim ();
1279 
1280  xZ1 = std::max (-1e6, x_zlim(0)-(x_zlim(1)-x_zlim(0))*100.0);
1281  xZ2 = std::min (1e6, x_zlim(1)+(x_zlim(1)-x_zlim(0))*100.0);
1282 
1283  Matrix x_mat1 = props.get_opengl_matrix_1 ();
1284  Matrix x_mat2 = props.get_opengl_matrix_2 ();
1285 
1286  m_glfcns.glMatrixMode (GL_MODELVIEW);
1288  m_glfcns.glScaled (1, 1, -1);
1289  m_glfcns.glMultMatrixd (x_mat1.data ());
1290  m_glfcns.glMatrixMode (GL_PROJECTION);
1292 
1293  Matrix vp = get_viewport_scaled ();
1294  m_glfcns.glOrtho (0, vp(2), vp(3), 0, xZ1, xZ2);
1295  m_glfcns.glMultMatrixd (x_mat2.data ());
1296  m_glfcns.glMatrixMode (GL_MODELVIEW);
1297 
1298  m_glfcns.glClear (GL_DEPTH_BUFFER_BIT);
1299 
1300  // store axes transformation data
1301 
1302  xform = props.get_transform ();
1303 
1304 #else
1305 
1306  octave_unused_parameter (props);
1307 
1308  // This shouldn't happen because construction of opengl_renderer
1309  // objects is supposed to be impossible if OpenGL is not available.
1310 
1311  panic_impossible ();
1312 
1313 #endif
1314  }
1315 
1316  void
1318  {
1319 #if defined (HAVE_OPENGL)
1320 
1321  Matrix axe_color = props.get_color_rgb ();
1322  if (axe_color.isempty () || ! props.is_visible ())
1323  return;
1324 
1325  double xPlane = props.get_xPlane ();
1326  double yPlane = props.get_yPlane ();
1327  double zPlane = props.get_zPlane ();
1328  double xPlaneN = props.get_xPlaneN ();
1329  double yPlaneN = props.get_yPlaneN ();
1330  double zPlaneN = props.get_zPlaneN ();
1331  bool is2D = props.get_is2D ();
1332 
1333  // Axes planes
1334  set_color (axe_color);
1335  set_polygon_offset (true, 9.0);
1336 
1337  m_glfcns.glBegin (GL_QUADS);
1338 
1339  if (! is2D)
1340  {
1341  // X plane
1342  m_glfcns.glVertex3d (xPlane, yPlaneN, zPlaneN);
1343  m_glfcns.glVertex3d (xPlane, yPlane, zPlaneN);
1344  m_glfcns.glVertex3d (xPlane, yPlane, zPlane);
1345  m_glfcns.glVertex3d (xPlane, yPlaneN, zPlane);
1346 
1347  // Y plane
1348  m_glfcns.glVertex3d (xPlaneN, yPlane, zPlaneN);
1349  m_glfcns.glVertex3d (xPlane, yPlane, zPlaneN);
1350  m_glfcns.glVertex3d (xPlane, yPlane, zPlane);
1351  m_glfcns.glVertex3d (xPlaneN, yPlane, zPlane);
1352  }
1353 
1354  // Z plane
1355  m_glfcns.glVertex3d (xPlaneN, yPlaneN, zPlane);
1356  m_glfcns.glVertex3d (xPlane, yPlaneN, zPlane);
1357  m_glfcns.glVertex3d (xPlane, yPlane, zPlane);
1358  m_glfcns.glVertex3d (xPlaneN, yPlane, zPlane);
1359 
1360  m_glfcns.glEnd ();
1361 
1362  set_polygon_offset (false);
1363 
1364 #else
1365 
1366  octave_unused_parameter (props);
1367 
1368  // This shouldn't happen because construction of opengl_renderer
1369  // objects is supposed to be impossible if OpenGL is not available.
1370 
1371  panic_impossible ();
1372 
1373 #endif
1374  }
1375 
1376  void
1378  {
1379 #if defined (HAVE_OPENGL)
1380 
1381  if (! props.is_visible ())
1382  return;
1383 
1384  bool xySym = props.get_xySym ();
1385  bool layer2Dtop = props.get_layer2Dtop ();
1386  bool is2D = props.get_is2D ();
1387  bool isXOrigin = props.xaxislocation_is ("origin")
1388  && ! props.yscale_is ("log");
1389  bool isYOrigin = props.yaxislocation_is ("origin")
1390  && ! props.xscale_is ("log");
1391  bool boxFull = (props.get_boxstyle () == "full");
1392  double linewidth = props.get_linewidth ();
1393  double xPlane = props.get_xPlane ();
1394  double yPlane = props.get_yPlane ();
1395  double zPlane = props.get_zPlane ();
1396  double xPlaneN = props.get_xPlaneN ();
1397  double yPlaneN = props.get_yPlaneN ();
1398  double zPlaneN = props.get_zPlaneN ();
1399  double xpTick = props.get_xpTick ();
1400  double ypTick = props.get_ypTick ();
1401  double zpTick = props.get_zpTick ();
1402  double xpTickN = props.get_xpTickN ();
1403  double ypTickN = props.get_ypTickN ();
1404  double zpTickN = props.get_zpTickN ();
1405 
1406  bool plotyy = (props.has_property ("__plotyy_axes__"));
1407 
1408  // Axes box
1409 
1410  set_linecap ("square");
1411  set_linestyle ("-", true, linewidth);
1412 
1413  m_glfcns.glBegin (GL_LINES);
1414 
1415  if (layer2Dtop)
1416  std::swap (zpTick, zpTickN);
1417 
1418  // X box
1419  Matrix color = props.get_xcolor_rgb ();
1420 
1421  if (! color.isempty ())
1422  {
1423  set_color (color);
1424 
1425  if (! isXOrigin || props.is_box() || ! is2D)
1426  {
1427  m_glfcns.glVertex3d (xPlaneN, ypTick, zpTick);
1428  m_glfcns.glVertex3d (xPlane, ypTick, zpTick);
1429  }
1430 
1431  if (props.is_box ())
1432  {
1433  m_glfcns.glVertex3d (xPlaneN, ypTickN, zpTick);
1434  m_glfcns.glVertex3d (xPlane, ypTickN, zpTick);
1435  if (! is2D)
1436  {
1437  m_glfcns.glVertex3d (xPlaneN, ypTickN, zpTickN);
1438  m_glfcns.glVertex3d (xPlane, ypTickN, zpTickN);
1439  if (boxFull)
1440  {
1441  m_glfcns.glVertex3d (xPlaneN, ypTick, zpTickN);
1442  m_glfcns.glVertex3d (xPlane, ypTick, zpTickN);
1443  }
1444  }
1445  }
1446  }
1447 
1448  // Y box
1449  color = props.get_ycolor_rgb ();
1450 
1451  if (! color.isempty ())
1452  {
1453  set_color (color);
1454  if (! isYOrigin || props.is_box() || ! is2D)
1455  {
1456  m_glfcns.glVertex3d (xpTick, yPlaneN, zpTick);
1457  m_glfcns.glVertex3d (xpTick, yPlane, zpTick);
1458  }
1459 
1460  if (props.is_box () && ! plotyy)
1461  {
1462  m_glfcns.glVertex3d (xpTickN, yPlaneN, zpTick);
1463  m_glfcns.glVertex3d (xpTickN, yPlane, zpTick);
1464 
1465  if (! is2D)
1466  {
1467  m_glfcns.glVertex3d (xpTickN, yPlaneN, zpTickN);
1468  m_glfcns.glVertex3d (xpTickN, yPlane, zpTickN);
1469  if (boxFull)
1470  {
1471  m_glfcns.glVertex3d (xpTick, yPlaneN, zpTickN);
1472  m_glfcns.glVertex3d (xpTick, yPlane, zpTickN);
1473  }
1474  }
1475  }
1476  }
1477 
1478  // Z box
1479  color = props.get_zcolor_rgb ();
1480 
1481  if (! color.isempty () && ! is2D)
1482  {
1483  set_color (color);
1484 
1485  if (xySym)
1486  {
1487  m_glfcns.glVertex3d (xPlaneN, yPlane, zPlaneN);
1488  m_glfcns.glVertex3d (xPlaneN, yPlane, zPlane);
1489  }
1490  else
1491  {
1492  m_glfcns.glVertex3d (xPlane, yPlaneN, zPlaneN);
1493  m_glfcns.glVertex3d (xPlane, yPlaneN, zPlane);
1494  }
1495 
1496  if (props.is_box ())
1497  {
1498  m_glfcns.glVertex3d (xPlane, yPlane, zPlaneN);
1499  m_glfcns.glVertex3d (xPlane, yPlane, zPlane);
1500 
1501  if (xySym)
1502  {
1503  m_glfcns.glVertex3d (xPlane, yPlaneN, zPlaneN);
1504  m_glfcns.glVertex3d (xPlane, yPlaneN, zPlane);
1505  }
1506  else
1507  {
1508  m_glfcns.glVertex3d (xPlaneN, yPlane, zPlaneN);
1509  m_glfcns.glVertex3d (xPlaneN, yPlane, zPlane);
1510  }
1511 
1512  if (boxFull)
1513  {
1514  m_glfcns.glVertex3d (xPlaneN, yPlaneN, zPlaneN);
1515  m_glfcns.glVertex3d (xPlaneN, yPlaneN, zPlane);
1516  }
1517  }
1518  }
1519 
1520  m_glfcns.glEnd ();
1521 
1522  set_linestyle ("-"); // Disable LineStipple
1523 
1524 #else
1525 
1526  octave_unused_parameter (props);
1527 
1528  // This shouldn't happen because construction of opengl_renderer
1529  // objects is supposed to be impossible if OpenGL is not available.
1530 
1531  panic_impossible ();
1532 
1533 #endif
1534  }
1535 
1536  void
1538  {
1539 #if defined (HAVE_OPENGL)
1540 
1541  gh_manager& gh_mgr
1542  = __get_gh_manager__ ("opengl_renderer::draw_axes_x_grid");
1543 
1544  int xstate = props.get_xstate ();
1545 
1546  if (xstate != AXE_DEPTH_DIR
1547  && (props.is_visible ()
1548  || (selecting && props.pickableparts_is ("all"))))
1549  {
1550  int zstate = props.get_zstate ();
1551  bool x2Dtop = props.get_x2Dtop ();
1552  bool layer2Dtop = props.get_layer2Dtop ();
1553  bool xyzSym = props.get_xyzSym ();
1554  bool nearhoriz = props.get_nearhoriz ();
1555  double xticklen = props.get_xticklen ();
1556  double xtickoffset = props.get_xtickoffset ();
1557  double fy = props.get_fy ();
1558  double fz = props.get_fz ();
1559  double x_min = props.get_x_min ();
1560  double x_max = props.get_x_max ();
1561  double y_min = props.get_y_min ();
1562  double y_max = props.get_y_max ();
1563  double yPlane = props.get_yPlane ();
1564  double yPlaneN = props.get_yPlaneN ();
1565  double ypTick = props.get_ypTick ();
1566  double ypTickN = props.get_ypTickN ();
1567  double zPlane = props.get_zPlane ();
1568  double zPlaneN = props.get_zPlaneN ();
1569  double zpTick = props.get_zpTick ();
1570  double zpTickN = props.get_zpTickN ();
1571 
1572  // X ticks and grid properties
1573  Matrix xticks = xform.xscale (props.get_xtick ().matrix_value ());
1574  Matrix xmticks = xform.xscale (props.get_xminortickvalues ().matrix_value ());
1575  bool do_xminortick = props.is_xminortick () && ! xticks.isempty ();
1576  string_vector xticklabels = props.get_xticklabel ().string_vector_value ();
1577  int wmax = 0;
1578  int hmax = 0;
1579  bool tick_along_z = nearhoriz || math::isinf (fy);
1580  double linewidth = props.get_linewidth ();
1581  std::string gridstyle = props.get_gridlinestyle ();
1582  std::string minorgridstyle = props.get_minorgridlinestyle ();
1583  Matrix gridcolor = props.get_gridcolor_rgb ();
1584  Matrix minorgridcolor = props.get_minorgridcolor_rgb ();
1585  double gridalpha = props.get_gridalpha ();
1586  double minorgridalpha = props.get_minorgridalpha ();
1587  bool do_xgrid = (props.is_xgrid () && (gridstyle != "none"));
1588  bool do_xminorgrid = (props.is_xminorgrid ()
1589  && (minorgridstyle != "none")
1590  && ! xticks.isempty ());
1591  bool is_origin = props.xaxislocation_is ("origin") && props.get_is2D ()
1592  && ! props.yscale_is ("log");
1593  bool is_origin_low = is_origin && (y_min + y_max) < 0;
1594  bool mirror = props.is_box () && xstate != AXE_ANY_DIR;
1595 
1596  // X grid
1597 
1598  // possibly use axis color for gridcolor & minorgridcolor
1599  if (props.gridcolormode_is ("auto"))
1600  if (props.xcolormode_is ("manual") && ! props.xcolor_is ("none"))
1601  gridcolor = props.get_xcolor_rgb ();
1602 
1603  if (props.minorgridcolormode_is ("auto"))
1604  if (props.xcolormode_is ("manual") && ! props.xcolor_is ("none"))
1605  minorgridcolor = props.get_xcolor_rgb ();
1606 
1607  if (gridcolor.isempty ())
1608  do_xgrid = false;
1609 
1610  if (minorgridcolor.isempty ())
1611  do_xminorgrid = false;
1612 
1613  // set styles when drawing only minor grid
1614  if (do_xminorgrid && ! do_xgrid)
1615  {
1616  gridstyle = minorgridstyle;
1617  gridcolor = minorgridcolor;
1618  gridalpha = minorgridalpha;
1619  do_xgrid = true;
1620  }
1621 
1622  // minor grid lines
1623  if (do_xminorgrid)
1624  render_grid (linewidth,
1625  minorgridstyle, minorgridcolor, minorgridalpha,
1626  xmticks, x_min, x_max,
1627  yPlane, yPlaneN, layer2Dtop ? zPlaneN : zPlane, zPlaneN,
1628  0, (zstate != AXE_DEPTH_DIR));
1629 
1630  // grid lines
1631  if (do_xgrid)
1632  render_grid (linewidth,
1633  gridstyle, gridcolor, gridalpha,
1634  xticks, x_min, x_max,
1635  yPlane, yPlaneN, layer2Dtop ? zPlaneN : zPlane, zPlaneN,
1636  0, (zstate != AXE_DEPTH_DIR));
1637 
1638  // Skip drawing axis, ticks, and ticklabels when color is "none"
1639  if (props.xcolor_is ("none"))
1640  return;
1641 
1642  set_color (props.get_xcolor_rgb ());
1643 
1644  // axis line
1645  double y_axis_pos = 0.;
1646  if (is_origin)
1647  {
1648  y_axis_pos = math::max (math::min (0., y_max), y_min);
1649  m_glfcns.glBegin (GL_LINES);
1650  set_color (props.get_xcolor_rgb ());
1651  m_glfcns.glVertex3d (x_min, y_axis_pos, zpTick);
1652  m_glfcns.glVertex3d (x_max, y_axis_pos, zpTick);
1653  m_glfcns.glEnd ();
1654  }
1655 
1656  // minor tick marks
1657  if (do_xminortick)
1658  {
1659  if (tick_along_z)
1660  render_tickmarks (xmticks, x_min, x_max,
1661  is_origin ? y_axis_pos : ypTick, ypTick,
1662  zpTick, zpTickN, 0., 0.,
1663  (is_origin_low ? -1. : 1.) *
1664  math::signum (zpTick-zpTickN)*fz*xticklen/2,
1665  0, ! is_origin && mirror);
1666  else
1667  render_tickmarks (xmticks, x_min, x_max,
1668  is_origin ? y_axis_pos : ypTick, ypTickN,
1669  zpTick, zpTick, 0.,
1670  (is_origin_low ? -1. : 1.) *
1671  math::signum (ypTick-ypTickN)*fy*xticklen/2,
1672  0., 0, ! is_origin && mirror);
1673  }
1674 
1675  // tick marks
1676  if (tick_along_z)
1677  render_tickmarks (xticks, x_min, x_max,
1678  is_origin ? y_axis_pos : ypTick, ypTick,
1679  zpTick, zpTickN, 0., 0.,
1680  (is_origin_low ? -1. : 1.) *
1681  math::signum (zpTick-zpTickN)*fz*xticklen,
1682  0, ! is_origin && mirror);
1683  else
1684  render_tickmarks (xticks, x_min, x_max,
1685  is_origin ? y_axis_pos : ypTick, ypTickN,
1686  zpTick, zpTick, 0.,
1687  (is_origin_low ? -1. : 1.) *
1688  math::signum (ypTick-ypTickN)*fy*xticklen,
1689  0., 0, ! is_origin && mirror);
1690 
1691  // tick texts
1692  if (xticklabels.numel () > 0)
1693  {
1694  int halign = (xstate == AXE_HORZ_DIR
1695  ? 1
1696  : (xyzSym || is_origin_low ? 0 : 2));
1697  int valign = (xstate == AXE_VERT_DIR
1698  ? 1
1699  : (x2Dtop || is_origin_low ? 0 : 2));
1700 
1701  if (tick_along_z)
1702  render_ticktexts (xticks, xticklabels, x_min, x_max,
1703  is_origin ? y_axis_pos : ypTick,
1704  zpTick +
1705  (is_origin_low ? -1. : 1.) *
1706  math::signum (zpTick-zpTickN)*fz*xtickoffset,
1707  0, halign, valign, wmax, hmax);
1708  else
1709  render_ticktexts (xticks, xticklabels, x_min, x_max,
1710  (is_origin ? y_axis_pos : ypTick) +
1711  (is_origin_low ? -1. : 1.) *
1712  math::signum (ypTick-ypTickN)*fy*xtickoffset,
1713  zpTick, 0, halign, valign, wmax, hmax);
1714  }
1715 
1716  gh_mgr.get_object (props.get_xlabel ()).set ("visible", "on");
1717  }
1718  else
1719  gh_mgr.get_object (props.get_xlabel ()).set ("visible", "off");
1720 
1721 #else
1722 
1723  octave_unused_parameter (props);
1724 
1725  // This shouldn't happen because construction of opengl_renderer
1726  // objects is supposed to be impossible if OpenGL is not available.
1727 
1728  panic_impossible ();
1729 
1730 #endif
1731  }
1732 
1733  void
1735  {
1736 #if defined (HAVE_OPENGL)
1737 
1738  gh_manager& gh_mgr
1739  = __get_gh_manager__ ("opengl_renderer::draw_axes_y_grid");
1740 
1741  int ystate = props.get_ystate ();
1742 
1743  if (ystate != AXE_DEPTH_DIR && props.is_visible ()
1744  && (props.is_visible ()
1745  || (selecting && props.pickableparts_is ("all"))))
1746  {
1747  int zstate = props.get_zstate ();
1748  bool y2Dright = props.get_y2Dright ();
1749  bool layer2Dtop = props.get_layer2Dtop ();
1750  bool xyzSym = props.get_xyzSym ();
1751  bool nearhoriz = props.get_nearhoriz ();
1752  double yticklen = props.get_yticklen ();
1753  double ytickoffset = props.get_ytickoffset ();
1754  double fx = props.get_fx ();
1755  double fz = props.get_fz ();
1756  double xPlane = props.get_xPlane ();
1757  double xPlaneN = props.get_xPlaneN ();
1758  double xpTick = props.get_xpTick ();
1759  double xpTickN = props.get_xpTickN ();
1760  double y_min = props.get_y_min ();
1761  double y_max = props.get_y_max ();
1762  double x_min = props.get_x_min ();
1763  double x_max = props.get_x_max ();
1764  double zPlane = props.get_zPlane ();
1765  double zPlaneN = props.get_zPlaneN ();
1766  double zpTick = props.get_zpTick ();
1767  double zpTickN = props.get_zpTickN ();
1768 
1769  // Y ticks and grid properties
1770  Matrix yticks = xform.yscale (props.get_ytick ().matrix_value ());
1771  Matrix ymticks = xform.yscale (props.get_yminortickvalues ().matrix_value ());
1772  bool do_yminortick = props.is_yminortick () && ! yticks.isempty ();
1773  string_vector yticklabels = props.get_yticklabel ().string_vector_value ();
1774  int wmax = 0;
1775  int hmax = 0;
1776  bool tick_along_z = nearhoriz || math::isinf (fx);
1777  double linewidth = props.get_linewidth ();
1778  std::string gridstyle = props.get_gridlinestyle ();
1779  std::string minorgridstyle = props.get_minorgridlinestyle ();
1780  Matrix gridcolor = props.get_gridcolor_rgb ();
1781  Matrix minorgridcolor = props.get_minorgridcolor_rgb ();
1782  double gridalpha = props.get_gridalpha ();
1783  double minorgridalpha = props.get_minorgridalpha ();
1784  bool do_ygrid = (props.is_ygrid () && (gridstyle != "none"));
1785  bool do_yminorgrid = (props.is_yminorgrid ()
1786  && (minorgridstyle != "none")
1787  && ! yticks.isempty ());
1788  bool is_origin = props.yaxislocation_is ("origin") && props.get_is2D ()
1789  && ! props.xscale_is ("log");
1790  bool is_origin_low = is_origin && (x_min + x_max) < 0;
1791  bool mirror = props.is_box () && ystate != AXE_ANY_DIR
1792  && (! props.has_property ("__plotyy_axes__"));
1793 
1794  // Y grid
1795 
1796  // possibly use axis color for gridcolor & minorgridcolor
1797  if (props.gridcolormode_is ("auto"))
1798  if (props.ycolormode_is ("manual") && ! props.ycolor_is ("none"))
1799  gridcolor = props.get_ycolor_rgb ();
1800 
1801  if (props.minorgridcolormode_is ("auto"))
1802  if (props.ycolormode_is ("manual") && ! props.ycolor_is ("none"))
1803  minorgridcolor = props.get_ycolor_rgb ();
1804 
1805  if (gridcolor.isempty ())
1806  do_ygrid = false;
1807 
1808  if (minorgridcolor.isempty ())
1809  do_yminorgrid = false;
1810 
1811  // set styles when drawing only minor grid
1812  if (do_yminorgrid && ! do_ygrid)
1813  {
1814  gridstyle = minorgridstyle;
1815  gridcolor = minorgridcolor;
1816  gridalpha = minorgridalpha;
1817  do_ygrid = true;
1818  }
1819 
1820  // minor grid lines
1821  if (do_yminorgrid)
1822  render_grid (linewidth,
1823  minorgridstyle, minorgridcolor, minorgridalpha,
1824  ymticks, y_min, y_max,
1825  xPlane, xPlaneN, layer2Dtop ? zPlaneN : zPlane, zPlaneN,
1826  1, (zstate != AXE_DEPTH_DIR));
1827 
1828  // grid lines
1829  if (do_ygrid)
1830  render_grid (linewidth,
1831  gridstyle, gridcolor, gridalpha,
1832  yticks, y_min, y_max,
1833  xPlane, xPlaneN, layer2Dtop ? zPlaneN : zPlane, zPlaneN,
1834  1, (zstate != AXE_DEPTH_DIR));
1835 
1836  // Skip drawing axis, ticks, and ticklabels when color is "none"
1837  if (props.ycolor_is ("none"))
1838  return;
1839 
1840  set_color (props.get_ycolor_rgb ());
1841 
1842  // axis line
1843  double x_axis_pos = 0.;
1844  if (is_origin)
1845  {
1846  x_axis_pos = math::max (math::min (0., x_max), x_min);
1847  m_glfcns.glBegin (GL_LINES);
1848  set_color (props.get_ycolor_rgb ());
1849  m_glfcns.glVertex3d (x_axis_pos, y_min, zpTick);
1850  m_glfcns.glVertex3d (x_axis_pos, y_max, zpTick);
1851  m_glfcns.glEnd ();
1852  }
1853 
1854  // minor tick marks
1855  if (do_yminortick)
1856  {
1857  if (tick_along_z)
1858  render_tickmarks (ymticks, y_min, y_max,
1859  is_origin ? x_axis_pos : xpTick, xpTick,
1860  zpTick, zpTickN, 0., 0.,
1861  (is_origin_low ? -1. : 1.) *
1862  math::signum (zpTick-zpTickN)*fz*yticklen/2,
1863  1, ! is_origin && mirror);
1864  else
1865  render_tickmarks (ymticks, y_min, y_max,
1866  is_origin ? x_axis_pos : xpTick, xpTickN,
1867  zpTick, zpTick,
1868  (is_origin_low ? -1. : 1.) *
1869  math::signum (xpTick-xpTickN)*fx*yticklen/2,
1870  0., 0., 1, ! is_origin && mirror);
1871  }
1872 
1873  // tick marks
1874  if (tick_along_z)
1875  render_tickmarks (yticks, y_min, y_max,
1876  is_origin ? x_axis_pos : xpTick, xpTick,
1877  zpTick, zpTickN, 0., 0.,
1878  (is_origin_low ? -1. : 1.) *
1879  math::signum (zpTick-zpTickN)*fz*yticklen,
1880  1, ! is_origin && mirror);
1881  else
1882  render_tickmarks (yticks, y_min, y_max,
1883  is_origin ? x_axis_pos : xpTick, xpTickN,
1884  zpTick, zpTick,
1885  (is_origin_low ? -1. : 1.) *
1886  math::signum (xPlaneN-xPlane)*fx*yticklen,
1887  0., 0., 1, ! is_origin && mirror);
1888 
1889  // tick texts
1890  if (yticklabels.numel () > 0)
1891  {
1892  int halign = (ystate == AXE_HORZ_DIR
1893  ? 1
1894  : (! xyzSym || y2Dright || is_origin_low ? 0 : 2));
1895  int valign = (ystate == AXE_VERT_DIR
1896  ? 1
1897  : (is_origin_low ? 0 : 2));
1898 
1899  if (tick_along_z)
1900  render_ticktexts (yticks, yticklabels, y_min, y_max,
1901  is_origin ? x_axis_pos : xpTick,
1902  zpTick +
1903  (is_origin_low ? -1. : 1.) *
1904  math::signum (zpTick-zpTickN)*fz*ytickoffset,
1905  1, halign, valign, wmax, hmax);
1906  else
1907  render_ticktexts (yticks, yticklabels, y_min, y_max,
1908  (is_origin ? x_axis_pos : xpTick) +
1909  (is_origin_low ? -1. : 1.) *
1910  math::signum (xpTick-xpTickN)*fx*ytickoffset,
1911  zpTick, 1, halign, valign, wmax, hmax);
1912  }
1913 
1914  gh_mgr.get_object (props.get_ylabel ()).set ("visible", "on");
1915  }
1916  else
1917  gh_mgr.get_object (props.get_ylabel ()).set ("visible", "off");
1918 
1919 #else
1920 
1921  octave_unused_parameter (props);
1922 
1923  // This shouldn't happen because construction of opengl_renderer
1924  // objects is supposed to be impossible if OpenGL is not available.
1925 
1926  panic_impossible ();
1927 
1928 #endif
1929  }
1930 
1931  void
1933  {
1934  gh_manager& gh_mgr
1935  = __get_gh_manager__ ("opengl_renderer::draw_axes_z_grid");
1936 
1937  int zstate = props.get_zstate ();
1938 
1939  if (zstate != AXE_DEPTH_DIR && props.is_visible ()
1940  && (props.is_visible ()
1941  || (selecting && props.pickableparts_is ("all"))))
1942  {
1943  bool xySym = props.get_xySym ();
1944  bool zSign = props.get_zSign ();
1945  double zticklen = props.get_zticklen ();
1946  double ztickoffset = props.get_ztickoffset ();
1947  double fx = props.get_fx ();
1948  double fy = props.get_fy ();
1949  double xPlane = props.get_xPlane ();
1950  double xPlaneN = props.get_xPlaneN ();
1951  double yPlane = props.get_yPlane ();
1952  double yPlaneN = props.get_yPlaneN ();
1953  double z_min = props.get_z_min ();
1954  double z_max = props.get_z_max ();
1955 
1956  // Z ticks and grid properties
1957  Matrix zticks = xform.zscale (props.get_ztick ().matrix_value ());
1958  Matrix zmticks = xform.zscale (props.get_zminortickvalues ().matrix_value ());
1959  bool do_zminortick = props.is_zminortick () && ! zticks.isempty ();
1960  string_vector zticklabels = props.get_zticklabel ().string_vector_value ();
1961  int wmax = 0;
1962  int hmax = 0;
1963  double linewidth = props.get_linewidth ();
1964  std::string gridstyle = props.get_gridlinestyle ();
1965  std::string minorgridstyle = props.get_minorgridlinestyle ();
1966  Matrix gridcolor = props.get_gridcolor_rgb ();
1967  Matrix minorgridcolor = props.get_minorgridcolor_rgb ();
1968  double gridalpha = props.get_gridalpha ();
1969  double minorgridalpha = props.get_minorgridalpha ();
1970  bool do_zgrid = (props.is_zgrid () && (gridstyle != "none"));
1971  bool do_zminorgrid = (props.is_zminorgrid ()
1972  && (minorgridstyle != "none")
1973  && ! zticks.isempty ());
1974  bool mirror = props.is_box () && zstate != AXE_ANY_DIR;
1975 
1976  // Z grid
1977 
1978  // possibly use axis color for gridcolor & minorgridcolor
1979  if (props.gridcolormode_is ("auto"))
1980  if (props.zcolormode_is ("manual") && ! props.zcolor_is ("none"))
1981  gridcolor = props.get_zcolor_rgb ();
1982 
1983  if (props.minorgridcolormode_is ("auto"))
1984  if (props.zcolormode_is ("manual") && ! props.zcolor_is ("none"))
1985  minorgridcolor = props.get_zcolor_rgb ();
1986 
1987  if (gridcolor.isempty ())
1988  do_zgrid = false;
1989 
1990  if (minorgridcolor.isempty ())
1991  do_zminorgrid = false;
1992 
1993  // set styles when drawing only minor grid
1994  if (do_zminorgrid && ! do_zgrid)
1995  {
1996  gridstyle = minorgridstyle;
1997  gridcolor = minorgridcolor;
1998  gridalpha = minorgridalpha;
1999  do_zgrid = true;
2000  }
2001 
2002  // minor grid lines
2003  if (do_zminorgrid)
2004  render_grid (linewidth,
2005  minorgridstyle, minorgridcolor, minorgridalpha,
2006  zmticks, z_min, z_max,
2007  xPlane, xPlaneN, yPlane, yPlaneN, 2, true);
2008 
2009  // grid lines
2010  if (do_zgrid)
2011  render_grid (linewidth,
2012  gridstyle, gridcolor, gridalpha,
2013  zticks, z_min, z_max,
2014  xPlane, xPlaneN, yPlane, yPlaneN, 2, true);
2015 
2016  // Skip drawing axis, ticks, and ticklabels when color is "none"
2017  if (props.zcolor_is ("none"))
2018  return;
2019 
2020  set_color (props.get_zcolor_rgb ());
2021 
2022  // minor tick marks
2023  if (do_zminortick)
2024  {
2025  if (xySym)
2026  {
2027  if (math::isinf (fy))
2028  render_tickmarks (zmticks, z_min, z_max, xPlaneN, xPlane,
2029  yPlane, yPlane,
2030  math::signum (xPlaneN-xPlane)*fx*zticklen/2,
2031  0., 0., 2, mirror);
2032  else
2033  render_tickmarks (zmticks, z_min, z_max, xPlaneN, xPlaneN,
2034  yPlane, yPlane, 0.,
2035  math::signum (yPlane-yPlaneN)*fy*zticklen/2,
2036  0., 2, false);
2037  }
2038  else
2039  {
2040  if (math::isinf (fx))
2041  render_tickmarks (zmticks, z_min, z_max, xPlane, xPlane,
2042  yPlaneN, yPlane, 0.,
2043  math::signum (yPlaneN-yPlane)*fy*zticklen/2,
2044  0., 2, mirror);
2045  else
2046  render_tickmarks (zmticks, z_min, z_max, xPlane, xPlane,
2047  yPlaneN, yPlaneN,
2048  math::signum (xPlane-xPlaneN)*fx*zticklen/2,
2049  0., 0., 2, false);
2050  }
2051  }
2052 
2053  // tick marks
2054  if (xySym)
2055  {
2056  if (math::isinf (fy))
2057  render_tickmarks (zticks, z_min, z_max, xPlaneN, xPlane,
2058  yPlane, yPlane,
2059  math::signum (xPlaneN-xPlane)*fx*zticklen,
2060  0., 0., 2, mirror);
2061  else
2062  render_tickmarks (zticks, z_min, z_max, xPlaneN, xPlaneN,
2063  yPlane, yPlane, 0.,
2064  math::signum (yPlane-yPlaneN)*fy*zticklen,
2065  0., 2, false);
2066  }
2067  else
2068  {
2069  if (math::isinf (fx))
2070  render_tickmarks (zticks, z_min, z_max, xPlaneN, xPlane,
2071  yPlaneN, yPlane, 0.,
2072  math::signum (yPlaneN-yPlane)*fy*zticklen,
2073  0., 2, mirror);
2074  else
2075  render_tickmarks (zticks, z_min, z_max, xPlane, xPlane,
2076  yPlaneN, yPlane,
2077  math::signum (xPlane-xPlaneN)*fx*zticklen,
2078  0., 0., 2, false);
2079  }
2080 
2081  // tick texts
2082  if (zticklabels.numel () > 0)
2083  {
2084  int halign = 2;
2085  int valign = (zstate == AXE_VERT_DIR ? 1 : (zSign ? 3 : 2));
2086 
2087  if (xySym)
2088  {
2089  if (math::isinf (fy))
2090  render_ticktexts (zticks, zticklabels, z_min, z_max,
2091  xPlaneN + math::signum (xPlaneN-xPlane)*fx*ztickoffset,
2092  yPlane, 2, halign, valign, wmax, hmax);
2093  else
2094  render_ticktexts (zticks, zticklabels, z_min, z_max, xPlaneN,
2095  yPlane + math::signum (yPlane-yPlaneN)*fy*ztickoffset,
2096  2, halign, valign, wmax, hmax);
2097  }
2098  else
2099  {
2100  if (math::isinf (fx))
2101  render_ticktexts (zticks, zticklabels, z_min, z_max, xPlane,
2102  yPlaneN + math::signum (yPlaneN-yPlane)*fy*ztickoffset,
2103  2, halign, valign, wmax, hmax);
2104  else
2105  render_ticktexts (zticks, zticklabels, z_min, z_max,
2106  xPlane + math::signum (xPlane-xPlaneN)*fx*ztickoffset,
2107  yPlaneN, 2, halign, valign, wmax, hmax);
2108  }
2109  }
2110 
2111  gh_mgr.get_object (props.get_zlabel ()).set ("visible", "on");
2112  }
2113  else
2114  gh_mgr.get_object (props.get_zlabel ()).set ("visible", "off");
2115  }
2116 
2117  void
2119  {
2120 #if defined (HAVE_OPENGL)
2121  // Disable line smoothing for axes
2122  GLboolean antialias;
2123 
2124  m_glfcns.glGetBooleanv (GL_LINE_SMOOTH, &antialias);
2125 
2126  if (antialias == GL_TRUE)
2127  m_glfcns.glDisable (GL_LINE_SMOOTH);
2128 
2129  set_linecap ("butt");
2130  set_linewidth (props.get_linewidth ());
2131  set_font (props);
2132  set_interpreter (props.get_ticklabelinterpreter ());
2133 
2134  draw_axes_x_grid (props);
2135  draw_axes_y_grid (props);
2136  draw_axes_z_grid (props);
2137 
2138  if (antialias == GL_TRUE)
2139  m_glfcns.glEnable (GL_LINE_SMOOTH);
2140 #else
2141 
2142  octave_unused_parameter (props);
2143 
2144  // This shouldn't happen because construction of opengl_renderer
2145  // objects is supposed to be impossible if OpenGL is not available.
2146 
2147  panic_impossible ();
2148 
2149 #endif
2150  }
2151 
2152  void
2154  std::list<graphics_object>& obj_list)
2155  {
2156 #if defined (HAVE_OPENGL)
2157  gh_manager& gh_mgr
2158  = __get_gh_manager__ ("opengl_renderer::draw_axes_all_lights");
2159 
2160  Matrix children = props.get_all_children ();
2161 
2162  for (octave_idx_type i = children.numel () - 1; i >= 0; i--)
2163  {
2164  graphics_object go = gh_mgr.get_object (children(i));
2165 
2166  base_properties p = go.get_properties ();
2167 
2168  if (p.is_visible ()
2169  || (selecting && p.pickableparts_is ("all")))
2170  {
2171  if (go.isa ("light") && ! selecting)
2172  {
2173  if (m_current_light-GL_LIGHT0 < m_max_lights)
2174  {
2175  set_clipping (p.is_clipping ());
2176  draw (go);
2177  m_current_light++;
2178  }
2179  }
2180  else if (go.isa ("hggroup")
2181  && ! (selecting && p.pickableparts_is ("none")))
2182  draw_all_lights (go.get_properties (), obj_list);
2183  else if (! (selecting && p.pickableparts_is ("none")))
2184  obj_list.push_back (go);
2185  }
2186  }
2187 #else
2188 
2189  octave_unused_parameter (props);
2190  octave_unused_parameter (obj_list);
2191 
2192  // This shouldn't happen because construction of opengl_renderer
2193  // objects is supposed to be impossible if OpenGL is not available.
2194 
2195  panic_impossible ();
2196 
2197 #endif
2198  }
2199 
2200  void
2202  {
2203 #if defined (HAVE_OPENGL)
2204  // list for non-light child objects
2205  std::list<graphics_object> obj_list;
2206  std::list<graphics_object>::iterator it;
2207 
2208  // 1st pass: draw light objects
2209 
2210  // FIXME: max_lights only needs to be set once.
2211  // It would be better if this could be in the constructor for gl_renderer
2212  // but this seems to lead to calls of OpenGL functions before the context
2213  // is actually initialized. See bug #48669.
2214  // Check actual maximum number of lights possible
2215  init_maxlights ();
2216 
2217  // Start with the last element of the array of child objects to
2218  // display them in the order they were added to the array.
2219 
2220  if (props.get_num_lights () > m_max_lights)
2221  warning_with_id ("Octave:max-lights-exceeded",
2222  "light: Maximum number of lights (%d) in these axes is "
2223  "exceeded.", m_max_lights);
2224 
2225  m_current_light = GL_LIGHT0;
2226  draw_all_lights (props, obj_list);
2227 
2228  // disable other OpenGL lights
2229  for (unsigned int i = props.get_num_lights (); i < m_max_lights; i++)
2230  m_glfcns.glDisable (GL_LIGHT0 + i);
2231 
2232  // save camera position and set ambient light color before drawing
2233  // other objects
2234  view_vector = props.get_cameraposition ().matrix_value ();
2235 
2236  float cb[4] = { 1.0, 1.0, 1.0, 1.0 };
2237  ColumnVector ambient_color = props.get_ambientlightcolor_rgb ();
2238  for (int i = 0; i < 3; i++)
2239  cb[i] = ambient_color(i);
2240  m_glfcns.glLightfv (GL_LIGHT0, GL_AMBIENT, cb);
2241 
2242  // 2nd pass: draw other objects (with units set to "data")
2243 
2244  it = obj_list.begin ();
2245  while (it != obj_list.end ())
2246  {
2247  graphics_object go = (*it);
2248 
2249  // FIXME: check whether object has "units" property and it is set
2250  // to "data"
2251  if (! go.isa ("text") || go.get ("units").string_value () == "data")
2252  {
2253  set_clipping (go.get_properties ().is_clipping ());
2254  draw (go);
2255 
2256  it = obj_list.erase (it);
2257  }
2258  else
2259  it++;
2260  }
2261 
2262  // 3rd pass: draw remaining objects
2263 
2264  m_glfcns.glDisable (GL_DEPTH_TEST);
2265 
2266  for (it = obj_list.begin (); it != obj_list.end (); it++)
2267  {
2268  graphics_object go = (*it);
2269 
2270  set_clipping (go.get_properties ().is_clipping ());
2271  draw (go);
2272  }
2273 
2274  set_clipping (false);
2275 
2276  // FIXME: finalize rendering (transparency processing)
2277  // FIXME: draw zoom box, if needed
2278 
2279 #else
2280 
2281  octave_unused_parameter (props);
2282 
2283  // This shouldn't happen because construction of opengl_renderer
2284  // objects is supposed to be impossible if OpenGL is not available.
2285 
2286  panic_impossible ();
2287 
2288 #endif
2289  }
2290 
2291  void
2293  {
2294 #if defined (HAVE_OPENGL)
2295 
2296  // Legends are not drawn when "visible" is "off".
2297  if (! props.is_visible () && props.get_tag () == "legend")
2298  return;
2299 
2300  // Don't draw the axes and its children if we are in selection and
2301  // pickable parts is "none".
2302  if (selecting && props.pickableparts_is ("none"))
2303  return;
2304 
2305  static double floatmax = std::numeric_limits<float>::max ();
2306 
2307  double x_min = props.get_x_min ();
2308  double x_max = props.get_x_max ();
2309  double y_min = props.get_y_min ();
2310  double y_max = props.get_y_max ();
2311  double z_min = props.get_z_min ();
2312  double z_max = props.get_z_max ();
2313 
2314  if (x_max > floatmax || y_max > floatmax || z_max > floatmax
2315  || x_min < -floatmax || y_min < -floatmax || z_min < -floatmax)
2316  {
2317  warning ("opengl_renderer: data values greater than float capacity. (1) Scale data, or (2) Use gnuplot");
2318  return;
2319  }
2320 
2322 
2323  // For 2D axes with only 2D primitives, draw from back to front without
2324  // depth sorting
2325  bool is2D = props.get_is2D (true);
2326  if (is2D)
2327  m_glfcns.glDisable (GL_DEPTH_TEST);
2328  else
2329  m_glfcns.glEnable (GL_DEPTH_TEST);
2330 
2331  draw_axes_planes (props);
2332 
2333  if (! is2D || props.layer_is ("bottom"))
2334  {
2335  draw_axes_grids (props);
2336  if (props.get_tag () != "legend" || props.get_box () != "off")
2337  draw_axes_boxes (props);
2338  }
2339 
2340  set_clipbox (x_min, x_max, y_min, y_max, z_min, z_max);
2341 
2342  draw_axes_children (props);
2343 
2344  if (is2D && props.layer_is ("top"))
2345  {
2346  draw_axes_grids (props);
2347  if (props.get_tag () != "legend" || props.get_box () != "off")
2348  draw_axes_boxes (props);
2349  }
2350 
2351 #else
2352 
2353  octave_unused_parameter (props);
2354 
2355  // This shouldn't happen because construction of opengl_renderer
2356  // objects is supposed to be impossible if OpenGL is not available.
2357 
2358  panic_impossible ();
2359 
2360 #endif
2361  }
2362 
2363  void
2365  {
2366 #if defined (HAVE_OPENGL)
2367 
2368  bool draw_all = selecting && props.pickableparts_is ("all");
2369 
2370  Matrix x = xform.xscale (props.get_xdata ().matrix_value ());
2371  Matrix y = xform.yscale (props.get_ydata ().matrix_value ());
2372  Matrix z = xform.zscale (props.get_zdata ().matrix_value ());
2373 
2374  bool has_z = (z.numel () > 0);
2375  int n = static_cast<int> (std::min (std::min (x.numel (), y.numel ()),
2376  (has_z ? z.numel ()
2378  uint8_t clip_mask = (props.is_clipping () ? 0x7F : 0x40);
2379  uint8_t clip_ok = 0x40;
2380 
2381  std::vector<uint8_t> clip (n);
2382 
2383  if (has_z)
2384  for (int i = 0; i < n; i++)
2385  clip[i] = (clip_code (x(i), y(i), z(i)) & clip_mask);
2386  else
2387  {
2388  double z_mid = (zmin+zmax)/2;
2389 
2390  for (int i = 0; i < n; i++)
2391  clip[i] = (clip_code (x(i), y(i), z_mid) & clip_mask);
2392  }
2393 
2394  if (! props.linestyle_is ("none") && ! props.color_is ("none"))
2395  {
2396  set_color (props.get_color_rgb ());
2397  set_linestyle (props.get_linestyle (), false, props.get_linewidth ());
2398  set_linewidth (props.get_linewidth ());
2399  set_linecap ("butt");
2400  set_linejoin (props.get_linejoin ());
2401 
2402  if (has_z)
2403  {
2404  bool flag = false;
2405 
2406  for (int i = 1; i < n; i++)
2407  {
2408  if ((clip[i-1] & clip[i]) == clip_ok)
2409  {
2410  if (! flag)
2411  {
2412  flag = true;
2413  m_glfcns.glBegin (GL_LINE_STRIP);
2414  m_glfcns.glVertex3d (x(i-1), y(i-1), z(i-1));
2415  }
2416  m_glfcns.glVertex3d (x(i), y(i), z(i));
2417  }
2418  else if (flag)
2419  {
2420  flag = false;
2421  m_glfcns.glEnd ();
2422  }
2423  }
2424 
2425  if (flag)
2426  m_glfcns.glEnd ();
2427  }
2428  else
2429  {
2430  bool flag = false;
2431 
2432  for (int i = 1; i < n; i++)
2433  {
2434  if ((clip[i-1] & clip[i]) == clip_ok)
2435  {
2436  if (! flag)
2437  {
2438  flag = true;
2439  m_glfcns.glBegin (GL_LINE_STRIP);
2440  m_glfcns.glVertex2d (x(i-1), y(i-1));
2441  }
2442  m_glfcns.glVertex2d (x(i), y(i));
2443  }
2444  else if (flag)
2445  {
2446  flag = false;
2447  m_glfcns.glEnd ();
2448  }
2449  }
2450 
2451  if (flag)
2452  m_glfcns.glEnd ();
2453  }
2454 
2455  set_linewidth (0.5f);
2456  set_linestyle ("-");
2457  }
2458 
2459  set_clipping (false);
2460 
2461  if (! props.marker_is ("none")
2462  && ! (props.markeredgecolor_is ("none")
2463  && props.markerfacecolor_is ("none")))
2464  {
2465  Matrix lc, fc;
2466 
2467  if (draw_all)
2468  lc = Matrix (1, 3, 0.0);
2469  else if (props.markeredgecolor_is ("auto"))
2470  lc = props.get_color_rgb ();
2471  else if (! props.markeredgecolor_is ("none"))
2472  lc = props.get_markeredgecolor_rgb ();
2473 
2474  if (draw_all)
2475  fc = Matrix (1, 3, 0.0);
2476  if (props.markerfacecolor_is ("auto"))
2477  fc = props.get_color_rgb ();
2478  else if (! props.markerfacecolor_is ("none"))
2479  fc = props.get_markerfacecolor_rgb ();
2480 
2481  init_marker (props.get_marker (), props.get_markersize (),
2482  props.get_linewidth ());
2483 
2484  for (int i = 0; i < n; i++)
2485  {
2486  if (clip[i] == clip_ok)
2487  draw_marker (x(i), y(i),
2488  has_z ? z(i) : 0.0,
2489  lc, fc);
2490  }
2491 
2492  end_marker ();
2493  }
2494 
2495  set_clipping (props.is_clipping ());
2496 
2497 #else
2498 
2499  octave_unused_parameter (props);
2500 
2501  // This shouldn't happen because construction of opengl_renderer
2502  // objects is supposed to be impossible if OpenGL is not available.
2503 
2504  panic_impossible ();
2505 
2506 #endif
2507  }
2508 
2509  void
2511  {
2512 #if defined (HAVE_OPENGL)
2513 
2514  bool draw_all = selecting && props.pickableparts_is ("all");
2515 
2516  const Matrix x = xform.xscale (props.get_xdata ().matrix_value ());
2517  const Matrix y = xform.yscale (props.get_ydata ().matrix_value ());
2518  const Matrix z = xform.zscale (props.get_zdata ().matrix_value ());
2519 
2520  int zr = z.rows ();
2521  int zc = z.columns ();
2522 
2523  NDArray c;
2524  const NDArray vn = props.get_vertexnormals ().array_value ();
2525  dim_vector vn_dims = vn.dims ();
2526  bool has_vertex_normals = (vn_dims(0) == zr && vn_dims(1) == zc
2527  && vn_dims(2) == 3);
2528  const NDArray fn = props.get_facenormals ().array_value ();
2529  dim_vector fn_dims = fn.dims ();
2530  bool has_face_normals = (fn_dims(0) == zr - 1 && fn_dims(1) == zc - 1
2531  && fn_dims(2) == 3);
2532 
2533  // FIXME: handle transparency
2534  Matrix a;
2535 
2536  int fc_mode = (props.facecolor_is_rgb () ? 0 :
2537  (props.facecolor_is ("flat") ? 1 :
2538  (props.facecolor_is ("interp") ? 2 :
2539  (props.facecolor_is ("texturemap") ? 3 : -1))));
2540  int fl_mode = (props.facelighting_is ("none") ? 0 :
2541  (props.facelighting_is ("flat") ?
2542  (has_face_normals ? 1 : 0) :
2543  (has_vertex_normals ? 2 : 0)));
2544  int fa_mode = (props.facealpha_is_double () ? 0 :
2545  (props.facealpha_is ("flat") ? 1 : 2));
2546  int ec_mode = (props.edgecolor_is_rgb () ? 0 :
2547  (props.edgecolor_is ("flat") ? 1 :
2548  (props.edgecolor_is ("interp") ? 2 : -1)));
2549  int el_mode = (props.edgelighting_is ("none") ? 0 :
2550  (props.edgelighting_is ("flat") ?
2551  (has_face_normals ? 1 : 0) :
2552  (has_vertex_normals ? 2 : 0)));
2553  int ea_mode = (props.edgealpha_is_double () ? 0 :
2554  (props.edgealpha_is ("flat") ? 1 : 2));
2555  int bfl_mode = (props.backfacelighting_is ("lit") ? 0 :
2556  (props.backfacelighting_is ("reverselit") ? 1 : 2));
2557  bool do_lighting = props.get_do_lighting ();
2558 
2559  Matrix fcolor = (fc_mode == TEXTURE ? Matrix (1, 3, 1.0)
2560  : props.get_facecolor_rgb ());
2561  Matrix ecolor = props.get_edgecolor_rgb ();
2562  double fa = 1.0;
2563 
2564  float as = props.get_ambientstrength ();
2565  float ds = props.get_diffusestrength ();
2566  float ss = props.get_specularstrength ();
2567  float se = props.get_specularexponent () * 5; // to fit Matlab
2568  float scr = props.get_specularcolorreflectance ();
2569  float cb[4] = { 0.0, 0.0, 0.0, 1.0 };
2570 
2571  opengl_texture tex (m_glfcns);
2572 
2573  int i1, i2, j1, j2;
2574  bool x_mat = (x.rows () == z.rows ());
2575  bool y_mat = (y.columns () == z.columns ());
2576 
2577  i1 = i2 = j1 = j2 = 0;
2578 
2579  if ((fc_mode > 0 && fc_mode < 3) || ec_mode > 0)
2580  c = props.get_color_data ().array_value ();
2581 
2582  boolMatrix clip (z.dims (), false);
2583 
2584  for (int i = 0; i < zr; i++)
2585  {
2586  if (x_mat)
2587  i1 = i;
2588 
2589  for (int j = 0; j < zc; j++)
2590  {
2591  if (y_mat)
2592  j1 = j;
2593 
2594  clip(i,j) = is_nan_or_inf (x(i1,j), y(i,j1), z(i,j));
2595  }
2596  }
2597 
2598  if (fa_mode > 0 || ea_mode > 0)
2599  {
2600  // FIXME: implement alphadata conversion
2601  //a = props.get_alpha_data ();
2602  }
2603 
2604  if (fl_mode > 0 || el_mode > 0)
2605  m_glfcns.glMaterialf (LIGHT_MODE, GL_SHININESS, se);
2606 
2607  // FIXME: good candidate for caching,
2608  // transferring pixel data to OpenGL is time consuming.
2609  if (fc_mode == TEXTURE)
2611 
2612  if (draw_all || ! props.facecolor_is ("none"))
2613  {
2614  if (fa_mode == 0)
2615  {
2616  fa = props.get_facealpha_double ();
2617  cb[3] = fa;
2618  if (fc_mode == UNIFORM || fc_mode == TEXTURE)
2619  {
2620  m_glfcns.glColor4d (fcolor(0), fcolor(1), fcolor(2), fa);
2621  if (fl_mode > 0)
2622  {
2623  for (int i = 0; i < 3; i++)
2624  cb[i] = as * fcolor(i);
2625  m_glfcns.glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
2626 
2627  for (int i = 0; i < 3; i++)
2628  cb[i] = ds * fcolor(i);
2629  m_glfcns.glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
2630 
2631  for (int i = 0; i < 3; i++)
2632  cb[i] = ss * (scr + (1-scr) * fcolor(i));
2633  m_glfcns.glMaterialfv (LIGHT_MODE, GL_SPECULAR, cb);
2634  }
2635  }
2636 
2637  if ((fl_mode > 0) && do_lighting)
2638  m_glfcns.glEnable (GL_LIGHTING);
2639  m_glfcns.glShadeModel ((fc_mode == INTERP || fl_mode == GOURAUD)
2640  ? GL_SMOOTH : GL_FLAT);
2641  set_polygon_offset (true, 1.0);
2642  if (fc_mode == TEXTURE)
2643  m_glfcns.glEnable (GL_TEXTURE_2D);
2644 
2645  for (int i = 1; i < zc; i++)
2646  {
2647  if (y_mat)
2648  {
2649  i1 = i-1;
2650  i2 = i;
2651  }
2652 
2653  for (int j = 1; j < zr; j++)
2654  {
2655 
2656  if (clip(j-1, i-1) || clip(j, i-1)
2657  || clip(j-1, i) || clip(j, i))
2658  continue;
2659 
2660  if (fc_mode == FLAT)
2661  {
2662  // "flat" only needs color at lower-left vertex
2663  if (! math::isfinite (c(j-1,i-1)))
2664  continue;
2665  }
2666  else if (fc_mode == INTERP)
2667  {
2668  // "interp" needs valid color at all 4 vertices
2669  if (! (math::isfinite (c(j-1, i-1)) && math::isfinite (c(j, i-1))
2670  && math::isfinite (c(j-1, i)) && math::isfinite (c(j, i))))
2671  continue;
2672  }
2673 
2674  if (x_mat)
2675  {
2676  j1 = j-1;
2677  j2 = j;
2678  }
2679 
2680  m_glfcns.glBegin (GL_QUADS);
2681 
2682  // Vertex 1
2683  if (fc_mode == TEXTURE)
2684  tex.tex_coord (double (i-1) / (zc-1),
2685  double (j-1) / (zr-1));
2686  else if (fc_mode > 0)
2687  {
2688  // FIXME: is there a smarter way to do this?
2689  for (int k = 0; k < 3; k++)
2690  cb[k] = c(j-1, i-1, k);
2691  m_glfcns.glColor4fv (cb);
2692 
2693  if (fl_mode > 0)
2694  {
2695  for (int k = 0; k < 3; k++)
2696  cb[k] *= as;
2697  m_glfcns.glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
2698 
2699  for (int k = 0; k < 3; k++)
2700  cb[k] = ds * c(j-1, i-1, k);
2701  m_glfcns.glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
2702 
2703  for (int k = 0; k < 3; k++)
2704  cb[k] = ss * (scr + (1-scr) * c(j-1, i-1, k));
2705  m_glfcns.glMaterialfv (LIGHT_MODE, GL_SPECULAR, cb);
2706  }
2707  }
2708  if (fl_mode > 0)
2709  set_normal (bfl_mode, (fl_mode == GOURAUD ? vn : fn),
2710  j-1, i-1);
2711 
2712  m_glfcns.glVertex3d (x(j1,i-1), y(j-1,i1), z(j-1,i-1));
2713 
2714  // Vertex 2
2715  if (fc_mode == TEXTURE)
2716  tex.tex_coord (double (i) / (zc-1), double (j-1) / (zr-1));
2717  else if (fc_mode == INTERP)
2718  {
2719  for (int k = 0; k < 3; k++)
2720  cb[k] = c(j-1, i, k);
2721  m_glfcns.glColor4fv (cb);
2722 
2723  if (fl_mode > 0)
2724  {
2725  for (int k = 0; k < 3; k++)
2726  cb[k] *= as;
2727  m_glfcns.glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
2728 
2729  for (int k = 0; k < 3; k++)
2730  cb[k] = ds * c(j-1, i, k);
2731  m_glfcns.glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
2732 
2733  for (int k = 0; k < 3; k++)
2734  cb[k] = ss * (scr + (1-scr) * c(j-1, i, k));
2735  m_glfcns.glMaterialfv (LIGHT_MODE, GL_SPECULAR, cb);
2736  }
2737  }
2738 
2739  if (fl_mode == GOURAUD)
2740  set_normal (bfl_mode, vn, j-1, i);
2741 
2742  m_glfcns.glVertex3d (x(j1,i), y(j-1,i2), z(j-1,i));
2743 
2744  // Vertex 3
2745  if (fc_mode == TEXTURE)
2746  tex.tex_coord (double (i) / (zc-1), double (j) / (zr-1));
2747  else if (fc_mode == INTERP)
2748  {
2749  for (int k = 0; k < 3; k++)
2750  cb[k] = c(j, i, k);
2751  m_glfcns.glColor4fv (cb);
2752 
2753  if (fl_mode > 0)
2754  {
2755  for (int k = 0; k < 3; k++)
2756  cb[k] *= as;
2757  m_glfcns.glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
2758 
2759  for (int k = 0; k < 3; k++)
2760  cb[k] = ds * c(j, i, k);
2761  m_glfcns.glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
2762 
2763  for (int k = 0; k < 3; k++)
2764  cb[k] = ss * (scr + (1-scr) * c(j, i, k));
2765  m_glfcns.glMaterialfv (LIGHT_MODE, GL_SPECULAR, cb);
2766  }
2767  }
2768  if (fl_mode == GOURAUD)
2769  set_normal (bfl_mode, vn, j, i);
2770 
2771  m_glfcns.glVertex3d (x(j2,i), y(j,i2), z(j,i));
2772 
2773  // Vertex 4
2774  if (fc_mode == TEXTURE)
2775  tex.tex_coord (double (i-1) / (zc-1), double (j) / (zr-1));
2776  else if (fc_mode == INTERP)
2777  {
2778  for (int k = 0; k < 3; k++)
2779  cb[k] = c(j, i-1, k);
2780  m_glfcns.glColor4fv (cb);
2781 
2782  if (fl_mode > 0)
2783  {
2784  for (int k = 0; k < 3; k++)
2785  cb[k] *= as;
2786  m_glfcns.glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
2787 
2788  for (int k = 0; k < 3; k++)
2789  cb[k] = ds * c(j, i-1, k);
2790  m_glfcns.glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
2791 
2792  for (int k = 0; k < 3; k++)
2793  cb[k] = ss * (scr + (1-scr) * c(j, i-1, k));
2794  m_glfcns.glMaterialfv (LIGHT_MODE, GL_SPECULAR, cb);
2795  }
2796  }
2797  if (fl_mode == GOURAUD)
2798  set_normal (bfl_mode, vn, j, i-1);
2799 
2800  m_glfcns.glVertex3d (x(j2,i-1), y(j,i1), z(j,i-1));
2801 
2802  m_glfcns.glEnd ();
2803  }
2804  }
2805 
2806  set_polygon_offset (false);
2807  if (fc_mode == TEXTURE)
2808  m_glfcns.glDisable (GL_TEXTURE_2D);
2809 
2810  if ((fl_mode > 0) && do_lighting)
2811  m_glfcns.glDisable (GL_LIGHTING);
2812  }
2813  else
2814  {
2815  // FIXME: implement flat, interp and texturemap transparency
2816  }
2817  }
2818 
2819  if (! props.edgecolor_is ("none") && ! props.linestyle_is ("none"))
2820  {
2821  if (props.get_edgealpha_double () == 1)
2822  {
2823  cb[3] = 1.0; // edgealpha isn't implemented yet
2824  if (ec_mode == UNIFORM)
2825  {
2826  m_glfcns.glColor3dv (ecolor.data ());
2827  if (el_mode > 0)
2828  {
2829  for (int i = 0; i < 3; i++)
2830  cb[i] = as * ecolor(i);
2831  m_glfcns.glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
2832 
2833  for (int i = 0; i < 3; i++)
2834  cb[i] = ds * ecolor(i);
2835  m_glfcns.glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
2836 
2837  for (int i = 0; i < 3; i++)
2838  cb[i] = ss * (scr + (1-scr) * ecolor(i));
2839  m_glfcns.glMaterialfv (LIGHT_MODE, GL_SPECULAR, cb);
2840  }
2841  }
2842 
2843  if ((el_mode > 0) && do_lighting)
2844  m_glfcns.glEnable (GL_LIGHTING);
2845  m_glfcns.glShadeModel ((ec_mode == INTERP || el_mode == GOURAUD)
2846  ? GL_SMOOTH : GL_FLAT);
2847 
2848  set_linestyle (props.get_linestyle (), false,
2849  props.get_linewidth ());
2850  set_linewidth (props.get_linewidth ());
2851  set_linecap ("butt");
2852  set_linejoin ("miter");
2853 
2854  // Mesh along Y-axis
2855 
2856  if (props.meshstyle_is ("both") || props.meshstyle_is ("column"))
2857  {
2858  for (int i = 0; i < zc; i++)
2859  {
2860  if (y_mat)
2861  {
2862  i1 = i-1;
2863  i2 = i;
2864  }
2865 
2866  for (int j = 1; j < zr; j++)
2867  {
2868  if (clip(j-1,i) || clip(j,i))
2869  continue;
2870 
2871  if (ec_mode == FLAT)
2872  {
2873  // "flat" only needs color at lower-left vertex
2874  if (! math::isfinite (c(j-1,i)))
2875  continue;
2876  }
2877  else if (ec_mode == INTERP)
2878  {
2879  // "interp" needs valid color at both vertices
2880  if (! (math::isfinite (c(j-1, i)) && math::isfinite (c(j, i))))
2881  continue;
2882  }
2883 
2884  if (x_mat)
2885  {
2886  j1 = j-1;
2887  j2 = j;
2888  }
2889 
2890  m_glfcns.glBegin (GL_LINES);
2891 
2892  // Vertex 1
2893  if (ec_mode > 0)
2894  {
2895  for (int k = 0; k < 3; k++)
2896  cb[k] = c(j-1, i, k);
2897  m_glfcns.glColor3fv (cb);
2898 
2899  if (el_mode > 0)
2900  {
2901  for (int k = 0; k < 3; k++)
2902  cb[k] *= as;
2903  m_glfcns.glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
2904 
2905  for (int k = 0; k < 3; k++)
2906  cb[k] = ds * c(j-1, i, k);
2907  m_glfcns.glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
2908 
2909  for (int k = 0; k < 3; k++)
2910  cb[k] = ss * (scr + (1-scr) * c(j-1, i, k));
2911  m_glfcns.glMaterialfv (LIGHT_MODE, GL_SPECULAR, cb);
2912  }
2913  }
2914  if (el_mode > 0)
2915  {
2916  if (el_mode == GOURAUD)
2917  set_normal (bfl_mode, vn, j-1, i);
2918  else
2919  set_normal (bfl_mode, fn, j-1, std::min (i, zc-2));
2920  }
2921 
2922  m_glfcns.glVertex3d (x(j1,i), y(j-1,i2), z(j-1,i));
2923 
2924  // Vertex 2
2925  if (ec_mode == INTERP)
2926  {
2927  for (int k = 0; k < 3; k++)
2928  cb[k] = c(j, i, k);
2929  m_glfcns.glColor3fv (cb);
2930 
2931  if (el_mode > 0)
2932  {
2933  for (int k = 0; k < 3; k++)
2934  cb[k] *= as;
2935  m_glfcns.glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
2936 
2937  for (int k = 0; k < 3; k++)
2938  cb[k] = ds * c(j, i, k);
2939  m_glfcns.glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
2940 
2941  for (int k = 0; k < 3; k++)
2942  cb[k] = ss * (scr + (1-scr) * c(j, i, k));
2943  m_glfcns.glMaterialfv (LIGHT_MODE, GL_SPECULAR, cb);
2944  }
2945  }
2946  if (el_mode == GOURAUD)
2947  set_normal (bfl_mode, vn, j, i);
2948 
2949  m_glfcns.glVertex3d (x(j2,i), y(j,i2), z(j,i));
2950 
2951  m_glfcns.glEnd ();
2952  }
2953  }
2954  }
2955 
2956  // Mesh along X-axis
2957 
2958  if (props.meshstyle_is ("both") || props.meshstyle_is ("row"))
2959  {
2960  for (int j = 0; j < zr; j++)
2961  {
2962  if (x_mat)
2963  {
2964  j1 = j-1;
2965  j2 = j;
2966  }
2967 
2968  for (int i = 1; i < zc; i++)
2969  {
2970  if (clip(j,i-1) || clip(j,i))
2971  continue;
2972 
2973  if (ec_mode == FLAT)
2974  {
2975  // "flat" only needs color at lower-left vertex
2976  if (! math::isfinite (c(j,i-1)))
2977  continue;
2978  }
2979  else if (ec_mode == INTERP)
2980  {
2981  // "interp" needs valid color at both vertices
2982  if (! (math::isfinite (c(j, i-1)) && math::isfinite (c(j, i))))
2983  continue;
2984  }
2985 
2986  if (y_mat)
2987  {
2988  i1 = i-1;
2989  i2 = i;
2990  }
2991 
2992  m_glfcns.glBegin (GL_LINES);
2993 
2994  // Vertex 1
2995  if (ec_mode > 0)
2996  {
2997  for (int k = 0; k < 3; k++)
2998  cb[k] = c(j, i-1, k);
2999  m_glfcns.glColor3fv (cb);
3000 
3001  if (el_mode > 0)
3002  {
3003  for (int k = 0; k < 3; k++)
3004  cb[k] *= as;
3005  m_glfcns.glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
3006 
3007  for (int k = 0; k < 3; k++)
3008  cb[k] = ds * c(j, i-1, k);
3009  m_glfcns.glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
3010 
3011  for (int k = 0; k < 3; k++)
3012  cb[k] = ss * (scr + (1-scr) * c(j, i-1, k));
3013  m_glfcns.glMaterialfv (LIGHT_MODE, GL_SPECULAR, cb);
3014  }
3015  }
3016  if (el_mode > 0)
3017  {
3018  if (el_mode == GOURAUD)
3019  set_normal (bfl_mode, vn, j, i-1);
3020  else
3021  set_normal (bfl_mode, fn, std::min (j, zr-2), i-1);
3022  }
3023 
3024  m_glfcns.glVertex3d (x(j2,i-1), y(j,i1), z(j,i-1));
3025 
3026  // Vertex 2
3027  if (ec_mode == INTERP)
3028  {
3029  for (int k = 0; k < 3; k++)
3030  cb[k] = c(j, i, k);
3031  m_glfcns.glColor3fv (cb);
3032 
3033  if (el_mode > 0)
3034  {
3035  for (int k = 0; k < 3; k++)
3036  cb[k] *= as;
3037  m_glfcns.glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
3038 
3039  for (int k = 0; k < 3; k++)
3040  cb[k] = ds * c(j, i, k);
3041  m_glfcns.glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
3042 
3043  for (int k = 0; k < 3; k++)
3044  cb[k] = ss * (scr + (1-scr) * c(j, i, k));
3045  m_glfcns.glMaterialfv (LIGHT_MODE, GL_SPECULAR, cb);
3046  }
3047  }
3048  if (el_mode == GOURAUD)
3049  set_normal (bfl_mode, vn, j, i);
3050 
3051  m_glfcns.glVertex3d (x(j2,i), y(j,i2), z(j,i));
3052 
3053  m_glfcns.glEnd ();
3054  }
3055  }
3056  }
3057 
3058  set_linestyle ("-"); // Disable LineStipple
3059  set_linewidth (0.5f);
3060 
3061  if ((el_mode > 0) && do_lighting)
3062  m_glfcns.glDisable (GL_LIGHTING);
3063  }
3064  else
3065  {
3066  // FIXME: implement transparency
3067  }
3068  }
3069 
3070  if (! props.marker_is ("none")
3071  && ! (props.markeredgecolor_is ("none")
3072  && props.markerfacecolor_is ("none")))
3073  {
3074  // FIXME: check how transparency should be handled in markers
3075  // FIXME: check what to do with marker facecolor set to auto
3076  // and facecolor set to none.
3077 
3078  bool do_edge = draw_all || ! props.markeredgecolor_is ("none");
3079  bool do_face = draw_all || ! props.markerfacecolor_is ("none");
3080 
3081  Matrix mecolor = (draw_all ? Matrix (1, 3, 0.0) :
3082  props.get_markeredgecolor_rgb ());
3083  Matrix mfcolor = (draw_all ? Matrix (1, 3, 0.0) :
3084  props.get_markerfacecolor_rgb ());
3085  Matrix cc (1, 3, 0.0);
3086 
3087  if (mecolor.isempty () && props.markeredgecolor_is ("auto"))
3088  {
3089  mecolor = props.get_edgecolor_rgb ();
3090  do_edge = ! props.edgecolor_is ("none");
3091  }
3092 
3093  if (mfcolor.isempty () && props.markerfacecolor_is ("auto"))
3094  {
3095  mfcolor = props.get_facecolor_rgb ();
3096  do_face = ! props.facecolor_is ("none");
3097  }
3098 
3099  if ((mecolor.isempty () || mfcolor.isempty ()) && c.isempty ())
3100  c = props.get_color_data ().array_value ();
3101 
3102  init_marker (props.get_marker (), props.get_markersize (),
3103  props.get_linewidth ());
3104 
3105  uint8_t clip_mask = (props.is_clipping () ? 0x7F : 0x40);
3106  uint8_t clip_ok = 0x40;
3107 
3108  for (int i = 0; i < zc; i++)
3109  {
3110  if (y_mat)
3111  i1 = i;
3112 
3113  for (int j = 0; j < zr; j++)
3114  {
3115  if (x_mat)
3116  j1 = j;
3117 
3118  if ((clip_code (x(j1,i), y(j,i1), z(j,i)) & clip_mask)
3119  != clip_ok)
3120  continue;
3121 
3122  if ((do_edge && mecolor.isempty ())
3123  || (do_face && mfcolor.isempty ()))
3124  {
3125  if (! math::isfinite (c(j,i)))
3126  continue; // Skip NaNs in color data
3127 
3128  for (int k = 0; k < 3; k++)
3129  cc(k) = c(j,i,k);
3130  }
3131 
3132  Matrix lc = (do_edge ? (mecolor.isempty () ? cc : mecolor)
3133  : Matrix ());
3134  Matrix fc = (do_face ? (mfcolor.isempty () ? cc : mfcolor)
3135  : Matrix ());
3136 
3137  draw_marker (x(j1,i), y(j,i1), z(j,i), lc, fc);
3138  }
3139  }
3140 
3141  end_marker ();
3142  }
3143 
3144 #else
3145 
3146  octave_unused_parameter (props);
3147 
3148  // This shouldn't happen because construction of opengl_renderer
3149  // objects is supposed to be impossible if OpenGL is not available.
3150 
3151  panic_impossible ();
3152 
3153 #endif
3154  }
3155 
3156  // FIXME: global optimization (rendering, data structures...),
3157  // there is probably a smarter/faster/less-memory-consuming way to do this.
3158  void
3160  {
3161 #if defined (HAVE_OPENGL)
3162 
3163  // Do not render if the patch has incoherent data
3164  std::string msg;
3165  if (props.has_bad_data (msg))
3166  {
3167  warning ("opengl_renderer: %s. Not rendering.", msg.c_str ());
3168  return;
3169  }
3170 
3171  bool draw_all = selecting && props.pickableparts_is ("all");
3172  const Matrix f = props.get_faces ().matrix_value ();
3173  const Matrix v = xform.scale (props.get_vertices ().matrix_value ());
3174  Matrix c;
3175  Matrix a;
3176  double fa = 1.0;
3177 
3178  int nv = v.rows ();
3179  int nf = f.rows ();
3180  int fcmax = f.columns ();
3181 
3182  bool has_z = (v.columns () > 2);
3183  bool has_facecolor = false;
3184  bool has_facealpha = false;
3185 
3186  int fc_mode = ((props.facecolor_is ("none")
3187  || props.facecolor_is_rgb () || draw_all) ? 0 :
3188  (props.facecolor_is ("flat") ? 1 : 2));
3189  int fl_mode = (props.facelighting_is ("none") ? 0 :
3190  (props.facelighting_is ("flat") ? 1 : 2));
3191  int fa_mode = (props.facealpha_is_double () ? 0 :
3192  (props.facealpha_is ("flat") ? 1 : 2));
3193  int ec_mode = ((props.edgecolor_is ("none")
3194  || props.edgecolor_is_rgb ()) ? 0 :
3195  (props.edgecolor_is ("flat") ? 1 : 2));
3196  int el_mode = (props.edgelighting_is ("none") ? 0 :
3197  (props.edgelighting_is ("flat") ? 1 : 2));
3198  int ea_mode = (props.edgealpha_is_double () ? 0 :
3199  (props.edgealpha_is ("flat") ? 1 : 2));
3200  int bfl_mode = (props.backfacelighting_is ("lit") ? 0 :
3201  (props.backfacelighting_is ("reverselit") ? 1 : 2));
3202  bool do_lighting = props.get_do_lighting ();
3203 
3204  Matrix fcolor = props.get_facecolor_rgb ();
3205  Matrix ecolor = props.get_edgecolor_rgb ();
3206 
3207  float as = props.get_ambientstrength ();
3208  float ds = props.get_diffusestrength ();
3209  float ss = props.get_specularstrength ();
3210  float se = props.get_specularexponent () * 5; // to fit Matlab
3211  float scr = props.get_specularcolorreflectance ();
3212 
3213  const Matrix vn = props.get_vertexnormals ().matrix_value ();
3214  bool has_vertex_normals = (vn.rows () == nv);
3215  const Matrix fn = props.get_facenormals ().matrix_value ();
3216  bool has_face_normals = (fn.rows () == nf);
3217 
3218  boolMatrix clip (1, nv, false);
3219 
3220  if (has_z)
3221  for (int i = 0; i < nv; i++)
3222  clip(i) = is_nan_or_inf (v(i,0), v(i,1), v(i,2));
3223  else
3224  for (int i = 0; i < nv; i++)
3225  clip(i) = is_nan_or_inf (v(i,0), v(i,1), 0);
3226 
3227  boolMatrix clip_f (1, nf, false);
3228  Array<int> count_f (dim_vector (nf, 1), 0);
3229 
3230  for (int i = 0; i < nf; i++)
3231  {
3232  bool fclip = false;
3233  int count = 0;
3234 
3235  for (int j = 0; j < fcmax && ! math::isnan (f(i,j)); j++, count++)
3236  fclip = (fclip || clip(int (f(i,j) - 1)));
3237 
3238  clip_f(i) = fclip;
3239  count_f(i) = count;
3240  }
3241 
3242  if (draw_all || fc_mode > 0 || ec_mode > 0)
3243  {
3244  if (draw_all)
3245  c = Matrix (1, 3, 0.0);
3246  else
3247  c = props.get_color_data ().matrix_value ();
3248 
3249  if (c.rows () == 1)
3250  {
3251  // Single color specifications, we can simplify a little bit
3252 
3253  if (draw_all || fc_mode > 0)
3254  {
3255  fcolor = c;
3256  fc_mode = UNIFORM;
3257  }
3258 
3259  if (draw_all || ec_mode > 0)
3260  {
3261  ecolor = c;
3262  ec_mode = UNIFORM;
3263  }
3264 
3265  c = Matrix ();
3266  }
3267  else
3268  has_facecolor = ((c.numel () > 0) && (c.rows () == f.rows ()));
3269  }
3270 
3271  if (fa_mode > 0 || ea_mode > 0)
3272  {
3273  // FIXME: retrieve alpha data from patch object
3274  //a = props.get_alpha_data ();
3275  has_facealpha = ((a.numel () > 0) && (a.rows () == f.rows ()));
3276  }
3277 
3278  if (fa_mode == 0)
3279  fa = props.get_facealpha_double ();
3280 
3281  octave_idx_type fr = f.rows ();
3282  std::vector<vertex_data> vdata (f.numel ());
3283 
3284  for (int i = 0; i < nf; i++)
3285  for (int j = 0; j < count_f(i); j++)
3286  {
3287  int idx = int (f(i,j) - 1);
3288 
3289  Matrix vv (1, 3, 0.0);
3290  Matrix cc;
3291  Matrix vnn (1, 3, 0.0);
3292  Matrix fnn (1, 3, 0.0);
3293  double aa = 1.0;
3294 
3295  vv(0) = v(idx,0); vv(1) = v(idx,1);
3296  if (has_z)
3297  vv(2) = v(idx,2);
3298  if (((fl_mode == FLAT) || (el_mode == FLAT)) && has_face_normals)
3299  {
3300  double dir = 1.0;
3301  if (bfl_mode > 0)
3302  dir = ((fn(i,0) * view_vector(0)
3303  + fn(i,1) * view_vector(1)
3304  + fn(i,2) * view_vector(2) < 0)
3305  ? ((bfl_mode > 1) ? 0.0 : -1.0) : 1.0);
3306  fnn(0) = dir * fn(i,0);
3307  fnn(1) = dir * fn(i,1);
3308  fnn(2) = dir * fn(i,2);
3309  }
3310  if ((fl_mode == GOURAUD || el_mode == GOURAUD) && has_vertex_normals)
3311  {
3312  double dir = 1.0;
3313  if (bfl_mode > 0)
3314  dir = ((vn(idx,0) * view_vector(0)
3315  + vn(idx,1) * view_vector(1)
3316  + vn(idx,2) * view_vector(2) < 0)
3317  ? ((bfl_mode > 1) ? 0.0 : -1.0) : 1.0);
3318  vnn(0) = dir * vn(idx,0);
3319  vnn(1) = dir * vn(idx,1);
3320  vnn(2) = dir * vn(idx,2);
3321  }
3322  if (c.numel () > 0)
3323  {
3324  cc.resize (1, 3);
3325  if (has_facecolor)
3326  cc(0) = c(i,0), cc(1) = c(i,1), cc(2) = c(i,2);
3327  else
3328  cc(0) = c(idx,0), cc(1) = c(idx,1), cc(2) = c(idx,2);
3329  }
3330  if (fa_mode == 0)
3331  aa = fa;
3332  else if (a.numel () > 0)
3333  {
3334  if (has_facealpha)
3335  aa = a(i);
3336  else
3337  aa = a(idx);
3338  }
3339 
3340  vdata[i+j*fr] = vertex_data (vv, cc, vnn, fnn, aa, as, ds, ss, se, scr);
3341  }
3342 
3343  if (fl_mode > 0 || el_mode > 0)
3344  m_glfcns.glMaterialf (LIGHT_MODE, GL_SHININESS, se);
3345 
3346  if (draw_all || ! props.facecolor_is ("none"))
3347  {
3348  // FIXME: adapt to double-radio property
3349  if (fa_mode == 0)
3350  {
3351  if (fc_mode == UNIFORM)
3352  {
3353  m_glfcns.glColor4d (fcolor(0), fcolor(1), fcolor(2), fa);
3354  if (fl_mode > 0)
3355  {
3356  float cb[4] = { 0.0f, 0.0f, 0.0f, 1.0f };;
3357 
3358  for (int i = 0; i < 3; i++)
3359  cb[i] = as * fcolor(i);
3360  m_glfcns.glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
3361 
3362  for (int i = 0; i < 3; i++)
3363  cb[i] = ds * fcolor(i);
3364  m_glfcns.glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
3365 
3366  for (int i = 0; i < 3; i++)
3367  cb[i] = ss * (scr + (1-scr) * fcolor(i));
3368  m_glfcns.glMaterialfv (LIGHT_MODE, GL_SPECULAR, cb);
3369  }
3370  }
3371 
3372  if ((fl_mode > 0) && do_lighting)
3373  m_glfcns.glEnable (GL_LIGHTING);
3374 
3375  // NOTE: Push filled part of patch backwards to avoid Z-fighting
3376  // with tessellator outline. A value of 1.0 seems to work fine.
3377  // Value can't be too large or the patch will be pushed below the
3378  // axes planes at +2.5.
3379  patch_tessellator tess (this, fc_mode, fl_mode, true, 1.0);
3380 
3381  std::vector<octave_idx_type>::const_iterator it;
3382  octave_idx_type i_start, i_end;
3383 
3384  for (int i = 0; i < nf; i++)
3385  {
3386  if (clip_f(i))
3387  continue;
3388 
3389  bool is_non_planar = false;
3390  if (props.coplanar_last_idx.size () > 0
3391  && props.coplanar_last_idx[i].size () > 1)
3392  {
3393  is_non_planar = true;
3394  it = props.coplanar_last_idx[i].end ();
3395  it--;
3396  }
3397 
3398  // loop over planar subsets of face
3399  do
3400  {
3401  if (is_non_planar)
3402  {
3403  i_end = *it;
3404  if (it == props.coplanar_last_idx[i].begin ())
3405  i_start = 0;
3406  else
3407  {
3408  it--;
3409  i_start = *it - 1;
3410  }
3411  }
3412  else
3413  {
3414  i_end = count_f(i) - 1;
3415  i_start = 0;
3416  }
3417 
3418  tess.begin_polygon (true);
3419  tess.begin_contour ();
3420 
3421  // Add vertices in reverse order for Matlab compatibility
3422  for (int j = i_end; j > i_start; j--)
3423  {
3425  = vdata[i+j*fr].get_rep ();
3426 
3427  tess.add_vertex (vv->coords.fortran_vec (), vv);
3428  }
3429 
3430  if (count_f(i) > 0)
3431  {
3432  vertex_data::vertex_data_rep *vv = vdata[i].get_rep ();
3433 
3434  if (fc_mode == FLAT)
3435  {
3436  // For "flat" shading, use color of 1st vertex.
3437  Matrix col = vv->color;
3438 
3439  if (col.numel () == 3)
3440  {
3441  m_glfcns.glColor4d (col(0), col(1), col(2), fa);
3442  if (fl_mode > 0)
3443  {
3444  float cb[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
3445 
3446  for (int k = 0; k < 3; k++)
3447  cb[k] = (vv->ambient * col(k));
3448  m_glfcns.glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
3449 
3450  for (int k = 0; k < 3; k++)
3451  cb[k] = (vv->diffuse * col(k));
3452  m_glfcns.glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
3453 
3454  for (int k = 0; k < 3; k++)
3455  cb[k] = vv->specular *
3456  (vv->specular_color_refl
3457  + (1-vv->specular_color_refl) *
3458  col(k));
3459  m_glfcns.glMaterialfv (LIGHT_MODE, GL_SPECULAR, cb);
3460  }
3461  }
3462  }
3463 
3464  tess.add_vertex (vv->coords.fortran_vec (), vv);
3465  }
3466 
3467  tess.end_contour ();
3468  tess.end_polygon ();
3469  } while (i_start > 0);
3470  }
3471 
3472  if ((fl_mode > 0) && do_lighting)
3473  m_glfcns.glDisable (GL_LIGHTING);
3474  }
3475  else
3476  {
3477  // FIXME: implement flat and interp transparency
3478  }
3479  }
3480 
3481  if (draw_all
3482  || (! props.edgecolor_is ("none") && ! props.linestyle_is ("none")))
3483  {
3484  // FIXME: adapt to double-radio property
3485  if (props.get_edgealpha_double () == 1)
3486  {
3487  if (ec_mode == UNIFORM)
3488  {
3489  m_glfcns.glColor3dv (ecolor.data ());
3490  if (el_mode > 0)
3491  {
3492  // edge lighting only uses ambient light
3493  float cb[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
3494  m_glfcns.glMaterialfv (LIGHT_MODE, GL_SPECULAR, cb);
3495  m_glfcns.glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
3496 
3497  for (int i = 0; i < 3; i++)
3498  cb[i] = (as * ecolor(i));
3499  m_glfcns.glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
3500  }
3501  }
3502 
3503  if ((el_mode > 0) && do_lighting)
3504  m_glfcns.glEnable (GL_LIGHTING);
3505 
3506  double linewidth = props.get_linewidth ();
3507  set_linestyle (props.get_linestyle (), false, linewidth);
3508  set_linewidth (linewidth);
3509  set_linecap ("butt");
3510  set_linejoin ("miter");
3511 
3512  // NOTE: patch contour cannot be offset. Offset must occur with the
3513  // filled portion of the patch above. The tessellator uses
3514  // GLU_TESS_BOUNDARY_ONLY to get the outline of the patch and OpenGL
3515  // automatically sets the glType to GL_LINE_LOOP. This primitive is
3516  // not supported by glPolygonOffset which is used to do Z offsets.
3517  patch_tessellator tess (this, ec_mode, el_mode, false);
3518 
3519  for (int i = 0; i < nf; i++)
3520  {
3521  bool is_non_planar = false;
3522  if (props.coplanar_last_idx.size () > 0
3523  && props.coplanar_last_idx[i].size () > 1)
3524  is_non_planar = true;
3525  if (clip_f(i) || is_non_planar)
3526  {
3527  // This is an unclosed contour or a non-planar face.
3528  // Draw it as a line.
3529  bool flag = false;
3530 
3531  m_glfcns.glShadeModel ((ec_mode == INTERP || el_mode == GOURAUD)
3532  ? GL_SMOOTH : GL_FLAT);
3533 
3534  // Add vertices in reverse order for Matlab compatibility
3535  for (int j = count_f(i)-1; j >= 0; j--)
3536  {
3537  if (! clip(int (f(i,j) - 1)))
3538  {
3540  = vdata[i+j*fr].get_rep ();
3541  const Matrix m = vv->coords;
3542  if (! flag)
3543  {
3544  flag = true;
3545  m_glfcns.glBegin (GL_LINE_STRIP);
3546  }
3547  if (ec_mode != UNIFORM)
3548  {
3549  Matrix col = vv->color;
3550 
3551  if (col.numel () == 3)
3552  m_glfcns.glColor3dv (col.data ());
3553  }
3554  m_glfcns.glVertex3d (m(0), m(1), m(2));
3555  }
3556  else if (flag)
3557  {
3558  flag = false;
3559  m_glfcns.glEnd ();
3560  }
3561  }
3562  // Do loop body with vertex N to "close" GL_LINE_STRIP
3563  // from vertex 0 to vertex N.
3564  int j = count_f(i)-1;
3565  if (flag && ! clip(int (f(i,j) - 1)))
3566  {
3568  = vdata[i+j*fr].get_rep ();
3569  const Matrix m = vv->coords;
3570  if (ec_mode != UNIFORM)
3571  {
3572  Matrix col = vv->color;
3573 
3574  if (col.numel () == 3)
3575  m_glfcns.glColor3dv (col.data ());
3576  }
3577  m_glfcns.glVertex3d (m(0), m(1), m(2));
3578  }
3579 
3580  if (flag)
3581  m_glfcns.glEnd ();
3582  }
3583  else // Normal edge contour drawn with tessellator
3584  {
3585  tess.begin_polygon (false);
3586  tess.begin_contour ();
3587 
3588  for (int j = count_f(i)-1; j >= 0; j--)
3589  {
3591  = vdata[i+j*fr].get_rep ();
3592  tess.add_vertex (vv->coords.fortran_vec (), vv);
3593  }
3594 
3595  tess.end_contour ();
3596  tess.end_polygon ();
3597  }
3598  }
3599 
3600  set_linestyle ("-"); // Disable LineStipple
3601  set_linewidth (0.5f);
3602 
3603  if ((el_mode > 0) && do_lighting)
3604  m_glfcns.glDisable (GL_LIGHTING);
3605  }
3606  else
3607  {
3608  // FIXME: implement transparency
3609  }
3610  }
3611 
3612  if (! props.marker_is ("none")
3613  && ! (props.markeredgecolor_is ("none")
3614  && props.markerfacecolor_is ("none")))
3615  {
3616  bool do_edge = draw_all || ! props.markeredgecolor_is ("none");
3617  bool do_face = draw_all || ! props.markerfacecolor_is ("none");
3618 
3619  Matrix mecolor = (draw_all ? Matrix (1, 3, 0.0) :
3620  props.get_markeredgecolor_rgb ());
3621  Matrix mfcolor = (draw_all ? Matrix (1, 3, 0.0) :
3622  props.get_markerfacecolor_rgb ());
3623 
3624  bool has_markerfacecolor = draw_all || false;
3625 
3626  if ((mecolor.isempty () && ! props.markeredgecolor_is ("none"))
3627  || (mfcolor.isempty () && ! props.markerfacecolor_is ("none")))
3628  {
3629  Matrix mc = props.get_color_data ().matrix_value ();
3630 
3631  if (mc.rows () == 1)
3632  {
3633  // Single color specifications, we can simplify a little bit
3634  if (mfcolor.isempty () && ! props.markerfacecolor_is ("none"))
3635  mfcolor = mc;
3636 
3637  if (mecolor.isempty () && ! props.markeredgecolor_is ("none"))
3638  mecolor = mc;
3639  }
3640  else
3641  {
3642  if (c.isempty ())
3643  c = props.get_color_data ().matrix_value ();
3644  has_markerfacecolor = ((c.numel () > 0)
3645  && (c.rows () == f.rows ()));
3646  }
3647  }
3648 
3649  init_marker (props.get_marker (), props.get_markersize (),
3650  props.get_linewidth ());
3651 
3652  uint8_t clip_mask = (props.is_clipping () ? 0x7F : 0x40);
3653  uint8_t clip_ok = 0x40;
3654 
3655  for (int i = 0; i < nf; i++)
3656  for (int j = 0; j < count_f(i); j++)
3657  {
3658  int idx = int (f(i,j) - 1);
3659 
3660  if ((clip_code (v(idx,0), v(idx,1), (has_z ? v(idx,2) : 0))
3661  & clip_mask) != clip_ok)
3662  continue;
3663 
3664  Matrix cc;
3665  if (c.numel () > 0)
3666  {
3667  cc.resize (1, 3);
3668  if (has_markerfacecolor)
3669  cc(0) = c(i,0), cc(1) = c(i,1), cc(2) = c(i,2);
3670  else
3671  cc(0) = c(idx,0), cc(1) = c(idx,1), cc(2) = c(idx,2);
3672  }
3673 
3674  Matrix lc = (do_edge ? (mecolor.isempty () ? cc : mecolor)
3675  : Matrix ());
3676  Matrix fc = (do_face ? (mfcolor.isempty () ? cc : mfcolor)
3677  : Matrix ());
3678 
3679  draw_marker (v(idx,0), v(idx,1), (has_z ? v(idx,2) : 0), lc, fc);
3680  }
3681 
3682  end_marker ();
3683  }
3684 
3685 #else
3686 
3687  octave_unused_parameter (props);
3688 
3689  // This shouldn't happen because construction of opengl_renderer
3690  // objects is supposed to be impossible if OpenGL is not available.
3691 
3692  panic_impossible ();
3693 
3694 #endif
3695  }
3696 
3697  void
3699  {
3700 #if defined (HAVE_OPENGL)
3701 
3702  // enable light source
3704 
3705  // light position
3706  float pos[4] = { 0, 0, 0, 0 }; // X,Y,Z,infinite/local
3707  Matrix lpos = props.get_position ().matrix_value ();
3708  for (int i = 0; i < 3; i++)
3709  pos[i] = lpos(i);
3710  if (props.style_is ("local"))
3711  pos[3] = 1;
3712  m_glfcns.glLightfv (m_current_light, GL_POSITION, pos);
3713 
3714  // light color
3715  float col[4] = { 1, 1, 1, 1 }; // R,G,B,ALPHA (the latter has no meaning)
3716  Matrix lcolor = props.get_color ().matrix_value ();
3717  for (int i = 0; i < 3; i++)
3718  col[i] = lcolor(i);
3719  m_glfcns.glLightfv (m_current_light, GL_DIFFUSE, col);
3720  m_glfcns.glLightfv (m_current_light, GL_SPECULAR, col);
3721 
3722 #else
3723 
3724  octave_unused_parameter (props);
3725 
3726  // This shouldn't happen because construction of opengl_renderer
3727  // objects is supposed to be impossible if OpenGL is not available.
3728 
3729  panic_impossible ();
3730 
3731 #endif
3732  }
3733 
3734  void
3736  {
3737  draw (props.get_children ());
3738  }
3739 
3740  void
3742  {
3743 #if defined (HAVE_OPENGL)
3744 
3745  if (props.get_string ().isempty () || props.color_is ("none"))
3746  return;
3747 
3748  Matrix pos = xform.scale (props.get_data_position ());
3749 
3750  // Handle clipping manually when drawing text background
3751  if (! props.is_clipping ()
3752  || (clip_code (pos(0), pos(1), pos.numel () > 2 ? pos(2) : 0.0) == 0x40))
3753  {
3754  set_clipping (false);
3755  draw_text_background (props);
3756  set_clipping (props.is_clipping ());
3757  }
3758 
3759  set_font (props);
3760 
3761  const Matrix bbox = props.get_extent_matrix ();
3762 
3763  bool blend = m_glfcns.glIsEnabled (GL_BLEND);
3764 
3765  m_glfcns.glEnable (GL_BLEND);
3766  m_glfcns.glEnable (GL_ALPHA_TEST);
3767  m_glfcns.glRasterPos3d (pos(0), pos(1), pos.numel () > 2 ? pos(2) : 0.0);
3768  m_glfcns.glBitmap (0, 0, 0, 0, bbox(0), bbox(1), nullptr);
3769  m_glfcns.glDrawPixels (bbox(2), bbox(3), GL_RGBA, GL_UNSIGNED_BYTE,
3770  props.get_pixels ().data ());
3771  m_glfcns.glDisable (GL_ALPHA_TEST);
3772  if (! blend)
3773  m_glfcns.glDisable (GL_BLEND);
3774 
3775 #else
3776 
3777  octave_unused_parameter (props);
3778 
3779  // This shouldn't happen because construction of opengl_renderer
3780  // objects is supposed to be impossible if OpenGL is not available.
3781 
3782  panic_impossible ();
3783 
3784 #endif
3785  }
3786 
3787  void
3789  bool do_rotate)
3790  {
3791 #if defined (HAVE_OPENGL)
3792 
3793  Matrix bgcol = props.get_backgroundcolor_rgb ();
3794  Matrix ecol = props.get_edgecolor_rgb ();
3795 
3796  if (bgcol.isempty () && ecol.isempty ())
3797  return;
3798 
3799  Matrix pos = props.get_data_position ();
3800  ColumnVector pixpos = get_transform ().transform (pos(0), pos(1),
3801  pos(2), true);
3802 
3803  // Save current transform matrices and set orthogonal window coordinates
3804  m_glfcns.glMatrixMode (GL_PROJECTION);
3807 
3808  Matrix vp = get_viewport_scaled ();
3809  m_glfcns.glOrtho (0, vp(2), vp(3), 0, xZ1, xZ2);
3810  m_glfcns.glMatrixMode (GL_MODELVIEW);
3813 
3814  // Translate coordinates so that the text anchor is (0,0)
3815  m_glfcns.glTranslated (pixpos(0), pixpos(1), -pixpos(2));
3816 
3817  // FIXME: Only multiples of 90° are handled by the text renderer.
3818  // Handle others here.
3819  double rotation = props.get_rotation ();
3820 
3821  if (do_rotate && rotation != 0.0 && rotation != 90.0
3822  && rotation != 180.0 && rotation != 270.0)
3823  m_glfcns.glRotated (-rotation, 0.0, 0.0, 1.0);
3824 
3825  double m = points_to_pixels (props.get_margin ());
3826  const Matrix bbox = props.get_extent_matrix ();
3827  double x0 = bbox (0) / m_devpixratio - m;
3828  double x1 = x0 + bbox(2) / m_devpixratio + 2 * m;
3829  double y0 = -(bbox (1) / m_devpixratio - m);
3830  double y1 = y0 - (bbox(3) / m_devpixratio + 2 * m);
3831 
3832  if (! bgcol.isempty ())
3833  {
3834  m_glfcns.glColor3f (bgcol(0), bgcol(1), bgcol(2));
3835 
3836  bool depth_test = m_glfcns.glIsEnabled (GL_DEPTH_TEST);
3837  if (depth_test)
3838  set_polygon_offset (true, 4.0);
3839 
3840  m_glfcns.glBegin (GL_QUADS);
3841  m_glfcns.glVertex2d (x0, y0);
3842  m_glfcns.glVertex2d (x1, y0);
3843  m_glfcns.glVertex2d (x1, y1);
3844  m_glfcns.glVertex2d (x0, y1);
3845  m_glfcns.glEnd ();
3846 
3847  if (depth_test)
3848  set_polygon_offset (false);
3849  }
3850 
3851  if (! ecol.isempty ())
3852  {
3853  m_glfcns.glColor3f (ecol(0), ecol(1), ecol(2));
3854 
3855  set_linestyle (props.get_linestyle (), false, props.get_linewidth ());
3856  set_linewidth (props.get_linewidth ());
3857 
3858  m_glfcns.glBegin (GL_LINE_STRIP);
3859  m_glfcns.glVertex2d (x0, y0);
3860  m_glfcns.glVertex2d (x1, y0);
3861  m_glfcns.glVertex2d (x1, y1);
3862  m_glfcns.glVertex2d (x0, y1);
3863  m_glfcns.glVertex2d (x0, y0);
3864  m_glfcns.glEnd ();
3865 
3866  set_linestyle ("-");
3867  }
3868 
3869  // Restore previous coordinate system
3871  m_glfcns.glMatrixMode (GL_PROJECTION);
3873 
3874 #else
3875 
3876  octave_unused_parameter (props);
3877  octave_unused_parameter (do_rotate);
3878 
3879  // This shouldn't happen because construction of opengl_renderer
3880  // objects is supposed to be impossible if OpenGL is not available.
3881 
3882  panic_impossible ();
3883 
3884 #endif
3885  }
3886 
3887  void
3889  {
3890 #if defined (HAVE_OPENGL)
3891 
3892  octave_value cdata = props.get_color_data ();
3893  dim_vector dv (cdata.dims ());
3894  int h = dv(0);
3895  int w = dv(1);
3896  double x0, x1, y0, y1;
3897 
3898  Matrix x = props.get_xdata ().matrix_value ();
3899  double dx = 1.0;
3900  if (w > 1)
3901  dx = (x(1) - x(0)) / (w - 1);
3902 
3903  x0 = x(0)-dx/2;
3904  x1 = x(1)+dx/2;
3905 
3906  Matrix y = props.get_ydata ().matrix_value ();
3907  double dy = 1.0;
3908  if (h > 1)
3909  dy = (y(1) - y(0)) / (h - 1);
3910 
3911  y0 = y(0)-dy/2;
3912  y1 = y(1)+dy/2;
3913 
3914  // Expect RGB data
3915  if (dv.ndims () == 3 && dv(2) == 3)
3916  {
3918  if (tex.is_valid ())
3919  {
3920  m_glfcns.glColor4d (1.0, 1.0, 1.0, 1.0);
3921 
3922  m_glfcns.glEnable (GL_TEXTURE_2D);
3923 
3924  m_glfcns.glBegin (GL_QUADS);
3925 
3926  tex.tex_coord (0.0, 0.0);
3927  m_glfcns.glVertex3d (x0, y0, 0.0);
3928 
3929  tex.tex_coord (1.0, 0.0);
3930  m_glfcns.glVertex3d (x1, y0, 0.0);
3931 
3932  tex.tex_coord (1.0, 1.0);
3933  m_glfcns.glVertex3d (x1, y1, 0.0);
3934 
3935  tex.tex_coord (0.0, 1.0);
3936  m_glfcns.glVertex3d (x0, y1, 0.0);
3937 
3938  m_glfcns.glEnd ();
3939  m_glfcns.glDisable (GL_TEXTURE_2D);
3940  }
3941  }
3942  else
3943  warning ("opengl_renderer: invalid image size (expected MxNx3 or MxN)");
3944 
3945 #else
3946 
3947  octave_unused_parameter (props);
3948 
3949  // This shouldn't happen because construction of opengl_renderer
3950  // objects is supposed to be impossible if OpenGL is not available.
3951 
3952  panic_impossible ();
3953 
3954 #endif
3955  }
3956 
3957  void opengl_renderer::draw (const Matrix& hlist, bool toplevel)
3958  {
3959  int len = hlist.numel ();
3960 
3961  gh_manager& gh_mgr = __get_gh_manager__ ("opengl_renderer::draw");
3962 
3963  for (int i = len-1; i >= 0; i--)
3964  {
3965  graphics_object obj = gh_mgr.get_object (hlist(i));
3966 
3967  if (obj)
3968  draw (obj, toplevel);
3969  }
3970  }
3971 
3972  void
3974  {
3975 #if defined (HAVE_OPENGL)
3976 
3977  m_glfcns.glViewport (0, 0, w, h);
3978 
3979 #else
3980 
3981  octave_unused_parameter (w);
3982  octave_unused_parameter (h);
3983 
3984  // This shouldn't happen because construction of opengl_renderer
3985  // objects is supposed to be impossible if OpenGL is not available.
3986 
3987  panic_impossible ();
3988 
3989 #endif
3990  }
3991 
3992  Matrix
3994  {
3995  Matrix retval (1, 4, 0.0);
3996 
3997 #if defined (HAVE_OPENGL)
3998 #if defined (HAVE_FRAMEWORK_OPENGL)
3999  GLint vp[4];
4000 #else
4001  int vp[4];
4002 #endif
4003 
4004  m_glfcns.glGetIntegerv (GL_VIEWPORT, vp);
4005 
4006  for (int i = 0; i < 4; i++)
4007  retval(i) = static_cast<double> (vp[i]) / m_devpixratio;
4008 
4009 #else
4010 
4011  // This shouldn't happen because construction of opengl_renderer
4012  // objects is supposed to be impossible if OpenGL is not available.
4013 
4014  panic_impossible ();
4015 
4016 #endif
4017 
4018  return retval;
4019  }
4020 
4021  void
4023  {
4024 #if defined (HAVE_OPENGL)
4025 
4026  m_glfcns.glColor3dv (c.data ());
4027 
4028  if (! c.isempty ())
4029  txt_renderer.set_color (c);
4030 
4031 #else
4032 
4033  octave_unused_parameter (c);
4034 
4035  // This shouldn't happen because construction of opengl_renderer
4036  // objects is supposed to be impossible if OpenGL is not available.
4037 
4038  panic_impossible ();
4039 
4040 #endif
4041  }
4042 
4043  void
4045  {
4046  bool do_anti_alias = props.get ("fontsmoothing").string_value () == "on";
4047  txt_renderer.set_anti_aliasing (do_anti_alias);
4048  txt_renderer.set_font (props.get ("fontname").string_value (),
4049  props.get ("fontweight").string_value (),
4050  props.get ("fontangle").string_value (),
4051  props.get ("__fontsize_points__").double_value ()
4052  * m_devpixratio);
4053  }
4054 
4055  void
4056  opengl_renderer::set_polygon_offset (bool on, float offset)
4057  {
4058 #if defined (HAVE_OPENGL)
4059 
4060  if (on)
4061  {
4062  m_glfcns.glEnable (GL_POLYGON_OFFSET_FILL);
4063  m_glfcns.glEnable (GL_POLYGON_OFFSET_LINE);
4064  m_glfcns.glPolygonOffset (offset, offset);
4065  }
4066  else
4067  {
4068  m_glfcns.glDisable (GL_POLYGON_OFFSET_FILL);
4069  m_glfcns.glDisable (GL_POLYGON_OFFSET_LINE);
4070  }
4071 
4072 #else
4073 
4074  octave_unused_parameter (on);
4075  octave_unused_parameter (offset);
4076 
4077  // This shouldn't happen because construction of opengl_renderer
4078  // objects is supposed to be impossible if OpenGL is not available.
4079 
4080  panic_impossible ();
4081 
4082 #endif
4083  }
4084 
4085  void
4087  {
4088 #if defined (HAVE_OPENGL)
4089  // Measure LineWidth in points. See bug #53056.
4091 
4092 #else
4093 
4094  octave_unused_parameter (w);
4095 
4096  // This shouldn't happen because construction of opengl_renderer
4097  // objects is supposed to be impossible if OpenGL is not available.
4098 
4099  panic_impossible ();
4100 
4101 #endif
4102  }
4103 
4104  void
4105  opengl_renderer::set_linestyle (const std::string& s, bool use_stipple,
4106  double linewidth)
4107  {
4108 #if defined (HAVE_OPENGL)
4109  // Measure LineWidth in points. See bug #53056.
4110  int factor = math::round (points_to_pixels (linewidth) * m_devpixratio);
4111  if (factor < 1)
4112  factor = 1;
4113 
4114  uint16_t pattern = 0xFFFF;
4115 
4116  bool solid = false;
4117 
4118  if (s == "-")
4119  solid = true;
4120  else if (s == ":")
4121  {
4122  if (factor > 1)
4123  pattern = 0x5555;
4124  else
4125  pattern = 0x1111;
4126  }
4127  else if (s == "--")
4128  {
4129  if (factor > 1)
4130  pattern = 0x0F0F;
4131  else
4132  pattern = 0x01FF;
4133  }
4134  else if (s == "-.")
4135  {
4136  if (factor > 1)
4137  pattern = 0x6F6F;
4138  else
4139  pattern = 0x18FF;
4140  }
4141  else
4142  pattern = 0x0000;
4143 
4144  m_glfcns.glLineStipple (factor, pattern);
4145 
4146  if (solid && ! use_stipple)
4147  m_glfcns.glDisable (GL_LINE_STIPPLE);
4148  else
4149  m_glfcns.glEnable (GL_LINE_STIPPLE);
4150 
4151 #else
4152 
4153  octave_unused_parameter (s);
4154  octave_unused_parameter (use_stipple);
4155  octave_unused_parameter (linewidth);
4156 
4157  // This shouldn't happen because construction of opengl_renderer
4158  // objects is supposed to be impossible if OpenGL is not available.
4159 
4160  panic_impossible ();
4161 
4162 #endif
4163  }
4164 
4165  void
4166  opengl_renderer::set_clipbox (double x1, double x2, double y1, double y2,
4167  double z1, double z2)
4168  {
4169 #if defined (HAVE_OPENGL)
4170 
4171  double dx = (x2-x1);
4172  double dy = (y2-y1);
4173  double dz = (z2-z1);
4174 
4175  x1 -= 0.001*dx; x2 += 0.001*dx;
4176  y1 -= 0.001*dy; y2 += 0.001*dy;
4177  z1 -= 0.001*dz; z2 += 0.001*dz;
4178 
4179  ColumnVector p (4, 0.0);
4180 
4181  p(0) = -1; p(3) = x2;
4182  m_glfcns.glClipPlane (GL_CLIP_PLANE0, p.data ());
4183  p(0) = 1; p(3) = -x1;
4184  m_glfcns.glClipPlane (GL_CLIP_PLANE1, p.data ());
4185  p(0) = 0; p(1) = -1; p(3) = y2;
4186  m_glfcns.glClipPlane (GL_CLIP_PLANE2, p.data ());
4187  p(1) = 1; p(3) = -y1;
4188  m_glfcns.glClipPlane (GL_CLIP_PLANE3, p.data ());
4189  p(1) = 0; p(2) = -1; p(3) = z2;
4190  m_glfcns.glClipPlane (GL_CLIP_PLANE4, p.data ());
4191  p(2) = 1; p(3) = -z1;
4192  m_glfcns.glClipPlane (GL_CLIP_PLANE5, p.data ());
4193 
4194  xmin = x1; xmax = x2;
4195  ymin = y1; ymax = y2;
4196  zmin = z1; zmax = z2;
4197 
4198 #else
4199 
4200  octave_unused_parameter (x1);
4201  octave_unused_parameter (x2);
4202  octave_unused_parameter (y1);
4203  octave_unused_parameter (y2);
4204  octave_unused_parameter (z1);
4205  octave_unused_parameter (z2);
4206 
4207  // This shouldn't happen because construction of opengl_renderer
4208  // objects is supposed to be impossible if OpenGL is not available.
4209 
4210  panic_impossible ();
4211 
4212 #endif
4213  }
4214 
4215  void
4217  {
4218 #if defined (HAVE_OPENGL)
4219 
4220  bool has_clipping = (m_glfcns.glIsEnabled (GL_CLIP_PLANE0) == GL_TRUE);
4221 
4222  if (enable != has_clipping)
4223  {
4224  if (enable)
4225  for (int i = 0; i < 6; i++)
4226  m_glfcns.glEnable (GL_CLIP_PLANE0+i);
4227  else
4228  for (int i = 0; i < 6; i++)
4229  m_glfcns.glDisable (GL_CLIP_PLANE0+i);
4230  }
4231 
4232 #else
4233 
4234  octave_unused_parameter (enable);
4235 
4236  // This shouldn't happen because construction of opengl_renderer
4237  // objects is supposed to be impossible if OpenGL is not available.
4238 
4239  panic_impossible ();
4240 
4241 #endif
4242  }
4243 
4244  void
4245  opengl_renderer::init_marker (const std::string& m, double size, float width)
4246  {
4247 #if defined (HAVE_OPENGL)
4248  m_glfcns.glMatrixMode (GL_PROJECTION);
4251 
4252  Matrix vp = get_viewport_scaled ();
4253  m_glfcns.glOrtho (0, vp(2), vp(3), 0, xZ1, xZ2);
4254  m_glfcns.glMatrixMode (GL_MODELVIEW);
4256 
4257  set_clipping (false);
4258  set_linewidth (width);
4259 
4260  marker_id = make_marker_list (m, size, false);
4261  filled_marker_id = make_marker_list (m, size, true);
4262 
4263 #else
4264 
4265  octave_unused_parameter (m);
4266  octave_unused_parameter (size);
4267  octave_unused_parameter (width);
4268 
4269  // This shouldn't happen because construction of opengl_renderer
4270  // objects is supposed to be impossible if OpenGL is not available.
4271 
4272  panic_impossible ();
4273 
4274 #endif
4275  }
4276 
4277  void
4279  {
4280 #if defined (HAVE_OPENGL)
4281 
4284 
4285  m_glfcns.glMatrixMode (GL_MODELVIEW);
4286  m_glfcns.glPopMatrix ();
4287  m_glfcns.glMatrixMode (GL_PROJECTION);
4288  m_glfcns.glPopMatrix ();
4289  set_linewidth (0.5f);
4290 
4291 #else
4292 
4293  // This shouldn't happen because construction of opengl_renderer
4294  // objects is supposed to be impossible if OpenGL is not available.
4295 
4296  panic_impossible ();
4297 
4298 #endif
4299  }
4300 
4301  void
4302  opengl_renderer::draw_marker (double x, double y, double z,
4303  const Matrix& lc, const Matrix& fc)
4304  {
4305 #if defined (HAVE_OPENGL)
4306 
4307  ColumnVector tmp = xform.transform (x, y, z, false);
4308 
4310  m_glfcns.glTranslated (tmp(0), tmp(1), -tmp(2));
4311 
4312  if (filled_marker_id > 0 && fc.numel () > 0)
4313  {
4314  m_glfcns.glColor3dv (fc.data ());
4315  set_polygon_offset (true, -1.0);
4317  if (lc.numel () > 0)
4318  {
4319  m_glfcns.glColor3dv (lc.data ());
4320  m_glfcns.glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
4321  m_glfcns.glEdgeFlag (GL_TRUE);
4322  set_polygon_offset (true, -2.0);
4324  m_glfcns.glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
4325  }
4326  set_polygon_offset (false);
4327  }
4328  else if (marker_id > 0 && lc.numel () > 0)
4329  {
4330  m_glfcns.glColor3dv (lc.data ());
4332  }
4333 
4334 #else
4335 
4336  octave_unused_parameter (x);
4337  octave_unused_parameter (y);
4338  octave_unused_parameter (z);
4339  octave_unused_parameter (lc);
4340  octave_unused_parameter (fc);
4341 
4342  // This shouldn't happen because construction of opengl_renderer
4343  // objects is supposed to be impossible if OpenGL is not available.
4344 
4345  panic_impossible ();
4346 
4347 #endif
4348  }
4349 
4350  void
4352  {
4353 #if defined (HAVE_OPENGL)
4354 
4355  // Check actual maximum number of lights possible
4356  if (m_max_lights == 0)
4357  {
4358  GLint max_lights;
4359  m_glfcns.glGetIntegerv (GL_MAX_LIGHTS, &max_lights);
4360  m_max_lights = max_lights;
4361  }
4362 
4363 #else
4364 
4365  // This shouldn't happen because construction of opengl_renderer
4366  // objects is supposed to be impossible if OpenGL is not available.
4367 
4368  panic_impossible ();
4369 
4370 #endif
4371  }
4372 
4373  std::string
4374  opengl_renderer::get_string (unsigned int id) const
4375  {
4376 #if defined (HAVE_OPENGL)
4377 
4378  // This is kind of ugly, but glGetString returns a pointer to GLubyte
4379  // and there is no std::string constructor that matches. Is there a
4380  // better way?
4381 
4382  std::ostringstream buf;
4383 
4384  buf << m_glfcns.glGetString (static_cast<GLenum> (id));
4385 
4386  return std::string (buf.str ());
4387 
4388 #else
4389 
4390  octave_unused_parameter (id);
4391 
4392  // This shouldn't happen because construction of opengl_renderer
4393  // objects is supposed to be impossible if OpenGL is not available.
4394 
4395  panic_impossible ();
4396  return std::string ();
4397 
4398 #endif
4399  }
4400 
4401  void
4402  opengl_renderer::set_normal (int bfl_mode, const NDArray& n, int j, int i)
4403  {
4404 #if defined (HAVE_OPENGL)
4405 
4406  double x = n(j,i,0);
4407  double y = n(j,i,1);
4408  double z = n(j,i,2);
4409 
4410  double d = sqrt (x*x + y*y + z*z);
4411 
4412  double dir = 1.0;
4413 
4414  if (bfl_mode > 0)
4415  dir = ((x * view_vector(0) + y * view_vector(1) + z * view_vector(2) < 0)
4416  ? ((bfl_mode > 1) ? 0.0 : -1.0) : 1.0);
4417 
4418  m_glfcns.glNormal3d (dir*x/d, dir*y/d, dir*z/d);
4419 
4420 #else
4421 
4422  octave_unused_parameter (bfl_mode);
4423  octave_unused_parameter (n);
4424  octave_unused_parameter (j);
4425  octave_unused_parameter (i);
4426 
4427  // This shouldn't happen because construction of opengl_renderer
4428  // objects is supposed to be impossible if OpenGL is not available.
4429 
4430  panic_impossible ();
4431 
4432 #endif
4433  }
4434 
4435  double
4436  opengl_renderer::points_to_pixels (const double val) const
4437  {
4438  gh_manager& gh_mgr = __get_gh_manager__ ("opengl_renderer::points_to_pixels");
4439 
4440  // FIXME: Does making this static cause problems if figure is moved to a
4441  // 2nd monitor with a different value for "screenpixelsperinch"?
4442  static const double pix_per_pts =
4443  gh_mgr.get_object (0).get ("screenpixelsperinch").double_value () / 72.0;
4444 
4445  double retval = val;
4446 
4447  if (! m_printing)
4448  retval *= pix_per_pts;
4449 
4450  return retval;
4451  }
4452 
4453  unsigned int
4454  opengl_renderer::make_marker_list (const std::string& marker, double size,
4455  bool filled) const
4456  {
4457 #if defined (HAVE_OPENGL)
4458 
4459  char c = marker[0];
4460 
4461  if (filled && (c == '+' || c == 'x' || c == '*' || c == '.'))
4462  return 0;
4463 
4464  unsigned int ID = m_glfcns.glGenLists (1);
4465 
4466  // FIXME: See bug #53056 (measure LineWidth in points).
4467  double sz = points_to_pixels (size);
4468 
4469  // constants for the * marker
4470  const double sqrt2d4 = 0.35355339059327;
4471  double tt = sz*sqrt2d4;
4472 
4473  m_glfcns.glNewList (ID, GL_COMPILE);
4474 
4475  switch (marker[0])
4476  {
4477  case '+':
4478  m_glfcns.glBegin (GL_LINES);
4479  m_glfcns.glVertex2d (-sz/2, 0);
4480  m_glfcns.glVertex2d (sz/2, 0);
4481  m_glfcns.glVertex2d (0, -sz/2);
4482  m_glfcns.glVertex2d (0, sz/2);
4483  m_glfcns.glEnd ();
4484  break;
4485  case 'x':
4486  m_glfcns.glBegin (GL_LINES);
4487  m_glfcns.glVertex2d (-sz/2, -sz/2);
4488  m_glfcns.glVertex2d (sz/2, sz/2);
4489  m_glfcns.glVertex2d (-sz/2, sz/2);
4490  m_glfcns.glVertex2d (sz/2, -sz/2);
4491  m_glfcns.glEnd ();
4492  break;
4493  case '*':
4494  m_glfcns.glBegin (GL_LINES);
4495  m_glfcns.glVertex2d (-sz/2, 0);
4496  m_glfcns.glVertex2d (sz/2, 0);
4497  m_glfcns.glVertex2d (0, -sz/2);
4498  m_glfcns.glVertex2d (0, sz/2);
4499  m_glfcns.glVertex2d (-tt, -tt);
4500  m_glfcns.glVertex2d (+tt, +tt);
4501  m_glfcns.glVertex2d (-tt, +tt);
4502  m_glfcns.glVertex2d (+tt, -tt);
4503  m_glfcns.glEnd ();
4504  break;
4505  case '.':
4506  {
4507  // The dot marker is special and is drawn at 1/3rd the specified size
4508 
4509  // Ensure that something is drawn even at very small markersizes
4510  if (sz > 0 && sz < 3)
4511  sz = 3;
4512 
4513  int div = static_cast<int> (M_PI * sz / 12);
4514  if (! (div % 2))
4515  div += 1; // ensure odd number for left/right symmetry
4516  div = std::max (div, 3); // ensure at least a few vertices are drawn
4517  double ang_step = M_PI / div;
4518 
4519  m_glfcns.glBegin (GL_POLYGON);
4520  for (double ang = 0; ang < 2*M_PI; ang += ang_step)
4521  m_glfcns.glVertex2d (sz/6*cos (ang), sz/6*sin (ang));
4522  m_glfcns.glEnd ();
4523  }
4524  break;
4525  case 's':
4526  m_glfcns.glBegin (filled ? GL_POLYGON : GL_LINE_LOOP);
4527  m_glfcns.glVertex2d (-sz/2, -sz/2);
4528  m_glfcns.glVertex2d (-sz/2, sz/2);
4529  m_glfcns.glVertex2d (sz/2, sz/2);
4530  m_glfcns.glVertex2d (sz/2, -sz/2);
4531  m_glfcns.glEnd ();
4532  break;
4533  case 'o':
4534  {
4535  int div = static_cast<int> (M_PI * sz / 4);
4536  if (! (div % 2))
4537  div += 1; // ensure odd number for left/right symmetry
4538  div = std::max (div, 5); // ensure at least a few vertices are drawn
4539  double ang_step = M_PI / div;
4540 
4541  m_glfcns.glBegin (filled ? GL_POLYGON : GL_LINE_LOOP);
4542  for (double ang = 0; ang < 2*M_PI; ang += ang_step)
4543  m_glfcns.glVertex2d (sz/2*cos (ang), sz/2*sin (ang));
4544  m_glfcns.glEnd ();
4545  }
4546  break;
4547  case 'd':
4548  m_glfcns.glBegin (filled ? GL_POLYGON : GL_LINE_LOOP);
4549  m_glfcns.glVertex2d (0, -sz/2);
4550  m_glfcns.glVertex2d (sz/2, 0);
4551  m_glfcns.glVertex2d (0, sz/2);
4552  m_glfcns.glVertex2d (-sz/2, 0);
4553  m_glfcns.glEnd ();
4554  break;
4555  case 'v':
4556  m_glfcns.glBegin (filled ? GL_POLYGON : GL_LINE_LOOP);
4557  m_glfcns.glVertex2d (0, sz/2);
4558  m_glfcns.glVertex2d (sz/2, -sz/2);
4559  m_glfcns.glVertex2d (-sz/2, -sz/2);
4560  m_glfcns.glEnd ();
4561  break;
4562  case '^':
4563  m_glfcns.glBegin (filled ? GL_POLYGON : GL_LINE_LOOP);
4564  m_glfcns.glVertex2d (0, -sz/2);
4565  m_glfcns.glVertex2d (-sz/2, sz/2);
4566  m_glfcns.glVertex2d (sz/2, sz/2);
4567  m_glfcns.glEnd ();
4568  break;
4569  case '>':
4570  m_glfcns.glBegin (filled ? GL_POLYGON : GL_LINE_LOOP);
4571  m_glfcns.glVertex2d (sz/2, 0);
4572  m_glfcns.glVertex2d (-sz/2, sz/2);
4573  m_glfcns.glVertex2d (-sz/2, -sz/2);
4574  m_glfcns.glEnd ();
4575  break;
4576  case '<':
4577  m_glfcns.glBegin (filled ? GL_POLYGON : GL_LINE_LOOP);
4578  m_glfcns.glVertex2d (-sz/2, 0);
4579  m_glfcns.glVertex2d (sz/2, -sz/2);
4580  m_glfcns.glVertex2d (sz/2, sz/2);
4581  m_glfcns.glEnd ();
4582  break;
4583  case 'p':
4584  {
4585  double ang, r, dr;
4586  dr = 1.0 - sin (M_PI/10)/sin (3*M_PI/10)*1.02;
4587 
4588  m_glfcns.glBegin (filled ? GL_POLYGON : GL_LINE_LOOP);
4589  for (int i = 0; i < 2*5; i++)
4590  {
4591  ang = (-0.5 + double (i+1) / 5) * M_PI;
4592  r = 1.0 - (dr * fmod (double (i+1), 2.0));
4593  m_glfcns.glVertex2d (sz/2*r*cos (ang), sz/2*r*sin (ang));
4594  }
4595  m_glfcns.glEnd ();
4596  }
4597  break;
4598  case 'h':
4599  {
4600  double ang, r, dr;
4601  dr = 1.0 - 0.5/sin (M_PI/3)*1.02;
4602 
4603  m_glfcns.glBegin (filled ? GL_POLYGON : GL_LINE_LOOP);
4604  for (int i = 0; i < 2*6; i++)
4605  {
4606  ang = (0.5 + double (i+1) / 6.0) * M_PI;
4607  r = 1.0 - (dr * fmod (double (i+1), 2.0));
4608  m_glfcns.glVertex2d (sz/2*r*cos (ang), sz/2*r*sin (ang));
4609  }
4610  m_glfcns.glEnd ();
4611  }
4612  break;
4613  default:
4614  warning ("opengl_renderer: unsupported marker '%s'", marker.c_str ());
4615  break;
4616  }
4617 
4618  m_glfcns.glEndList ();
4619 
4620  return ID;
4621 
4622 #else
4623 
4624  octave_unused_parameter (marker);
4625  octave_unused_parameter (size);
4626  octave_unused_parameter (filled);
4627 
4628  // This shouldn't happen because construction of opengl_renderer
4629  // objects is supposed to be impossible if OpenGL is not available.
4630 
4631  panic_impossible ();
4632 
4633 #endif
4634  }
4635 
4636  void
4637  opengl_renderer::text_to_pixels (const std::string& txt,
4638  uint8NDArray& pixels,
4639  Matrix& bbox,
4640  int halign, int valign, double rotation)
4641  {
4642  txt_renderer.text_to_pixels (txt, pixels, bbox, halign, valign,
4643  rotation, interpreter);
4644  }
4645 
4646  void
4647  opengl_renderer::text_to_strlist (const std::string& txt,
4648  std::list<text_renderer::string>& lst,
4649  Matrix& bbox,
4650  int halign, int valign, double rotation)
4651  {
4652  txt_renderer.text_to_strlist (txt, lst, bbox, halign, valign,
4653  rotation, interpreter);
4654  }
4655 
4656  Matrix
4657  opengl_renderer::render_text (const std::string& txt,
4658  double x, double y, double z,
4659  int halign, int valign, double rotation)
4660  {
4661 #if defined (HAVE_OPENGL)
4662 
4663  Matrix bbox (1, 4, 0.0);
4664 
4665  if (txt.empty ())
4666  return bbox;
4667 
4668  if (txt_renderer.ok ())
4669  {
4670  uint8NDArray pixels;
4671  text_to_pixels (txt, pixels, bbox, halign, valign, rotation);
4672 
4673  bool blend = m_glfcns.glIsEnabled (GL_BLEND);
4674 
4675  m_glfcns.glEnable (GL_BLEND);
4676  m_glfcns.glEnable (GL_ALPHA_TEST);
4677  m_glfcns.glRasterPos3d (x, y, z);
4678  m_glfcns.glBitmap(0, 0, 0, 0, bbox(0), bbox(1), nullptr);
4679  m_glfcns.glDrawPixels (bbox(2), bbox(3),
4680  GL_RGBA, GL_UNSIGNED_BYTE, pixels.data ());
4681  m_glfcns.glDisable (GL_ALPHA_TEST);
4682 
4683  if (! blend)
4684  m_glfcns.glDisable (GL_BLEND);
4685  }
4686 
4687  return bbox;
4688 
4689 #else
4690 
4691  octave_unused_parameter (txt);
4692  octave_unused_parameter (x);
4693  octave_unused_parameter (y);
4694  octave_unused_parameter (z);
4695  octave_unused_parameter (halign);
4696  octave_unused_parameter (valign);
4697  octave_unused_parameter (rotation);
4698 
4699  // This shouldn't happen because construction of opengl_renderer
4700  // objects is supposed to be impossible if OpenGL is not available.
4701 
4702  panic_impossible ();
4703 
4704 #endif
4705  }
4706 }
#define loc(X, Y)
Definition: Screen.cpp:56
charNDArray max(char d, const charNDArray &m)
Definition: chNDArray.cc:230
charNDArray min(char d, const charNDArray &m)
Definition: chNDArray.cc:207
octave_idx_type columns(void) const
Definition: Array.h:424
octave_idx_type numel(void) const
Number of elements in the array.
Definition: Array.h:377
const T * data(void) const
Size of the specified dimension.
Definition: Array.h:581
octave_idx_type rows(void) const
Definition: Array.h:415
const dim_vector & dims(void) const
Return a const-reference so that dims ()(i) works efficiently.
Definition: Array.h:453
const T * fortran_vec(void) const
Size of the specified dimension.
Definition: Array.h:583
bool isempty(void) const
Size of the specified dimension.
Definition: Array.h:572
MArray< T > permute(const Array< octave_idx_type > &vec, bool inv=false) const
Definition: MArray.h:96
Definition: dMatrix.h:42
void resize(octave_idx_type nr, octave_idx_type nc, double rfv=0)
Definition: dMatrix.h:151
double get_yticklen(void) const
Definition: graphics.in.h:3514
double get_ypTickN(void) const
Definition: graphics.in.h:3501
bool get_y2Dright(void) const
Definition: graphics.in.h:3520
double get_yPlaneN(void) const
Definition: graphics.in.h:3495
double get_zPlane(void) const
Definition: graphics.in.h:3496
graphics_xform get_transform(void) const
Definition: graphics.in.h:3480
bool get_zSign(void) const
Definition: graphics.in.h:3527
double get_yPlane(void) const
Definition: graphics.in.h:3494
unsigned int get_num_lights(void) const
Definition: graphics.in.h:3569
double get_xPlaneN(void) const
Definition: graphics.in.h:3493
double get_ypTick(void) const
Definition: graphics.in.h:3500
bool get_layer2Dtop(void) const
Definition: graphics.in.h:3521
double get_y_min(void) const
Definition: graphics.in.h:3506
double get_xpTickN(void) const
Definition: graphics.in.h:3499
bool get_is2D(bool include_kids=false) const
Definition: graphics.in.h:3522
int get_xstate(void) const
Definition: graphics.in.h:3489
double get_xpTick(void) const
Definition: graphics.in.h:3498
double get_zpTickN(void) const
Definition: graphics.in.h:3503
double get_fz(void) const
Definition: graphics.in.h:3512
double get_zpTick(void) const
Definition: graphics.in.h:3502
Matrix get_opengl_matrix_2(void) const
Definition: graphics.in.h:3486
Matrix get_opengl_matrix_1(void) const
Definition: graphics.in.h:3485
double get_zticklen(void) const
Definition: graphics.in.h:3515
double get_xtickoffset(void) const
Definition: graphics.in.h:3516
double get_z_min(void) const
Definition: graphics.in.h:3508
double get_fy(void) const
Definition: graphics.in.h:3511
bool get_xyzSym(void) const
Definition: graphics.in.h:3526
double get_x_max(void) const
Definition: graphics.in.h:3505
bool get_nearhoriz(void) const
Definition: graphics.in.h:3528
double get_y_max(void) const
Definition: graphics.in.h:3507
double get_z_max(void) const
Definition: graphics.in.h:3509
double get_x_min(void) const
Definition: graphics.in.h:3504
bool get_x2Dtop(void) const
Definition: graphics.in.h:3519
double get_fx(void) const
Definition: graphics.in.h:3510
double get_ztickoffset(void) const
Definition: graphics.in.h:3518
int get_zstate(void) const
Definition: graphics.in.h:3491
int get_ystate(void) const
Definition: graphics.in.h:3490
double get_zPlaneN(void) const
Definition: graphics.in.h:3497
double get_ytickoffset(void) const
Definition: graphics.in.h:3517
bool get_xySym(void) const
Definition: graphics.in.h:3525
double get_xticklen(void) const
Definition: graphics.in.h:3513
Matrix get_transform_zlim(void) const
Definition: graphics.in.h:3487
double get_xPlane(void) const
Definition: graphics.in.h:3492
Matrix get_children(void) const
Definition: graphics.in.h:2292
virtual octave::graphics_toolkit get_toolkit(void) const
Definition: graphics.cc:3512
Matrix get_all_children(void) const
Definition: graphics.in.h:2297
virtual bool has_property(const caseless_str &) const
Definition: graphics.in.h:2241
virtual octave_value get(const caseless_str &pname) const
virtual std::string graphics_object_name(void) const
Definition: graphics.in.h:2197
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:95
octave_idx_type ndims(void) const
Number of dimensions.
Definition: dim-vector.h:334
graphics_object get_object(double val) const
Definition: graphics.in.h:6260
octave_value get(bool all=false) const
Definition: graphics.in.h:2746
void set(const caseless_str &name, const octave_value &val)
Definition: graphics.in.h:2729
graphics_object get_ancestor(const std::string &type) const
Definition: graphics.cc:3905
bool isa(const std::string &go_name) const
Definition: graphics.in.h:2827
base_properties & get_properties(void)
Definition: graphics.in.h:2829
bool valid_object(void) const
Definition: graphics.in.h:2847
Matrix zscale(const Matrix &m) const
Definition: graphics.in.h:3390
Matrix yscale(const Matrix &m) const
Definition: graphics.in.h:3389
Matrix xscale(const Matrix &m) const
Definition: graphics.in.h:3388
Matrix scale(const Matrix &m) const
Definition: graphics.in.h:3392
ColumnVector transform(double x, double y, double z, bool use_scale=true) const
Definition: graphics.cc:7378
static const idx_vector colon
Definition: idx-vector.h:499
static idx_vector make_range(octave_idx_type start, octave_idx_type step, octave_idx_type len)
Definition: idx-vector.h:483
octave_value get_color_data(void) const
Definition: graphics.cc:9567
virtual void glBindTexture(GLenum target, GLuint texture)
Definition: oct-opengl.h:83
virtual void glPolygonMode(GLenum face, GLenum mode)
Definition: oct-opengl.h:330
virtual void glMultMatrixd(const GLdouble *m)
Definition: oct-opengl.h:294
virtual void glEnd(void)
Definition: oct-opengl.h:194
virtual void glBegin(GLenum mode)
Definition: oct-opengl.h:78
virtual void glDisable(GLenum cap)
Definition: oct-opengl.h:168
virtual void glNormal3dv(const GLdouble *v)
Definition: oct-opengl.h:309
virtual void glGenTextures(GLsizei n, GLuint *textures)
Definition: oct-opengl.h:209
virtual void glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
Definition: oct-opengl.h:105
virtual void glPolygonOffset(GLfloat factor, GLfloat units)
Definition: oct-opengl.h:335
virtual void glOrtho(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near_val, GLdouble far_val)
Definition: oct-opengl.h:314
virtual void glVertex2d(GLdouble x, GLdouble y)
Definition: oct-opengl.h:439
virtual void glDepthFunc(GLenum func)
Definition: oct-opengl.h:163
virtual void glPixelStorei(GLenum pname, GLint param)
Definition: oct-opengl.h:320
virtual void glBitmap(GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte *bitmap)
Definition: oct-opengl.h:88
virtual void glColor3dv(const GLdouble *v)
Definition: oct-opengl.h:121
virtual void glLineStipple(GLint factor, GLushort pattern)
Definition: oct-opengl.h:264
virtual void glColor4d(GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha)
Definition: oct-opengl.h:136
virtual void glShadeModel(GLenum mode)
Definition: oct-opengl.h:406
virtual void glMaterialfv(GLenum face, GLenum pname, const GLfloat *params)
Definition: oct-opengl.h:284
virtual void glAlphaFunc(GLenum func, GLclampf ref)
Definition: oct-opengl.h:73
virtual void glBlendFunc(GLenum sfactor, GLenum dfactor)
Definition: oct-opengl.h:95
virtual void glGetIntegerv(GLenum pname, GLint *data)
Definition: oct-opengl.h:234
virtual void glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels)
Definition: oct-opengl.h:375
virtual const GLubyte * glGetString(GLenum name)
Definition: oct-opengl.h:239
virtual GLboolean glIsEnabled(GLenum cap)
Definition: oct-opengl.h:254
virtual void glClipPlane(GLenum plane, const GLdouble *equation)
Definition: oct-opengl.h:116
virtual void glColor3f(GLfloat red, GLfloat green, GLfloat blue)
Definition: oct-opengl.h:126
virtual void glEdgeFlag(GLboolean flag)
Definition: oct-opengl.h:179
virtual void glViewport(GLint x, GLint y, GLsizei width, GLsizei height)
Definition: oct-opengl.h:454
virtual void glPopMatrix(void)
Definition: oct-opengl.h:345
virtual void glScaled(GLdouble x, GLdouble y, GLdouble z)
Definition: oct-opengl.h:391
virtual void glGetBooleanv(GLenum pname, GLboolean *data)
Definition: oct-opengl.h:214
virtual void glLineWidth(GLfloat width)
Definition: oct-opengl.h:269
virtual void glEnable(GLenum cap)
Definition: oct-opengl.h:184
virtual void glPushAttrib(GLbitfield mask)
Definition: oct-opengl.h:355
virtual void glVertex3d(GLdouble x, GLdouble y, GLdouble z)
Definition: oct-opengl.h:444
virtual void glDeleteLists(GLuint list, GLsizei range)
Definition: oct-opengl.h:153
virtual void glTexImage2D(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels)
Definition: oct-opengl.h:416
virtual void glDrawPixels(GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels)
Definition: oct-opengl.h:173
virtual void glCallList(GLuint list)
Definition: oct-opengl.h:100
virtual GLuint glGenLists(GLsizei range)
Definition: oct-opengl.h:204
virtual void glEndList(void)
Definition: oct-opengl.h:189
virtual void glLoadIdentity(void)
Definition: oct-opengl.h:274
virtual void glNewList(GLuint list, GLenum mode)
Definition: oct-opengl.h:299
virtual void glTranslated(GLdouble x, GLdouble y, GLdouble z)
Definition: oct-opengl.h:429
virtual void glFinish(void)
Definition: oct-opengl.h:199
virtual void glColor4f(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)
Definition: oct-opengl.h:142
virtual void glRasterPos3d(GLdouble x, GLdouble y, GLdouble z)
Definition: oct-opengl.h:370
virtual void glPopAttrib(void)
Definition: oct-opengl.h:340
virtual GLenum glGetError(void)
Definition: oct-opengl.h:224
virtual void glHint(GLenum target, GLenum mode)
Definition: oct-opengl.h:244
virtual void glRotated(GLdouble angle, GLdouble x, GLdouble y, GLdouble z)
Definition: oct-opengl.h:386
virtual void glMaterialf(GLenum face, GLenum pname, GLfloat param)
Definition: oct-opengl.h:279
virtual void glMatrixMode(GLenum mode)
Definition: oct-opengl.h:289
virtual void glNormal3d(GLdouble nx, GLdouble ny, GLdouble nz)
Definition: oct-opengl.h:304
virtual void glColor3fv(const GLfloat *v)
Definition: oct-opengl.h:131
virtual void glColor4fv(const GLfloat *v)
Definition: oct-opengl.h:148
virtual void glPushMatrix(void)
Definition: oct-opengl.h:360
virtual void glTexParameteri(GLenum target, GLenum pname, GLint param)
Definition: oct-opengl.h:424
virtual void glClear(GLbitfield mask)
Definition: oct-opengl.h:111
virtual void glVertex3dv(const GLdouble *v)
Definition: oct-opengl.h:449
virtual void glLightfv(GLenum light, GLenum pname, const GLfloat *params)
Definition: oct-opengl.h:259
patch_tessellator(const patch_tessellator &)=delete
void combine(GLdouble xyz[3], void *data[4], GLfloat w[4], void **out_data)
Definition: gl-render.cc:603
std::list< vertex_data > tmp_vdata
Definition: gl-render.cc:675
patch_tessellator(opengl_renderer *r, int cmode, int lmode, bool fl, float idx=0.0)
Definition: gl-render.cc:517
unsigned int filled_marker_id
Definition: gl-render.h:228
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)
Definition: gl-render.cc:4647
virtual void end_marker(void)
Definition: gl-render.cc:4278
virtual void draw_hggroup(const hggroup::properties &props)
Definition: gl-render.cc:3735
virtual void draw_surface(const surface::properties &props)
Definition: gl-render.cc:2510
virtual void draw_text_background(const text::properties &props, bool do_rotate=false)
Definition: gl-render.cc:3788
virtual void set_interpreter(const caseless_str &interp)
Definition: gl-render.h:102
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)
Definition: gl-render.cc:981
void draw_axes_grids(const axes::properties &props)
Definition: gl-render.cc:2118
virtual void set_clipbox(double x1, double x2, double y1, double y2, double z1, double z2)
Definition: gl-render.cc:4166
bool is_nan_or_inf(double x, double y, double z) const
Definition: gl-render.h:165
virtual void draw_text(const text::properties &props)
Definition: gl-render.cc:3741
opengl_functions & m_glfcns
Definition: gl-render.h:206
void draw_axes_boxes(const axes::properties &props)
Definition: gl-render.cc:1377
virtual void draw_line(const line::properties &props)
Definition: gl-render.cc:2364
virtual Matrix render_text(const std::string &txt, double x, double y, double z, int halign, int valign, double rotation=0.0)
Definition: gl-render.cc:4657
unsigned int m_max_lights
Definition: gl-render.h:240
void draw_all_lights(const base_properties &props, std::list< graphics_object > &obj_list)
Definition: gl-render.cc:2153
void draw_axes_children(const axes::properties &props)
Definition: gl-render.cc:2201
virtual void set_linewidth(float w)
Definition: gl-render.cc:4086
virtual void set_linejoin(const std::string &)
Definition: gl-render.h:110
virtual void draw_uibuttongroup(const uibuttongroup::properties &props, const graphics_object &go)
Definition: gl-render.cc:817
virtual void draw_axes(const axes::properties &props)
Definition: gl-render.cc:2292
virtual void draw(const graphics_object &go, bool toplevel=true)
Definition: gl-render.cc:717
unsigned int m_current_light
Definition: gl-render.h:239
void draw_axes_z_grid(const axes::properties &props)
Definition: gl-render.cc:1932
void draw_axes_planes(const axes::properties &props)
Definition: gl-render.cc:1317
virtual void init_gl_context(bool enhanced, const Matrix &backgroundColor)
Definition: gl-render.cc:835
ColumnVector view_vector
Definition: gl-render.h:231
virtual uint8NDArray get_pixels(int width, int height)
Definition: gl-render.cc:1218
virtual void set_polygon_offset(bool on, float offset=0.0f)
Definition: gl-render.cc:4056
virtual void init_marker(const std::string &m, double size, float width)
Definition: gl-render.cc:4245
virtual void draw_patch(const patch::properties &props)
Definition: gl-render.cc:3159
virtual graphics_xform get_transform(void) const
Definition: gl-render.h:66
virtual void set_linestyle(const std::string &s, bool stipple=false, double linewidth=0.5)
Definition: gl-render.cc:4105
virtual void set_font(const base_properties &props)
Definition: gl-render.cc:4044
void draw_axes_y_grid(const axes::properties &props)
Definition: gl-render.cc:1734
virtual void draw_image(const image::properties &props)
Definition: gl-render.cc:3888
virtual void text_to_pixels(const std::string &txt, uint8NDArray &pixels, Matrix &bbox, int halign=0, int valign=0, double rotation=0.0)
Definition: gl-render.cc:4637
uint8_t clip_code(double x, double y, double z) const
Definition: gl-render.h:173
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)
Definition: gl-render.cc:1057
virtual void draw_marker(double x, double y, double z, const Matrix &lc, const Matrix &fc)
Definition: gl-render.cc:4302
unsigned int make_marker_list(const std::string &m, double size, bool filled) const
Definition: gl-render.cc:4454
std::string get_string(unsigned int id) const
Definition: gl-render.cc:4374
text_renderer txt_renderer
Definition: gl-render.h:236
virtual void set_viewport(int w, int h)
Definition: gl-render.cc:3973
graphics_toolkit toolkit
Definition: gl-render.h:222
void set_normal(int bfl_mode, const NDArray &n, int j, int i)
Definition: gl-render.cc:4402
opengl_renderer(opengl_functions &glfcns)
Definition: gl-render.cc:688
virtual void set_linecap(const std::string &)
Definition: gl-render.h:109
virtual void set_clipping(bool on)
Definition: gl-render.cc:4216
virtual void set_color(const Matrix &c)
Definition: gl-render.cc:4022
graphics_xform xform
Definition: gl-render.h:217
virtual void setup_opengl_transformation(const axes::properties &props)
Definition: gl-render.cc:1272
void draw_axes_x_grid(const axes::properties &props)
Definition: gl-render.cc:1537
double points_to_pixels(const double val) const
Definition: gl-render.cc:4436
unsigned int marker_id
Definition: gl-render.h:228
virtual void draw_uipanel(const uipanel::properties &props, const graphics_object &go)
Definition: gl-render.cc:799
virtual void draw_light(const light::properties &props)
Definition: gl-render.cc:3698
virtual void finish(void)
Definition: gl-render.cc:1255
virtual void draw_figure(const figure::properties &props)
Definition: gl-render.cc:777
virtual void render_grid(const double linewidth, const std::string &gridstyle, const Matrix &gridcolor, const double gridalpha, const Matrix &ticks, double lim1, double lim2, double p1, double p1N, double p2, double p2N, int xyz, bool is_3D)
Definition: gl-render.cc:905
virtual Matrix get_viewport_scaled(void) const
Definition: gl-render.cc:3993
virtual void draw_zoom_box(int width, int height, int x1, int y1, int x2, int y2, const Matrix &overlaycolor, double overlayalpha, const Matrix &bordercolor, double borderalpha, double borderwidth)
Definition: gl-render.cc:1153
virtual void draw_zoom_rect(int x1, int y1, int x2, int y2)
Definition: gl-render.cc:1127
virtual ~opengl_tessellator(void)
Definition: gl-render.cc:346
static void tess_vertex(void *v, void *t)
Definition: gl-render.cc:411
virtual void vertex(void *)
Definition: gl-render.cc:374
void end_polygon(void) const
Definition: gl-render.cc:357
static void tess_combine(GLdouble c[3], void *v[4], GLfloat w[4], void **out, void *t)
Definition: gl-render.cc:414
static void tess_end(void *t)
Definition: gl-render.cc:408
virtual void init(void)
Definition: gl-render.cc:384
virtual void edge_flag(GLboolean)
Definition: gl-render.cc:379
static void tess_edge_flag(GLboolean flag, void *t)
Definition: gl-render.cc:418
void begin_polygon(bool filled=true)
Definition: gl-render.cc:349
virtual void combine(GLdouble[3], void *[4], GLfloat[4], void **)
Definition: gl-render.cc:376
static void tess_begin(GLenum type, void *t)
Definition: gl-render.cc:405
static void tess_error(GLenum err, void *t)
Definition: gl-render.cc:421
virtual void end(void)
Definition: gl-render.cc:372
GLUtesselator * glu_tess
Definition: gl-render.cc:426
virtual void error(GLenum err)
Definition: gl-render.cc:381
void add_vertex(double *loc, void *data) const
Definition: gl-render.cc:366
void begin_contour(void) const
Definition: gl-render.cc:360
opengl_tessellator(const opengl_tessellator &)=delete
virtual void begin(GLenum)
Definition: gl-render.cc:370
bool is_filled(void) const
Definition: gl-render.cc:402
void end_contour(void) const
Definition: gl-render.cc:363
texture_rep(opengl_functions &glfcns, GLuint id_arg, int w_arg, int h_arg, int tw_arg, int th_arg)
Definition: gl-render.cc:108
void tex_coord(double q, double r) const
Definition: gl-render.cc:124
texture_rep(opengl_functions &glfcns)
Definition: gl-render.cc:103
refcount< octave_idx_type > count
Definition: gl-render.cc:133
opengl_texture(opengl_functions &glfcns)
Definition: gl-render.cc:142
bool is_valid(void) const
Definition: gl-render.cc:180
opengl_texture(texture_rep *_rep)
Definition: gl-render.cc:139
opengl_texture(const opengl_texture &tx)
Definition: gl-render.cc:145
texture_rep * rep
Definition: gl-render.cc:136
static opengl_texture create(opengl_functions &glfcns, const octave_value &data)
Definition: gl-render.cc:185
void tex_coord(double q, double r) const
Definition: gl-render.cc:177
void bind(int mode=GL_TEXTURE_2D) const
Definition: gl-render.cc:174
void set_anti_aliasing(bool val)
bool ok(void) const
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")
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)
void set_color(const Matrix &c)
void set_font(const std::string &name, const std::string &weight, const std::string &angle, double size)
vertex_data_rep(const Matrix &c, const Matrix &col, const Matrix &vn, const Matrix &fn, double a, float as, float ds, float ss, float se, float scr)
Definition: gl-render.cc:456
refcount< octave_idx_type > count
Definition: gl-render.cc:449
vertex_data(vertex_data_rep *new_rep)
Definition: gl-render.cc:487
vertex_data(const Matrix &c, const Matrix &col, const Matrix &vn, const Matrix &fn, double a, float as, float ds, float ss, float se, float scr)
Definition: gl-render.cc:481
vertex_data(const vertex_data &v)
Definition: gl-render.cc:478
vertex_data_rep * nil_rep(void) const
Definition: gl-render.cc:467
vertex_data_rep * get_rep(void) const
Definition: gl-render.cc:510
vertex_data_rep * rep
Definition: gl-render.cc:465
uint16NDArray uint16_array_value(void) const
Definition: ov.h:918
bool is_uint16_type(void) const
Definition: ov.h:674
bool is_double_type(void) const
Definition: ov.h:648
uint8NDArray uint8_array_value(void) const
Definition: ov.h:915
std::string string_value(bool force=false) const
Definition: ov.h:927
NDArray array_value(bool frc_str_conv=false) const
Definition: ov.h:812
bool is_single_type(void) const
Definition: ov.h:651
FloatNDArray float_array_value(bool frc_str_conv=false) const
Definition: ov.h:815
bool is_uint8_type(void) const
Definition: ov.h:671
Matrix matrix_value(bool frc_str_conv=false) const
Definition: ov.h:806
double double_value(bool frc_str_conv=false) const
Definition: ov.h:794
dim_vector dims(void) const
Definition: ov.h:500
bool has_bad_data(std::string &msg) const
Definition: graphics.in.h:4820
octave_value get_color_data(void) const
Definition: graphics.cc:9618
std::vector< std::vector< octave_idx_type > > coplanar_last_idx
Definition: graphics.in.h:4838
bool get_do_lighting(void) const
Definition: graphics.cc:9604
octave_idx_type numel(void) const
Definition: str-vec.h:100
octave_value get_color_data(void) const
Definition: graphics.cc:10209
bool get_do_lighting(void) const
Definition: graphics.cc:10215
void warning(const char *fmt,...)
Definition: error.cc:1050
void warning_with_id(const char *id, const char *fmt,...)
Definition: error.cc:1065
void error(const char *fmt,...)
Definition: error.cc:968
#define panic_impossible()
Definition: error.h:380
void err_disabled_feature(const std::string &fcn, const std::string &feature, const std::string &pkg)
Definition: errwarn.cc:53
#define LIGHT_MODE
Definition: gl-render.cc:62
#define CALLBACK
Definition: gl-render.cc:93
void xform(ColumnVector &v, const Matrix &m)
Definition: graphics.cc:5858
@ AXE_ANY_DIR
Definition: graphics.in.h:3424
@ AXE_DEPTH_DIR
Definition: graphics.in.h:3425
@ AXE_HORZ_DIR
Definition: graphics.in.h:3426
@ AXE_VERT_DIR
Definition: graphics.in.h:3427
F77_RET_T const F77_DBLE const F77_DBLE F77_DBLE * d
F77_RET_T const F77_DBLE * x
T octave_idx_type m
Definition: mx-inlines.cc:773
octave_idx_type n
Definition: mx-inlines.cc:753
T * r
Definition: mx-inlines.cc:773
std::complex< double > w(std::complex< double > z, double relerr=0)
double signum(double x)
Definition: lo-mappers.h:222
T max(T x, T y)
Definition: lo-mappers.h:361
bool isfinite(double x)
Definition: lo-mappers.h:192
bool isnan(bool)
Definition: lo-mappers.h:178
bool isinf(double x)
Definition: lo-mappers.h:203
double round(double x)
Definition: lo-mappers.h:136
T min(T x, T y)
Definition: lo-mappers.h:354
static int next_power_of_2(int n)
Definition: gl-render.cc:52
gh_manager & __get_gh_manager__(const std::string &who)
static double f(double k, double l_nu, double c_pm)
Definition: randpoisson.cc:118
@ GOURAUD
Definition: gl-render.cc:86
@ NONE
Definition: gl-render.cc:84
@ FLAT
Definition: gl-render.cc:76
@ INTERP
Definition: gl-render.cc:77
@ TEXTURE
Definition: gl-render.cc:78
@ UNIFORM
Definition: gl-render.cc:75
@ Z_AXIS
Definition: gl-render.cc:69
@ Y_AXIS
Definition: gl-render.cc:68
@ X_AXIS
Definition: gl-render.cc:67
octave_int< T > xmin(const octave_int< T > &x, const octave_int< T > &y)
octave_int< T > xmax(const octave_int< T > &x, const octave_int< T > &y)
#define OCTAVE_LOCAL_BUFFER(T, buf, size)
Definition: oct-locbuf.h:44
octave_value::octave_value(const Array< char > &chm, char type) return retval
Definition: ov.cc:811
F77_RET_T len
Definition: xerbla.cc:61