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