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