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