GNU Octave  4.0.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
gl-render.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 2008-2015 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 the
9 Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
11 
12 Octave is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 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 <http://www.gnu.org/licenses/>.
20 
21 */
22 
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26 
27 #if defined (HAVE_OPENGL)
28 
29 #include <iostream>
30 
31 #include <lo-mappers.h>
32 #include "oct-locbuf.h"
33 #include "oct-refcount.h"
34 #include "gl-render.h"
35 #include "txt-eng.h"
36 #include "txt-eng-ft.h"
37 
38 #define LIGHT_MODE GL_FRONT_AND_BACK
39 
40 // Use symbolic names for axes
41 enum
42 {
43  X_AXIS,
44  Y_AXIS,
45  Z_AXIS
46 };
47 
48 // Use symbolic names for color mode
49 enum
50 {
51  UNIFORM,
52  FLAT,
53  INTERP,
54  TEXTURE
55 };
56 
57 // Use symbolic names for lighting
58 enum
59 {
60  NONE,
61  //FLAT, // Already declared in anonymous enum for color mode
62  GOURAUD = 2
63 };
64 
65 // Win32 API requires the CALLBACK attributes for
66 // GLU callback functions. Define it to empty on
67 // other platforms.
68 #ifndef CALLBACK
69 #define CALLBACK
70 #endif
71 
72 class
73 opengl_texture
74 {
75 protected:
76  class texture_rep
77  {
78  public:
79  texture_rep (void)
80  : id (), w (), h (), tw (), th (), tx (), ty (),
81  valid (false), count (1)
82  { }
83 
84  texture_rep (GLuint id_arg, int w_arg, int h_arg, int tw_arg, int th_arg)
85  : id (id_arg), w (w_arg), h (h_arg), tw (tw_arg), th (th_arg),
86  tx (double(w)/tw), ty (double(h)/th), valid (true),
87  count (1) { }
88 
89  ~texture_rep (void)
90  {
91  if (valid)
92  glDeleteTextures (1, &id);
93  }
94 
95  void bind (int mode) const
96  { if (valid) glBindTexture (mode, id); }
97 
98  void tex_coord (double q, double r) const
99  { if (valid) glTexCoord2d (q*tx, r*ty); }
100 
101  GLuint id;
102  int w, h;
103  int tw, th;
104  double tx, ty;
105  bool valid;
106  octave_refcount<int> count;
107  };
108 
109  texture_rep *rep;
110 
111 private:
112  opengl_texture (texture_rep *_rep) : rep (_rep) { }
113 
114 public:
115  opengl_texture (void) : rep (new texture_rep ()) { }
116 
117  opengl_texture (const opengl_texture& tx)
118  : rep (tx.rep)
119  {
120  rep->count++;
121  }
122 
123  ~opengl_texture (void)
124  {
125  if (--rep->count == 0)
126  delete rep;
127  }
128 
129  opengl_texture& operator = (const opengl_texture& tx)
130  {
131  if (--rep->count == 0)
132  delete rep;
133 
134  rep = tx.rep;
135  rep->count++;
136 
137  return *this;
138  }
139 
140  static opengl_texture create (const octave_value& data);
141 
142  void bind (int mode = GL_TEXTURE_2D) const
143  { rep->bind (mode); }
144 
145  void tex_coord (double q, double r) const
146  { rep->tex_coord (q, r); }
147 
148  bool is_valid (void) const
149  { return rep->valid; }
150 };
151 
152 static int
153 next_power_of_2 (int n)
154 {
155  int m = 1;
156 
157  while (m < n && m < std::numeric_limits<int>::max ())
158  m <<= 1;
159 
160  return m;
161 }
162 
163 opengl_texture
164 opengl_texture::create (const octave_value& data)
165 {
166  opengl_texture retval;
167 
168  dim_vector dv (data.dims ());
169 
170  // Expect RGB data
171  if (dv.length () == 3 && dv(2) == 3)
172  {
173  // FIXME: dim_vectors hold octave_idx_type values.
174  // Should we check for dimensions larger than intmax?
175  int h, w, tw, th;
176  h = dv(0), w = dv(1);
177  GLuint id;
178  bool ok = true;
179 
180  tw = next_power_of_2 (w);
181  th = next_power_of_2 (h);
182 
183  glGenTextures (1, &id);
184  glBindTexture (GL_TEXTURE_2D, id);
185 
186  if (data.is_double_type ())
187  {
188  const NDArray xdata = data.array_value ();
189 
190  OCTAVE_LOCAL_BUFFER (float, a, (3*tw*th));
191 
192  for (int i = 0; i < h; i++)
193  {
194  for (int j = 0, idx = i*tw*3; j < w; j++, idx += 3)
195  {
196  a[idx] = xdata(i,j,0);
197  a[idx+1] = xdata(i,j,1);
198  a[idx+2] = xdata(i,j,2);
199  }
200  }
201 
202  glTexImage2D (GL_TEXTURE_2D, 0, 3, tw, th, 0, GL_RGB, GL_FLOAT, a);
203  }
204  else if (data.is_uint8_type ())
205  {
206  const uint8NDArray xdata = data.uint8_array_value ();
207 
208  OCTAVE_LOCAL_BUFFER (octave_uint8, a, (3*tw*th));
209 
210  for (int i = 0; i < h; i++)
211  {
212  for (int j = 0, idx = i*tw*3; j < w; j++, idx += 3)
213  {
214  a[idx] = xdata(i,j,0);
215  a[idx+1] = xdata(i,j,1);
216  a[idx+2] = xdata(i,j,2);
217  }
218  }
219 
220  glTexImage2D (GL_TEXTURE_2D, 0, 3, tw, th, 0,
221  GL_RGB, GL_UNSIGNED_BYTE, a);
222  }
223  else
224  {
225  ok = false;
226  warning ("opengl_texture::create: invalid texture data type (expected double or uint8)");
227  }
228 
229  if (ok)
230  {
231  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
232  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
233 
234  if (glGetError () != GL_NO_ERROR)
235  warning ("opengl_texture::create: OpenGL error while generating texture data");
236  else
237  retval = opengl_texture (new texture_rep (id, w, h, tw, th));
238  }
239  }
240  else
241  warning ("opengl_texture::create: invalid texture data size");
242 
243  return retval;
244 }
245 
246 class
247 opengl_tesselator
248 {
249 public:
250 #if defined (HAVE_FRAMEWORK_OPENGL) && defined (HAVE_GLUTESSCALLBACK_THREEDOTS)
251  typedef GLvoid (CALLBACK *fcn) (...);
252 #else
253  typedef void (CALLBACK *fcn) (void);
254 #endif
255 
256 public:
257 
258  opengl_tesselator (void) : glu_tess (0), fill () { init (); }
259 
260  virtual ~opengl_tesselator (void)
261  { if (glu_tess) gluDeleteTess (glu_tess); }
262 
263  void begin_polygon (bool filled = true)
264  {
265  gluTessProperty (glu_tess, GLU_TESS_BOUNDARY_ONLY,
266  (filled ? GL_FALSE : GL_TRUE));
267  fill = filled;
268  gluTessBeginPolygon (glu_tess, this);
269  }
270 
271  void end_polygon (void) const
272  { gluTessEndPolygon (glu_tess); }
273 
274  void begin_contour (void) const
275  { gluTessBeginContour (glu_tess); }
276 
277  void end_contour (void) const
278  { gluTessEndContour (glu_tess); }
279 
280  void add_vertex (double *loc, void *data) const
281  { gluTessVertex (glu_tess, loc, data); }
282 
283 protected:
284  virtual void begin (GLenum /*type*/) { }
285 
286  virtual void end (void) { }
287 
288  virtual void vertex (void * /*data*/) { }
289 
290  virtual void combine (GLdouble [3] /*c*/, void * [4] /*data*/,
291  GLfloat [4] /*w*/, void ** /*out_data*/) { }
292 
293  virtual void edge_flag (GLboolean /*flag*/) { }
294 
295  virtual void error (GLenum err)
296  { ::error ("OpenGL tesselation error (%d)", err); }
297 
298  virtual void init (void)
299  {
300  glu_tess = gluNewTess ();
301 
302  gluTessCallback (glu_tess, GLU_TESS_BEGIN_DATA,
303  reinterpret_cast<fcn> (tess_begin));
304  gluTessCallback (glu_tess, GLU_TESS_END_DATA,
305  reinterpret_cast<fcn> (tess_end));
306  gluTessCallback (glu_tess, GLU_TESS_VERTEX_DATA,
307  reinterpret_cast<fcn> (tess_vertex));
308  gluTessCallback (glu_tess, GLU_TESS_COMBINE_DATA,
309  reinterpret_cast<fcn> (tess_combine));
310  gluTessCallback (glu_tess, GLU_TESS_EDGE_FLAG_DATA,
311  reinterpret_cast<fcn> (tess_edge_flag));
312  gluTessCallback (glu_tess, GLU_TESS_ERROR_DATA,
313  reinterpret_cast<fcn> (tess_error));
314  }
315 
316  bool is_filled (void) const { return fill; }
317 
318 private:
319  static void CALLBACK tess_begin (GLenum type, void *t)
320  { reinterpret_cast<opengl_tesselator *> (t)->begin (type); }
321 
322  static void CALLBACK tess_end (void *t)
323  { reinterpret_cast<opengl_tesselator *> (t)->end (); }
324 
325  static void CALLBACK tess_vertex (void *v, void *t)
326  { reinterpret_cast<opengl_tesselator *> (t)->vertex (v); }
327 
328  static void CALLBACK tess_combine (GLdouble c[3], void *v[4], GLfloat w[4],
329  void **out, void *t)
330  { reinterpret_cast<opengl_tesselator *> (t)->combine (c, v, w, out); }
331 
332  static void CALLBACK tess_edge_flag (GLboolean flag, void *t)
333  { reinterpret_cast<opengl_tesselator *> (t)->edge_flag (flag); }
334 
335  static void CALLBACK tess_error (GLenum err, void *t)
336  { reinterpret_cast<opengl_tesselator *> (t)->error (err); }
337 
338 private:
339 
340  // No copying!
341 
342  opengl_tesselator (const opengl_tesselator&);
343 
344  opengl_tesselator operator = (const opengl_tesselator&);
345 
346  GLUtesselator *glu_tess;
347  bool fill;
348 };
349 
350 class
351 vertex_data
352 {
353 public:
354  class vertex_data_rep
355  {
356  public:
357  Matrix coords;
358  Matrix color;
359  Matrix normal;
360  double alpha;
361  float ambient;
362  float diffuse;
363  float specular;
364  float specular_exp;
365 
366  // reference counter
367  octave_refcount<int> count;
368 
369  vertex_data_rep (void)
370  : coords (), color (), normal (), alpha (),
371  ambient (), diffuse (), specular (), specular_exp (),count (1) { }
372 
373  vertex_data_rep (const Matrix& c, const Matrix& col, const Matrix& n,
374  double a, float as, float ds, float ss, float se)
375  : coords (c), color (col), normal (n), alpha (a),
376  ambient (as), diffuse (ds), specular (ss), specular_exp (se),
377  count (1) { }
378  };
379 
380 private:
381  vertex_data_rep *rep;
382 
383  vertex_data_rep *nil_rep (void) const
384  {
385  static vertex_data_rep *nr = new vertex_data_rep ();
386 
387  return nr;
388  }
389 
390 public:
391  vertex_data (void) : rep (nil_rep ())
392  { rep->count++; }
393 
394  vertex_data (const vertex_data& v) : rep (v.rep)
395  { rep->count++; }
396 
397  vertex_data (const Matrix& c, const Matrix& col, const Matrix& n,
398  double a, float as, float ds, float ss, float se)
399  : rep (new vertex_data_rep (c, col, n, a, as, ds, ss, se))
400  { }
401 
402  vertex_data (vertex_data_rep *new_rep)
403  : rep (new_rep) { }
404 
405  ~vertex_data (void)
406  {
407  if (--rep->count == 0)
408  delete rep;
409  }
410 
411  vertex_data& operator = (const vertex_data& v)
412  {
413  if (--rep->count == 0)
414  delete rep;
415 
416  rep = v.rep;
417  rep->count++;
418 
419  return *this;
420  }
421 
422  vertex_data_rep *get_rep (void) const { return rep; }
423 };
424 
425 class
426 opengl_renderer::patch_tesselator : public opengl_tesselator
427 {
428 public:
429  patch_tesselator (opengl_renderer *r, int cmode, int lmode, float idx = 0.0)
430  : opengl_tesselator (), renderer (r),
431  color_mode (cmode), light_mode (lmode), index (idx),
432  first (true), tmp_vdata ()
433  { }
434 
435 protected:
436  void begin (GLenum type)
437  {
438  //printf ("patch_tesselator::begin (%d)\n", type);
439  first = true;
440 
441  if (color_mode == INTERP || light_mode == GOURAUD)
442  glShadeModel (GL_SMOOTH);
443  else
444  glShadeModel (GL_FLAT);
445 
446  if (is_filled ())
447  renderer->set_polygon_offset (true, index);
448 
449  glBegin (type);
450  }
451 
452  void end (void)
453  {
454  //printf ("patch_tesselator::end\n");
455  glEnd ();
456  renderer->set_polygon_offset (false);
457  }
458 
459  void vertex (void *data)
460  {
461  vertex_data::vertex_data_rep *v
462  = reinterpret_cast<vertex_data::vertex_data_rep *> (data);
463  //printf ("patch_tesselator::vertex (%g, %g, %g)\n", v->coords(0), v->coords(1), v->coords(2));
464 
465  // NOTE: OpenGL can re-order vertices. For "flat" coloring of FaceColor
466  // the first vertex must be identified in the draw_patch routine.
467 
468  if (color_mode == INTERP || (color_mode == FLAT && ! is_filled ()))
469  {
470  Matrix col = v->color;
471 
472  if (col.numel () == 3)
473  {
474  glColor3dv (col.data ());
475  if (light_mode > 0)
476  {
477  float buf[4] = { 0, 0, 0, 1 };
478 
479  for (int k = 0; k < 3; k++)
480  buf[k] = (v->ambient * col(k));
481  glMaterialfv (LIGHT_MODE, GL_AMBIENT, buf);
482 
483  for (int k = 0; k < 3; k++)
484  buf[k] = (v->diffuse * col(k));
485  glMaterialfv (LIGHT_MODE, GL_DIFFUSE, buf);
486  }
487  }
488  }
489 
490  if (light_mode > 0 && (first || light_mode == GOURAUD))
491  glNormal3dv (v->normal.data ());
492 
493  glVertex3dv (v->coords.data ());
494 
495  first = false;
496  }
497 
498  void combine (GLdouble xyz[3], void *data[4], GLfloat w[4], void **out_data)
499  {
500  //printf ("patch_tesselator::combine\n");
501 
502  vertex_data::vertex_data_rep *v[4];
503  int vmax = 4;
504 
505  for (int i = 0; i < 4; i++)
506  {
507  v[i] = reinterpret_cast<vertex_data::vertex_data_rep *> (data[i]);
508 
509  if (vmax == 4 && ! v[i])
510  vmax = i;
511  }
512 
513  Matrix vv (1, 3, 0.0);
514  Matrix cc;
515  Matrix nn (1, 3, 0.0);
516  double aa = 0.0;
517 
518  vv(0) = xyz[0];
519  vv(1) = xyz[1];
520  vv(2) = xyz[2];
521 
522  if (v[0]->color.numel ())
523  {
524  cc.resize (1, 3, 0.0);
525  for (int ic = 0; ic < 3; ic++)
526  for (int iv = 0; iv < vmax; iv++)
527  cc(ic) += (w[iv] * v[iv]->color (ic));
528  }
529 
530  if (v[0]->normal.numel () > 0)
531  {
532  for (int in = 0; in < 3; in++)
533  for (int iv = 0; iv < vmax; iv++)
534  nn(in) += (w[iv] * v[iv]->normal (in));
535  }
536 
537  for (int iv = 0; iv < vmax; iv++)
538  aa += (w[iv] * v[iv]->alpha);
539 
540  vertex_data new_v (vv, cc, nn, aa, v[0]->ambient, v[0]->diffuse,
541  v[0]->specular, v[0]->specular_exp);
542  tmp_vdata.push_back (new_v);
543 
544  *out_data = new_v.get_rep ();
545  }
546 
547 private:
548 
549  // No copying!
550 
551  patch_tesselator (const patch_tesselator&);
552 
553  patch_tesselator& operator = (const patch_tesselator&);
554 
555  opengl_renderer *renderer;
556  int color_mode;
557  int light_mode;
558  int index;
559  bool first;
560  std::list<vertex_data> tmp_vdata;
561 };
562 
563 void
564 opengl_renderer::draw (const graphics_object& go, bool toplevel)
565 {
566  if (! go.valid_object ())
567  return;
568 
569  const base_properties& props = go.get_properties ();
570 
571  if (! toolkit)
572  toolkit = props.get_toolkit ();
573 
574  if (go.isa ("figure"))
575  draw_figure (dynamic_cast<const figure::properties&> (props));
576  else if (go.isa ("axes"))
577  draw_axes (dynamic_cast<const axes::properties&> (props));
578  else if (go.isa ("line"))
579  draw_line (dynamic_cast<const line::properties&> (props));
580  else if (go.isa ("surface"))
581  draw_surface (dynamic_cast<const surface::properties&> (props));
582  else if (go.isa ("patch"))
583  draw_patch (dynamic_cast<const patch::properties&> (props));
584  else if (go.isa ("hggroup"))
585  draw_hggroup (dynamic_cast<const hggroup::properties&> (props));
586  else if (go.isa ("text"))
587  draw_text (dynamic_cast<const text::properties&> (props));
588  else if (go.isa ("image"))
589  draw_image (dynamic_cast<const image::properties&> (props));
590  else if (go.isa ("uimenu") || go.isa ("uicontrol")
591  || go.isa ("uicontextmenu") || go.isa ("uitoolbar")
592  || go.isa ("uipushtool") || go.isa ("uitoggletool"))
593  /* SKIP */;
594  else if (go.isa ("uipanel"))
595  {
596  if (toplevel)
597  draw_uipanel (dynamic_cast<const uipanel::properties&> (props), go);
598  }
599  else
600  {
601  warning ("opengl_renderer: cannot render object of type '%s'",
602  props.graphics_object_name ().c_str ());
603  }
604 }
605 
606 void
607 opengl_renderer::draw_figure (const figure::properties& props)
608 {
609  // Initialize OpenGL context
610 
611  init_gl_context (props.is___enhanced__ (), props.get_color_rgb ());
612 
613  // Draw children
614 
615  draw (props.get_all_children (), false);
616 }
617 
618 void
619 opengl_renderer::draw_uipanel (const uipanel::properties& props,
620  const graphics_object& go)
621 {
622  graphics_object fig = go.get_ancestor ("figure");
623  const figure::properties& figProps =
624  dynamic_cast<const figure::properties&> (fig.get_properties ());
625 
626  // Initialize OpenGL context
627 
628  init_gl_context (figProps.is___enhanced__ (),
629  props.get_backgroundcolor_rgb ());
630 
631  // Draw children
632 
633  draw (props.get_all_children (), false);
634 }
635 
636 void
637 opengl_renderer::init_gl_context (bool enhanced, const Matrix& c)
638 {
639  // Initialize OpenGL context
640 
641  glEnable (GL_DEPTH_TEST);
642  glDepthFunc (GL_LEQUAL);
643  glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
644  glAlphaFunc (GL_GREATER, 0.0f);
645  glEnable (GL_NORMALIZE);
646 
647  if (enhanced)
648  {
649  glEnable (GL_BLEND);
650  glEnable (GL_MULTISAMPLE);
651  GLint iMultiSample, iNumSamples;
652  glGetIntegerv (GL_SAMPLE_BUFFERS, &iMultiSample);
653  glGetIntegerv (GL_SAMPLES, &iNumSamples);
654  if (iMultiSample != GL_TRUE || iNumSamples == 0)
655  {
656  // MultiSample not implemented. Use old-style anti-aliasing
657  glDisable (GL_MULTISAMPLE);
658  glEnable (GL_LINE_SMOOTH);
659  glHint (GL_LINE_SMOOTH_HINT, GL_NICEST);
660  }
661  }
662  else
663  {
664  glDisable (GL_BLEND);
665  glDisable (GL_LINE_SMOOTH);
666  }
667 
668  // Clear background
669 
670  if (c.length () >= 3)
671  {
672  glClearColor (c(0), c(1), c(2), 1);
673  glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
674  }
675 }
676 
677 void
678 opengl_renderer::render_grid (const std::string& gridstyle,
679  const Matrix& ticks, double lim1, double lim2,
680  double p1, double p1N, double p2, double p2N,
681  int xyz, bool is_3D)
682 {
683  set_linestyle (gridstyle, true);
684  glBegin (GL_LINES);
685  for (int i = 0; i < ticks.numel (); i++)
686  {
687  double val = ticks(i);
688  if (lim1 <= val && val <= lim2)
689  {
690  if (xyz == X_AXIS)
691  {
692  glVertex3d (val, p1N, p2);
693  glVertex3d (val, p1, p2);
694  if (is_3D)
695  {
696  glVertex3d (val, p1, p2N);
697  glVertex3d (val, p1, p2);
698  }
699  }
700  else if (xyz == Y_AXIS)
701  {
702  glVertex3d (p1N, val, p2);
703  glVertex3d (p1, val, p2);
704  if (is_3D)
705  {
706  glVertex3d (p1, val, p2N);
707  glVertex3d (p1, val, p2);
708  }
709  }
710  else if (xyz == Z_AXIS)
711  {
712  glVertex3d (p1N, p2, val);
713  glVertex3d (p1, p2, val);
714  glVertex3d (p1, p2N, val);
715  glVertex3d (p1, p2, val);
716  }
717  }
718  }
719  glEnd ();
720  set_linestyle ("-", true);
721 }
722 
723 void
724 opengl_renderer::render_tickmarks (const Matrix& ticks,
725  double lim1, double lim2,
726  double p1, double p1N,
727  double p2, double p2N,
728  double dx, double dy, double dz,
729  int xyz, bool mirror)
730 {
731  glBegin (GL_LINES);
732 
733  for (int i = 0; i < ticks.numel (); i++)
734  {
735  double val = ticks(i);
736 
737  if (lim1 <= val && val <= lim2)
738  {
739  if (xyz == X_AXIS)
740  {
741  glVertex3d (val, p1, p2);
742  glVertex3d (val, p1+dy, p2+dz);
743  if (mirror)
744  {
745  glVertex3d (val, p1N, p2N);
746  glVertex3d (val, p1N-dy, p2N-dz);
747  }
748  }
749  else if (xyz == Y_AXIS)
750  {
751  glVertex3d (p1, val, p2);
752  glVertex3d (p1+dx, val, p2+dz);
753  if (mirror)
754  {
755  glVertex3d (p1N, val, p2N);
756  glVertex3d (p1N-dx, val, p2N-dz);
757  }
758  }
759  else if (xyz == Z_AXIS)
760  {
761  glVertex3d (p1, p2, val);
762  glVertex3d (p1+dx, p2+dy, val);
763  if (mirror)
764  {
765  glVertex3d (p1N, p2N, val);
766  glVertex3d (p1N-dx, p2N-dy, val);
767  }
768  }
769  }
770  }
771 
772  glEnd ();
773 }
774 
775 void
776 opengl_renderer::render_ticktexts (const Matrix& ticks,
777  const string_vector& ticklabels,
778  double lim1, double lim2,
779  double p1, double p2,
780  int xyz, int ha, int va,
781  int& wmax, int& hmax)
782 {
783  int nticks = ticks.numel ();
784  int nlabels = ticklabels.numel ();
785 
786  if (nlabels == 0)
787  return;
788 
789  for (int i = 0; i < nticks; i++)
790  {
791  double val = ticks(i);
792 
793  if (lim1 <= val && val <= lim2)
794  {
795  Matrix b;
796 
797  std::string label (ticklabels(i % nlabels));
798  label.erase (0, label.find_first_not_of (" "));
799  label = label.substr (0, label.find_last_not_of (" ")+1);
800 
801  // FIXME: As tick text is transparent, shouldn't it be
802  // drawn after axes object, for correct rendering?
803  if (xyz == X_AXIS)
804  {
805  b = render_text (label, val, p1, p2, ha, va);
806  }
807  else if (xyz == Y_AXIS)
808  {
809  b = render_text (label, p1, val, p2, ha, va);
810  }
811  else if (xyz == Z_AXIS)
812  {
813  b = render_text (label, p1, p2, val, ha, va);
814  }
815 
816  wmax = std::max (wmax, static_cast<int> (b(2)));
817  hmax = std::max (hmax, static_cast<int> (b(3)));
818  }
819  }
820 }
821 
822 void
823 opengl_renderer::setup_opengl_transformation (const axes::properties& props)
824 {
825  // setup OpenGL transformation
826 
827  Matrix x_zlim = props.get_transform_zlim ();
828 
829  xZ1 = x_zlim(0)-(x_zlim(1)-x_zlim(0))/2;
830  xZ2 = x_zlim(1)+(x_zlim(1)-x_zlim(0))/2;
831 
832  Matrix x_mat1 = props.get_opengl_matrix_1 ();
833  Matrix x_mat2 = props.get_opengl_matrix_2 ();
834 
835 #if defined (HAVE_FRAMEWORK_OPENGL)
836  GLint vw[4];
837 #else
838  int vw[4];
839 #endif
840 
841  glGetIntegerv (GL_VIEWPORT, vw);
842 
843  glMatrixMode (GL_MODELVIEW);
844  glLoadIdentity ();
845  glScaled (1, 1, -1);
846  glMultMatrixd (x_mat1.data ());
847  glMatrixMode (GL_PROJECTION);
848  glLoadIdentity ();
849  glOrtho (0, vw[2], vw[3], 0, xZ1, xZ2);
850  glMultMatrixd (x_mat2.data ());
851  glMatrixMode (GL_MODELVIEW);
852 
853  glClear (GL_DEPTH_BUFFER_BIT);
854 
855  // store axes transformation data
856 
857  xform = props.get_transform ();
858 }
859 
860 void
861 opengl_renderer::draw_axes_planes (const axes::properties& props)
862 {
863  Matrix axe_color = props.get_color_rgb ();
864  if (axe_color.numel () == 0 || ! props.is_visible ())
865  return;
866 
867  double xPlane = props.get_xPlane ();
868  double yPlane = props.get_yPlane ();
869  double zPlane = props.get_zPlane ();
870  double xPlaneN = props.get_xPlaneN ();
871  double yPlaneN = props.get_yPlaneN ();
872  double zPlaneN = props.get_zPlaneN ();
873  bool is2d = props.get_is2D ();
874 
875  // Axes planes
876  set_color (axe_color);
877  set_polygon_offset (true, 2.5);
878 
879  glBegin (GL_QUADS);
880 
881  if (! is2d)
882  {
883  // X plane
884  glVertex3d (xPlane, yPlaneN, zPlaneN);
885  glVertex3d (xPlane, yPlane, zPlaneN);
886  glVertex3d (xPlane, yPlane, zPlane);
887  glVertex3d (xPlane, yPlaneN, zPlane);
888 
889  // Y plane
890  glVertex3d (xPlaneN, yPlane, zPlaneN);
891  glVertex3d (xPlane, yPlane, zPlaneN);
892  glVertex3d (xPlane, yPlane, zPlane);
893  glVertex3d (xPlaneN, yPlane, zPlane);
894  }
895 
896  // Z plane
897  glVertex3d (xPlaneN, yPlaneN, zPlane);
898  glVertex3d (xPlane, yPlaneN, zPlane);
899  glVertex3d (xPlane, yPlane, zPlane);
900  glVertex3d (xPlaneN, yPlane, zPlane);
901 
902  glEnd ();
903 
904  set_polygon_offset (false);
905 }
906 
907 void
908 opengl_renderer::draw_axes_boxes (const axes::properties& props)
909 {
910  if (! props.is_visible ())
911  return;
912 
913  bool xySym = props.get_xySym ();
914  bool layer2Dtop = props.get_layer2Dtop ();
915  bool is2d = props.get_is2D ();
916  double xPlane = props.get_xPlane ();
917  double yPlane = props.get_yPlane ();
918  double zPlane = props.get_zPlane ();
919  double xPlaneN = props.get_xPlaneN ();
920  double yPlaneN = props.get_yPlaneN ();
921  double zPlaneN = props.get_zPlaneN ();
922  double xpTick = props.get_xpTick ();
923  double ypTick = props.get_ypTick ();
924  double zpTick = props.get_zpTick ();
925  double xpTickN = props.get_xpTickN ();
926  double ypTickN = props.get_ypTickN ();
927  double zpTickN = props.get_zpTickN ();
928 
929  bool plotyy = (props.has_property ("__plotyy_axes__"));
930 
931  // Axes box
932 
933  set_linestyle ("-", true);
934  set_linewidth (props.get_linewidth ());
935 
936  glBegin (GL_LINES);
937 
938  if (layer2Dtop)
939  std::swap (zpTick, zpTickN);
940 
941  // X box
942  set_color (props.get_xcolor_rgb ());
943  glVertex3d (xPlaneN, ypTick, zpTick);
944  glVertex3d (xPlane, ypTick, zpTick);
945 
946  if (props.is_box ())
947  {
948  glVertex3d (xPlaneN, ypTickN, zpTick);
949  glVertex3d (xPlane, ypTickN, zpTick);
950  if (! is2d)
951  {
952  glVertex3d (xPlaneN, ypTickN, zpTickN);
953  glVertex3d (xPlane, ypTickN, zpTickN);
954  glVertex3d (xPlaneN, ypTick, zpTickN);
955  glVertex3d (xPlane, ypTick, zpTickN);
956  }
957  }
958 
959  // Y box
960  set_color (props.get_ycolor_rgb ());
961  glVertex3d (xpTick, yPlaneN, zpTick);
962  glVertex3d (xpTick, yPlane, zpTick);
963 
964  if (props.is_box () && ! plotyy)
965  {
966  glVertex3d (xpTickN, yPlaneN, zpTick);
967  glVertex3d (xpTickN, yPlane, zpTick);
968 
969  if (! is2d)
970  {
971  glVertex3d (xpTickN, yPlaneN, zpTickN);
972  glVertex3d (xpTickN, yPlane, zpTickN);
973  glVertex3d (xpTick, yPlaneN, zpTickN);
974  glVertex3d (xpTick, yPlane, zpTickN);
975  }
976  }
977 
978  // Z box
979  if (! is2d)
980  {
981  set_color (props.get_zcolor_rgb ());
982 
983  if (xySym)
984  {
985  glVertex3d (xPlaneN, yPlane, zPlaneN);
986  glVertex3d (xPlaneN, yPlane, zPlane);
987  }
988  else
989  {
990  glVertex3d (xPlane, yPlaneN, zPlaneN);
991  glVertex3d (xPlane, yPlaneN, zPlane);
992  }
993 
994  if (props.is_box ())
995  {
996  glVertex3d (xPlane, yPlane, zPlaneN);
997  glVertex3d (xPlane, yPlane, zPlane);
998 
999  if (xySym)
1000  {
1001  glVertex3d (xPlane, yPlaneN, zPlaneN);
1002  glVertex3d (xPlane, yPlaneN, zPlane);
1003  }
1004  else
1005  {
1006  glVertex3d (xPlaneN, yPlane, zPlaneN);
1007  glVertex3d (xPlaneN, yPlane, zPlane);
1008  }
1009 
1010  glVertex3d (xPlaneN, yPlaneN, zPlaneN);
1011  glVertex3d (xPlaneN, yPlaneN, zPlane);
1012  }
1013  }
1014 
1015  glEnd ();
1016 }
1017 
1018 void
1019 opengl_renderer::draw_axes_x_grid (const axes::properties& props)
1020 {
1021  int xstate = props.get_xstate ();
1022 
1023  if (props.is_visible () && xstate != AXE_DEPTH_DIR)
1024  {
1025  int zstate = props.get_zstate ();
1026  bool x2Dtop = props.get_x2Dtop ();
1027  bool layer2Dtop = props.get_layer2Dtop ();
1028  bool xyzSym = props.get_xyzSym ();
1029  bool nearhoriz = props.get_nearhoriz ();
1030  double xticklen = props.get_xticklen ();
1031  double xtickoffset = props.get_xtickoffset ();
1032  double fy = props.get_fy ();
1033  double fz = props.get_fz ();
1034  double x_min = props.get_x_min ();
1035  double x_max = props.get_x_max ();
1036  double yPlane = props.get_yPlane ();
1037  double yPlaneN = props.get_yPlaneN ();
1038  double ypTick = props.get_ypTick ();
1039  double ypTickN = props.get_ypTickN ();
1040  double zPlane = props.get_zPlane ();
1041  double zPlaneN = props.get_zPlaneN ();
1042  double zpTick = props.get_zpTick ();
1043  double zpTickN = props.get_zpTickN ();
1044 
1045  // X grid
1046 
1047  std::string gridstyle = props.get_gridlinestyle ();
1048  std::string minorgridstyle = props.get_minorgridlinestyle ();
1049  bool do_xgrid = (props.is_xgrid () && (gridstyle != "none"));
1050  bool do_xminorgrid = (props.is_xminorgrid ()
1051  && (minorgridstyle != "none"));
1052  bool do_xminortick = props.is_xminortick ();
1053  Matrix xticks = xform.xscale (props.get_xtick ().matrix_value ());
1054  Matrix xmticks = xform.xscale (props.get_xmtick ().matrix_value ());
1055  string_vector xticklabels = props.get_xticklabel ().all_strings ();
1056  int wmax = 0;
1057  int hmax = 0;
1058  bool tick_along_z = nearhoriz || xisinf (fy);
1059  bool mirror = props.is_box () && xstate != AXE_ANY_DIR;
1060 
1061  set_color (props.get_xcolor_rgb ());
1062 
1063  // grid lines
1064  if (do_xgrid)
1065  render_grid (gridstyle, xticks, x_min, x_max,
1066  yPlane, yPlaneN, layer2Dtop ? zPlaneN : zPlane,
1067  zPlaneN, 0, (zstate != AXE_DEPTH_DIR));
1068 
1069  // tick marks
1070  if (tick_along_z)
1071  {
1072  render_tickmarks (xticks, x_min, x_max, ypTick, ypTick,
1073  zpTick, zpTickN, 0., 0.,
1074  signum (zpTick-zpTickN)*fz*xticklen,
1075  0, mirror);
1076  }
1077  else
1078  {
1079  render_tickmarks (xticks, x_min, x_max, ypTick, ypTickN,
1080  zpTick, zpTick, 0.,
1081  signum (ypTick-ypTickN)*fy*xticklen,
1082  0., 0, mirror);
1083  }
1084 
1085  // tick texts
1086  if (xticklabels.numel () > 0)
1087  {
1088  int halign = (xstate == AXE_HORZ_DIR ? 1 : (xyzSym ? 0 : 2));
1089  int valign = (xstate == AXE_VERT_DIR ? 1 : (x2Dtop ? 0 : 2));
1090 
1091  if (tick_along_z)
1092  render_ticktexts (xticks, xticklabels, x_min, x_max, ypTick,
1093  zpTick+signum (zpTick-zpTickN)*fz*xtickoffset,
1094  0, halign, valign, wmax, hmax);
1095  else
1096  render_ticktexts (xticks, xticklabels, x_min, x_max,
1097  ypTick+signum (ypTick-ypTickN)*fy*xtickoffset,
1098  zpTick, 0, halign, valign, wmax, hmax);
1099  }
1100 
1101  // minor grid lines
1102  if (do_xminorgrid)
1103  render_grid (minorgridstyle, xmticks, x_min, x_max,
1104  yPlane, yPlaneN, layer2Dtop ? zPlaneN : zPlane,
1105  zPlaneN, 0, (zstate != AXE_DEPTH_DIR));
1106 
1107  // minor tick marks
1108  if (do_xminortick)
1109  {
1110  if (tick_along_z)
1111  render_tickmarks (xmticks, x_min, x_max, ypTick, ypTick,
1112  zpTick, zpTickN, 0., 0.,
1113  signum (zpTick-zpTickN)*fz*xticklen/2,
1114  0, mirror);
1115  else
1116  render_tickmarks (xmticks, x_min, x_max, ypTick, ypTickN,
1117  zpTick, zpTick, 0.,
1118  signum (ypTick-ypTickN)*fy*xticklen/2,
1119  0., 0, mirror);
1120  }
1121 
1122  gh_manager::get_object (props.get_xlabel ()).set ("visible", "on");
1123  }
1124  else
1125  gh_manager::get_object (props.get_xlabel ()).set ("visible", "off");
1126 }
1127 
1128 void
1129 opengl_renderer::draw_axes_y_grid (const axes::properties& props)
1130 {
1131  int ystate = props.get_ystate ();
1132 
1133  if (ystate != AXE_DEPTH_DIR && props.is_visible ())
1134  {
1135  int zstate = props.get_zstate ();
1136  bool y2Dright = props.get_y2Dright ();
1137  bool layer2Dtop = props.get_layer2Dtop ();
1138  bool xyzSym = props.get_xyzSym ();
1139  bool nearhoriz = props.get_nearhoriz ();
1140  double yticklen = props.get_yticklen ();
1141  double ytickoffset = props.get_ytickoffset ();
1142  double fx = props.get_fx ();
1143  double fz = props.get_fz ();
1144  double xPlane = props.get_xPlane ();
1145  double xPlaneN = props.get_xPlaneN ();
1146  double xpTick = props.get_xpTick ();
1147  double xpTickN = props.get_xpTickN ();
1148  double y_min = props.get_y_min ();
1149  double y_max = props.get_y_max ();
1150  double zPlane = props.get_zPlane ();
1151  double zPlaneN = props.get_zPlaneN ();
1152  double zpTick = props.get_zpTick ();
1153  double zpTickN = props.get_zpTickN ();
1154 
1155  // Y grid
1156 
1157  std::string gridstyle = props.get_gridlinestyle ();
1158  std::string minorgridstyle = props.get_minorgridlinestyle ();
1159  bool do_ygrid = (props.is_ygrid () && (gridstyle != "none"));
1160  bool do_yminorgrid = (props.is_yminorgrid ()
1161  && (minorgridstyle != "none"));
1162  bool do_yminortick = props.is_yminortick ();
1163  Matrix yticks = xform.yscale (props.get_ytick ().matrix_value ());
1164  Matrix ymticks = xform.yscale (props.get_ymtick ().matrix_value ());
1165  string_vector yticklabels = props.get_yticklabel ().all_strings ();
1166  int wmax = 0;
1167  int hmax = 0;
1168  bool tick_along_z = nearhoriz || xisinf (fx);
1169  bool mirror = props.is_box () && ystate != AXE_ANY_DIR
1170  && (! props.has_property ("__plotyy_axes__"));
1171 
1172  set_color (props.get_ycolor_rgb ());
1173 
1174  // grid lines
1175  if (do_ygrid)
1176  render_grid (gridstyle, yticks, y_min, y_max,
1177  xPlane, xPlaneN, layer2Dtop ? zPlaneN : zPlane,
1178  zPlaneN, 1, (zstate != AXE_DEPTH_DIR));
1179 
1180  // tick marks
1181  if (tick_along_z)
1182  render_tickmarks (yticks, y_min, y_max, xpTick, xpTick,
1183  zpTick, zpTickN, 0., 0.,
1184  signum (zpTick-zpTickN)*fz*yticklen,
1185  1, mirror);
1186  else
1187  render_tickmarks (yticks, y_min, y_max, xpTick, xpTickN,
1188  zpTick, zpTick,
1189  signum (xPlaneN-xPlane)*fx*yticklen,
1190  0., 0., 1, mirror);
1191 
1192  // tick texts
1193  if (yticklabels.numel () > 0)
1194  {
1195  int halign = (ystate == AXE_HORZ_DIR
1196  ? 1 : (!xyzSym || y2Dright ? 0 : 2));
1197  int valign = (ystate == AXE_VERT_DIR ? 1 : 2);
1198 
1199  if (tick_along_z)
1200  render_ticktexts (yticks, yticklabels, y_min, y_max, xpTick,
1201  zpTick+signum (zpTick-zpTickN)*fz*ytickoffset,
1202  1, halign, valign, wmax, hmax);
1203  else
1204  render_ticktexts (yticks, yticklabels, y_min, y_max,
1205  xpTick+signum (xpTick-xpTickN)*fx*ytickoffset,
1206  zpTick, 1, halign, valign, wmax, hmax);
1207  }
1208 
1209  // minor grid lines
1210  if (do_yminorgrid)
1211  render_grid (minorgridstyle, ymticks, y_min, y_max,
1212  xPlane, xPlaneN, layer2Dtop ? zPlaneN : zPlane,
1213  zPlaneN, 1, (zstate != AXE_DEPTH_DIR));
1214 
1215  // minor tick marks
1216  if (do_yminortick)
1217  {
1218  if (tick_along_z)
1219  render_tickmarks (ymticks, y_min, y_max, xpTick, xpTick,
1220  zpTick, zpTickN, 0., 0.,
1221  signum (zpTick-zpTickN)*fz*yticklen/2,
1222  1, mirror);
1223  else
1224  render_tickmarks (ymticks, y_min, y_max, xpTick, xpTickN,
1225  zpTick, zpTick,
1226  signum (xpTick-xpTickN)*fx*yticklen/2,
1227  0., 0., 1, mirror);
1228  }
1229 
1230  gh_manager::get_object (props.get_ylabel ()).set ("visible", "on");
1231  }
1232  else
1233  gh_manager::get_object (props.get_ylabel ()).set ("visible", "off");
1234 }
1235 
1236 void
1237 opengl_renderer::draw_axes_z_grid (const axes::properties& props)
1238 {
1239  int zstate = props.get_zstate ();
1240 
1241  if (zstate != AXE_DEPTH_DIR && props.is_visible ())
1242  {
1243  bool xySym = props.get_xySym ();
1244  bool zSign = props.get_zSign ();
1245  double zticklen = props.get_zticklen ();
1246  double ztickoffset = props.get_ztickoffset ();
1247  double fx = props.get_fx ();
1248  double fy = props.get_fy ();
1249  double xPlane = props.get_xPlane ();
1250  double xPlaneN = props.get_xPlaneN ();
1251  double yPlane = props.get_yPlane ();
1252  double yPlaneN = props.get_yPlaneN ();
1253  double z_min = props.get_z_min ();
1254  double z_max = props.get_z_max ();
1255 
1256  // Z Grid
1257 
1258  std::string gridstyle = props.get_gridlinestyle ();
1259  std::string minorgridstyle = props.get_minorgridlinestyle ();
1260  bool do_zgrid = (props.is_zgrid () && (gridstyle != "none"));
1261  bool do_zminorgrid = (props.is_zminorgrid ()
1262  && (minorgridstyle != "none"));
1263  bool do_zminortick = props.is_zminortick ();
1264  Matrix zticks = xform.zscale (props.get_ztick ().matrix_value ());
1265  Matrix zmticks = xform.zscale (props.get_zmtick ().matrix_value ());
1266  string_vector zticklabels = props.get_zticklabel ().all_strings ();
1267  int wmax = 0;
1268  int hmax = 0;
1269  bool mirror = props.is_box () && zstate != AXE_ANY_DIR;
1270 
1271  set_color (props.get_zcolor_rgb ());
1272 
1273  // grid lines
1274  if (do_zgrid)
1275  render_grid (gridstyle, zticks, z_min, z_max,
1276  xPlane, xPlaneN, yPlane, yPlaneN, 2, true);
1277 
1278  // tick marks
1279  if (xySym)
1280  {
1281  if (xisinf (fy))
1282  render_tickmarks (zticks, z_min, z_max, xPlaneN, xPlane,
1283  yPlane, yPlane,
1284  signum (xPlaneN-xPlane)*fx*zticklen,
1285  0., 0., 2, mirror);
1286  else
1287  render_tickmarks (zticks, z_min, z_max, xPlaneN, xPlaneN,
1288  yPlane, yPlane, 0.,
1289  signum (yPlane-yPlaneN)*fy*zticklen,
1290  0., 2, false);
1291  }
1292  else
1293  {
1294  if (xisinf (fx))
1295  render_tickmarks (zticks, z_min, z_max, xPlaneN, xPlane,
1296  yPlaneN, yPlane, 0.,
1297  signum (yPlaneN-yPlane)*fy*zticklen,
1298  0., 2, mirror);
1299  else
1300  render_tickmarks (zticks, z_min, z_max, xPlane, xPlane,
1301  yPlaneN, yPlane,
1302  signum (xPlane-xPlaneN)*fx*zticklen,
1303  0., 0., 2, false);
1304  }
1305 
1306  // FIXME: tick texts
1307  if (zticklabels.numel () > 0)
1308  {
1309  int halign = 2;
1310  int valign = (zstate == AXE_VERT_DIR ? 1 : (zSign ? 3 : 2));
1311 
1312  if (xySym)
1313  {
1314  if (xisinf (fy))
1315  render_ticktexts (zticks, zticklabels, z_min, z_max,
1316  xPlaneN+signum (xPlaneN-xPlane)*fx*ztickoffset,
1317  yPlane, 2, halign, valign, wmax, hmax);
1318  else
1319  render_ticktexts (zticks, zticklabels, z_min, z_max, xPlaneN,
1320  yPlane+signum (yPlane-yPlaneN)*fy*ztickoffset,
1321  2, halign, valign, wmax, hmax);
1322  }
1323  else
1324  {
1325  if (xisinf (fx))
1326  render_ticktexts (zticks, zticklabels, z_min, z_max, xPlane,
1327  yPlaneN+signum (yPlaneN-yPlane)*fy*ztickoffset,
1328  2, halign, valign, wmax, hmax);
1329  else
1330  render_ticktexts (zticks, zticklabels, z_min, z_max,
1331  xPlane+signum (xPlane-xPlaneN)*fx*ztickoffset,
1332  yPlaneN, 2, halign, valign, wmax, hmax);
1333  }
1334  }
1335 
1336  // minor grid lines
1337  if (do_zminorgrid)
1338  render_grid (minorgridstyle, zmticks, z_min, z_max,
1339  xPlane, xPlaneN, yPlane, yPlaneN, 2, true);
1340 
1341  // minor tick marks
1342  if (do_zminortick)
1343  {
1344  if (xySym)
1345  {
1346  if (xisinf (fy))
1347  render_tickmarks (zmticks, z_min, z_max, xPlaneN, xPlane,
1348  yPlane, yPlane,
1349  signum (xPlaneN-xPlane)*fx*zticklen/2,
1350  0., 0., 2, mirror);
1351  else
1352  render_tickmarks (zmticks, z_min, z_max, xPlaneN, xPlaneN,
1353  yPlane, yPlane, 0.,
1354  signum (yPlane-yPlaneN)*fy*zticklen/2,
1355  0., 2, false);
1356  }
1357  else
1358  {
1359  if (xisinf (fx))
1360  render_tickmarks (zmticks, z_min, z_max, xPlane, xPlane,
1361  yPlaneN, yPlane, 0.,
1362  signum (yPlaneN-yPlane)*fy*zticklen/2,
1363  0., 2, mirror);
1364  else
1365  render_tickmarks (zmticks, z_min, z_max, xPlane, xPlane,
1366  yPlaneN, yPlaneN,
1367  signum (xPlane-xPlaneN)*fx*zticklen/2,
1368  0., 0., 2, false);
1369  }
1370  }
1371 
1372  gh_manager::get_object (props.get_zlabel ()).set ("visible", "on");
1373  }
1374  else
1375  gh_manager::get_object (props.get_zlabel ()).set ("visible", "off");
1376 }
1377 
1378 void
1379 opengl_renderer::draw_axes_children (const axes::properties& props)
1380 {
1381  // Children
1382 
1383  Matrix children = props.get_all_children ();
1384  std::list<graphics_object> obj_list;
1385  std::list<graphics_object>::iterator it;
1386 
1387  // 1st pass: draw light objects
1388 
1389  // Start with the last element of the array of child objects to
1390  // display them in the order they were added to the array.
1391 
1392  for (octave_idx_type i = children.numel () - 1; i >= 0; i--)
1393  {
1394  graphics_object go = gh_manager::get_object (children(i));
1395 
1396  if (go.get_properties ().is_visible ())
1397  {
1398  if (go.isa ("light"))
1399  draw (go);
1400  else
1401  obj_list.push_back (go);
1402  }
1403  }
1404 
1405  // 2nd pass: draw other objects (with units set to "data")
1406 
1407  it = obj_list.begin ();
1408  while (it != obj_list.end ())
1409  {
1410  graphics_object go = (*it);
1411 
1412  // FIXME: check whether object has "units" property and it is set
1413  // to "data"
1414  if (! go.isa ("text") || go.get ("units").string_value () == "data")
1415  {
1416  set_clipping (go.get_properties ().is_clipping ());
1417  draw (go);
1418 
1419  it = obj_list.erase (it);
1420  }
1421  else
1422  it++;
1423  }
1424 
1425  // 3rd pass: draw remaining objects
1426 
1427  glDisable (GL_DEPTH_TEST);
1428 
1429  for (it = obj_list.begin (); it != obj_list.end (); it++)
1430  {
1431  graphics_object go = (*it);
1432 
1433  set_clipping (go.get_properties ().is_clipping ());
1434  draw (go);
1435  }
1436 
1437  glEnable (GL_DEPTH_TEST);
1438 
1439  set_clipping (false);
1440 
1441  // FIXME: finalize rendering (transparency processing)
1442  // FIXME: draw zoom box, if needed
1443 }
1444 
1445 void
1446 opengl_renderer::draw_axes (const axes::properties& props)
1447 {
1448  static double floatmax = std::numeric_limits<float>::max ();
1449 
1450  double x_min = props.get_x_min ();
1451  double x_max = props.get_x_max ();
1452  double y_min = props.get_y_min ();
1453  double y_max = props.get_y_max ();
1454  double z_min = props.get_z_min ();
1455  double z_max = props.get_z_max ();
1456 
1457  if (x_max > floatmax || y_max > floatmax || z_max > floatmax
1458  || x_min < -floatmax || y_min < -floatmax || z_min < -floatmax)
1459  {
1460  warning ("opengl_renderer: data values greater than float capacity. (1) Scale data, or (2) Use gnuplot");
1461  return;
1462  }
1463 
1464  setup_opengl_transformation (props);
1465 
1466  // Disable line smoothing for axes
1467  GLboolean antialias;
1468  glGetBooleanv (GL_LINE_SMOOTH, &antialias);
1469  if (antialias == GL_TRUE)
1470  glDisable (GL_LINE_SMOOTH);
1471 
1472  // draw axes object
1473 
1474  draw_axes_planes (props);
1475  draw_axes_boxes (props);
1476 
1477  set_font (props);
1478 
1479  draw_axes_x_grid (props);
1480  draw_axes_y_grid (props);
1481  draw_axes_z_grid (props);
1482 
1483  set_linestyle ("-");
1484 
1485  set_clipbox (x_min, x_max, y_min, y_max, z_min, z_max);
1486 
1487  // Re-enable line smoothing for children
1488  if (antialias == GL_TRUE)
1489  glEnable (GL_LINE_SMOOTH);
1490 
1491  draw_axes_children (props);
1492 }
1493 
1494 void
1495 opengl_renderer::draw_line (const line::properties& props)
1496 {
1497  Matrix x = xform.xscale (props.get_xdata ().matrix_value ());
1498  Matrix y = xform.yscale (props.get_ydata ().matrix_value ());
1499  Matrix z = xform.zscale (props.get_zdata ().matrix_value ());
1500 
1501  bool has_z = (z.numel () > 0);
1502  int n = static_cast<int> (std::min (std::min (x.numel (), y.numel ()),
1503  (has_z ? z.numel ()
1505  octave_uint8 clip_mask = (props.is_clipping () ? 0x7F : 0x40), clip_ok (0x40);
1506 
1507  std::vector<octave_uint8> clip (n);
1508 
1509  if (has_z)
1510  for (int i = 0; i < n; i++)
1511  clip[i] = (clip_code (x(i), y(i), z(i)) & clip_mask);
1512  else
1513  {
1514  double z_mid = (zmin+zmax)/2;
1515 
1516  for (int i = 0; i < n; i++)
1517  clip[i] = (clip_code (x(i), y(i), z_mid) & clip_mask);
1518  }
1519 
1520  if (! props.linestyle_is ("none"))
1521  {
1522  set_color (props.get_color_rgb ());
1523  set_linestyle (props.get_linestyle (), false);
1524  set_linewidth (props.get_linewidth ());
1525 
1526  if (has_z)
1527  {
1528  bool flag = false;
1529 
1530  for (int i = 1; i < n; i++)
1531  {
1532  if ((clip[i-1] & clip[i]) == clip_ok)
1533  {
1534  if (! flag)
1535  {
1536  flag = true;
1537  glBegin (GL_LINE_STRIP);
1538  glVertex3d (x(i-1), y(i-1), z(i-1));
1539  }
1540  glVertex3d (x(i), y(i), z(i));
1541  }
1542  else if (flag)
1543  {
1544  flag = false;
1545  glEnd ();
1546  }
1547  }
1548 
1549  if (flag)
1550  glEnd ();
1551  }
1552  else
1553  {
1554  bool flag = false;
1555 
1556  for (int i = 1; i < n; i++)
1557  {
1558  if ((clip[i-1] & clip[i]) == clip_ok)
1559  {
1560  if (! flag)
1561  {
1562  flag = true;
1563  glBegin (GL_LINE_STRIP);
1564  glVertex2d (x(i-1), y(i-1));
1565  }
1566  glVertex2d (x(i), y(i));
1567  }
1568  else if (flag)
1569  {
1570  flag = false;
1571  glEnd ();
1572  }
1573  }
1574 
1575  if (flag)
1576  glEnd ();
1577  }
1578 
1579  set_linewidth (0.5);
1580  set_linestyle ("-");
1581  }
1582 
1583  set_clipping (false);
1584 
1585  if (! props.marker_is ("none")
1586  && ! (props.markeredgecolor_is ("none")
1587  && props.markerfacecolor_is ("none")))
1588  {
1589  Matrix lc, fc;
1590 
1591  if (props.markeredgecolor_is ("auto"))
1592  lc = props.get_color_rgb ();
1593  else if (! props.markeredgecolor_is ("none"))
1594  lc = props.get_markeredgecolor_rgb ();
1595 
1596  if (props.markerfacecolor_is ("auto"))
1597  fc = props.get_color_rgb ();
1598  else if (! props.markerfacecolor_is ("none"))
1599  fc = props.get_markerfacecolor_rgb ();
1600 
1601  init_marker (props.get_marker (), props.get_markersize (),
1602  props.get_linewidth ());
1603 
1604  for (int i = 0; i < n; i++)
1605  {
1606  if (clip[i] == clip_ok)
1607  draw_marker (x(i), y(i),
1608  has_z ? z(i) : 0.0,
1609  lc, fc);
1610  }
1611 
1612  end_marker ();
1613  }
1614 
1615  set_clipping (props.is_clipping ());
1616 }
1617 
1618 void
1619 opengl_renderer::draw_surface (const surface::properties& props)
1620 {
1621  const Matrix x = xform.xscale (props.get_xdata ().matrix_value ());
1622  const Matrix y = xform.yscale (props.get_ydata ().matrix_value ());
1623  const Matrix z = xform.zscale (props.get_zdata ().matrix_value ());
1624 
1625  int zr = z.rows ();
1626  int zc = z.columns ();
1627 
1628  NDArray c;
1629  const NDArray n = props.get_vertexnormals ().array_value ();
1630 
1631  // FIXME: handle transparency
1632  Matrix a;
1633 
1634  if (props.facelighting_is ("phong") || props.edgelighting_is ("phong"))
1635  warning ("opengl_renderer: phong light model not supported");
1636 
1637  int fc_mode = (props.facecolor_is_rgb () ? 0 :
1638  (props.facecolor_is ("flat") ? 1 :
1639  (props.facecolor_is ("interp") ? 2 :
1640  (props.facecolor_is ("texturemap") ? 3 : -1))));
1641  int fl_mode = (props.facelighting_is ("none") ? 0 :
1642  (props.facelighting_is ("flat") ? 1 : 2));
1643  int fa_mode = (props.facealpha_is_double () ? 0 :
1644  (props.facealpha_is ("flat") ? 1 : 2));
1645  int ec_mode = (props.edgecolor_is_rgb () ? 0 :
1646  (props.edgecolor_is ("flat") ? 1 :
1647  (props.edgecolor_is ("interp") ? 2 : -1)));
1648  int el_mode = (props.edgelighting_is ("none") ? 0 :
1649  (props.edgelighting_is ("flat") ? 1 : 2));
1650  int ea_mode = (props.edgealpha_is_double () ? 0 :
1651  (props.edgealpha_is ("flat") ? 1 : 2));
1652 
1653  Matrix fcolor = (fc_mode == TEXTURE ? Matrix (1, 3, 1.0)
1654  : props.get_facecolor_rgb ());
1655  Matrix ecolor = props.get_edgecolor_rgb ();
1656 
1657  float as = props.get_ambientstrength ();
1658  float ds = props.get_diffusestrength ();
1659  float ss = props.get_specularstrength ();
1660  float se = props.get_specularexponent ();
1661  float cb[4] = { 0.0, 0.0, 0.0, 1.0 };
1662  double d = 1.0;
1663 
1664  opengl_texture tex;
1665 
1666  int i1, i2, j1, j2;
1667  bool x_mat = (x.rows () == z.rows ());
1668  bool y_mat = (y.columns () == z.columns ());
1669 
1670  i1 = i2 = j1 = j2 = 0;
1671 
1672  if ((fc_mode > 0 && fc_mode < 3) || ec_mode > 0)
1673  c = props.get_color_data ().array_value ();
1674 
1675  boolMatrix clip (z.dims (), false);
1676 
1677  for (int i = 0; i < zr; i++)
1678  {
1679  if (x_mat)
1680  i1 = i;
1681 
1682  for (int j = 0; j < zc; j++)
1683  {
1684  if (y_mat)
1685  j1 = j;
1686 
1687  clip(i,j) = is_nan_or_inf (x(i1,j), y(i,j1), z(i,j));
1688  }
1689  }
1690 
1691  if (fa_mode > 0 || ea_mode > 0)
1692  {
1693  // FIXME: implement alphadata conversion
1694  //a = props.get_alpha_data ();
1695  }
1696 
1697  if (fl_mode > 0 || el_mode > 0)
1698  {
1699  float buf[4] = { ss, ss, ss, 1 };
1700 
1701  glMaterialfv (LIGHT_MODE, GL_SPECULAR, buf);
1702  glMaterialf (LIGHT_MODE, GL_SHININESS, se);
1703  }
1704 
1705  // FIXME: good candidate for caching,
1706  // transferring pixel data to OpenGL is time consuming.
1707  if (fc_mode == TEXTURE)
1708  tex = opengl_texture::create (props.get_color_data ());
1709 
1710  if (! props.facecolor_is ("none"))
1711  {
1712  if (props.get_facealpha_double () == 1)
1713  {
1714  if (fc_mode == UNIFORM || fc_mode == TEXTURE)
1715  {
1716  glColor3dv (fcolor.data ());
1717  if (fl_mode > 0)
1718  {
1719  for (int i = 0; i < 3; i++)
1720  cb[i] = as * fcolor(i);
1721  glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
1722 
1723  for (int i = 0; i < 3; i++)
1724  cb[i] = ds * fcolor(i);
1725  glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
1726  }
1727  }
1728 
1729  if (fl_mode > 0)
1730  glEnable (GL_LIGHTING);
1731  glShadeModel ((fc_mode == INTERP || fl_mode == GOURAUD) ? GL_SMOOTH
1732  : GL_FLAT);
1733  set_polygon_offset (true, 1);
1734  if (fc_mode == TEXTURE)
1735  glEnable (GL_TEXTURE_2D);
1736 
1737  for (int i = 1; i < zc; i++)
1738  {
1739  if (y_mat)
1740  {
1741  i1 = i-1;
1742  i2 = i;
1743  }
1744 
1745  for (int j = 1; j < zr; j++)
1746  {
1747 
1748  if (clip(j-1, i-1) || clip(j, i-1)
1749  || clip(j-1, i) || clip(j, i))
1750  continue;
1751 
1752  if (fc_mode == FLAT)
1753  {
1754  // "flat" only needs color at lower-left vertex
1755  if (! xfinite (c(j-1,i-1)))
1756  continue;
1757  }
1758  else if (fc_mode == INTERP)
1759  {
1760  // "interp" needs valid color at all 4 vertices
1761  if (! (xfinite (c(j-1, i-1)) && xfinite (c(j, i-1))
1762  && xfinite (c(j-1, i)) && xfinite (c(j, i))))
1763  continue;
1764  }
1765 
1766  if (x_mat)
1767  {
1768  j1 = j-1;
1769  j2 = j;
1770  }
1771 
1772  glBegin (GL_QUADS);
1773 
1774  // Vertex 1
1775  if (fc_mode == TEXTURE)
1776  tex.tex_coord (double (i-1) / (zc-1),
1777  double (j-1) / (zr-1));
1778  else if (fc_mode > 0)
1779  {
1780  // FIXME: is there a smarter way to do this?
1781  for (int k = 0; k < 3; k++)
1782  cb[k] = c(j-1, i-1, k);
1783  glColor3fv (cb);
1784 
1785  if (fl_mode > 0)
1786  {
1787  for (int k = 0; k < 3; k++)
1788  cb[k] *= as;
1789  glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
1790 
1791  for (int k = 0; k < 3; k++)
1792  cb[k] = ds * c(j-1, i-1, k);
1793  glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
1794  }
1795  }
1796  if (fl_mode > 0)
1797  {
1798  d = sqrt (n(j-1,i-1,0) * n(j-1,i-1,0)
1799  + n(j-1,i-1,1) * n(j-1,i-1,1)
1800  + n(j-1,i-1,2) * n(j-1,i-1,2));
1801  glNormal3d (n(j-1,i-1,0)/d,
1802  n(j-1,i-1,1)/d,
1803  n(j-1,i-1,2)/d);
1804  }
1805  glVertex3d (x(j1,i-1), y(j-1,i1), z(j-1,i-1));
1806 
1807  // Vertex 2
1808  if (fc_mode == TEXTURE)
1809  tex.tex_coord (double (i) / (zc-1), double (j-1) / (zr-1));
1810  else if (fc_mode == INTERP)
1811  {
1812  for (int k = 0; k < 3; k++)
1813  cb[k] = c(j-1, i, k);
1814  glColor3fv (cb);
1815 
1816  if (fl_mode > 0)
1817  {
1818  for (int k = 0; k < 3; k++)
1819  cb[k] *= as;
1820  glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
1821 
1822  for (int k = 0; k < 3; k++)
1823  cb[k] = ds * c(j-1, i, k);
1824  glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
1825  }
1826  }
1827 
1828  if (fl_mode == GOURAUD)
1829  {
1830  d = sqrt (n(j-1,i,0) * n(j-1,i,0)
1831  + n(j-1,i,1) * n(j-1,i,1)
1832  + n(j-1,i,2) * n(j-1,i,2));
1833  glNormal3d (n(j-1,i,0)/d, n(j-1,i,1)/d, n(j-1,i,2)/d);
1834  }
1835 
1836  glVertex3d (x(j1,i), y(j-1,i2), z(j-1,i));
1837 
1838  // Vertex 3
1839  if (fc_mode == TEXTURE)
1840  tex.tex_coord (double (i) / (zc-1), double (j) / (zr-1));
1841  else if (fc_mode == INTERP)
1842  {
1843  for (int k = 0; k < 3; k++)
1844  cb[k] = c(j, i, k);
1845  glColor3fv (cb);
1846 
1847  if (fl_mode > 0)
1848  {
1849  for (int k = 0; k < 3; k++)
1850  cb[k] *= as;
1851  glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
1852 
1853  for (int k = 0; k < 3; k++)
1854  cb[k] = ds * c(j, i, k);
1855  glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
1856  }
1857  }
1858  if (fl_mode == GOURAUD)
1859  {
1860  d = sqrt (n(j,i,0) * n(j,i,0)
1861  + n(j,i,1) * n(j,i,1)
1862  + n(j,i,2) * n(j,i,2));
1863  glNormal3d (n(j,i,0)/d, n(j,i,1)/d, n(j,i,2)/d);
1864  }
1865  glVertex3d (x(j2,i), y(j,i2), z(j,i));
1866 
1867  // Vertex 4
1868  if (fc_mode == TEXTURE)
1869  tex.tex_coord (double (i-1) / (zc-1), double (j) / (zr-1));
1870  else if (fc_mode == INTERP)
1871  {
1872  for (int k = 0; k < 3; k++)
1873  cb[k] = c(j, i-1, k);
1874  glColor3fv (cb);
1875 
1876  if (fl_mode > 0)
1877  {
1878  for (int k = 0; k < 3; k++)
1879  cb[k] *= as;
1880  glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
1881 
1882  for (int k = 0; k < 3; k++)
1883  cb[k] = ds * c(j, i-1, k);
1884  glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
1885  }
1886  }
1887  if (fl_mode == GOURAUD)
1888  {
1889  d = sqrt (n(j,i-1,0) * n(j,i-1,0)
1890  + n(j,i-1,1) * n(j,i-1,1)
1891  + n(j,i-1,2) * n(j,i-1,2));
1892  glNormal3d (n(j,i-1,0)/d, n(j,i-1,1)/d, n(j,i-1,2)/d);
1893  }
1894  glVertex3d (x(j2,i-1), y(j,i1), z(j,i-1));
1895 
1896  glEnd ();
1897  }
1898  }
1899 
1900  set_polygon_offset (false);
1901  if (fc_mode == TEXTURE)
1902  glDisable (GL_TEXTURE_2D);
1903 
1904  if (fl_mode > 0)
1905  glDisable (GL_LIGHTING);
1906  }
1907  else
1908  {
1909  // FIXME: implement transparency
1910  }
1911  }
1912 
1913  if (! props.edgecolor_is ("none"))
1914  {
1915  if (props.get_edgealpha_double () == 1)
1916  {
1917  if (ec_mode == UNIFORM)
1918  {
1919  glColor3dv (ecolor.data ());
1920  if (fl_mode > 0)
1921  {
1922  for (int i = 0; i < 3; i++)
1923  cb[i] = as * ecolor(i);
1924  glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
1925 
1926  for (int i = 0; i < 3; i++)
1927  cb[i] = ds * ecolor(i);
1928  glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
1929  }
1930  }
1931 
1932  if (el_mode > 0)
1933  glEnable (GL_LIGHTING);
1934  glShadeModel ((ec_mode == INTERP || el_mode == GOURAUD) ? GL_SMOOTH
1935  : GL_FLAT);
1936 
1937  set_linestyle (props.get_linestyle (), false);
1938  set_linewidth (props.get_linewidth ());
1939 
1940  // Mesh along Y-axis
1941 
1942  if (props.meshstyle_is ("both") || props.meshstyle_is ("column"))
1943  {
1944  for (int i = 0; i < zc; i++)
1945  {
1946  if (y_mat)
1947  {
1948  i1 = i-1;
1949  i2 = i;
1950  }
1951 
1952  for (int j = 1; j < zr; j++)
1953  {
1954  if (clip(j-1,i) || clip(j,i))
1955  continue;
1956 
1957  if (ec_mode == FLAT)
1958  {
1959  // "flat" only needs color at lower-left vertex
1960  if (! xfinite (c(j-1,i)))
1961  continue;
1962  }
1963  else if (ec_mode == INTERP)
1964  {
1965  // "interp" needs valid color at both vertices
1966  if (! (xfinite (c(j-1, i)) && xfinite (c(j, i))))
1967  continue;
1968  }
1969 
1970  if (x_mat)
1971  {
1972  j1 = j-1;
1973  j2 = j;
1974  }
1975 
1976  glBegin (GL_LINES);
1977 
1978  // Vertex 1
1979  if (ec_mode > 0)
1980  {
1981  for (int k = 0; k < 3; k++)
1982  cb[k] = c(j-1, i, k);
1983  glColor3fv (cb);
1984 
1985  if (fl_mode > 0)
1986  {
1987  for (int k = 0; k < 3; k++)
1988  cb[k] *= as;
1989  glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
1990 
1991  for (int k = 0; k < 3; k++)
1992  cb[k] = ds * c(j-1, i, k);
1993  glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
1994  }
1995  }
1996  if (el_mode > 0)
1997  {
1998  d = sqrt (n(j-1,i,0) * n(j-1,i,0)
1999  + n(j-1,i,1) * n(j-1,i,1)
2000  + n(j-1,i,2) * n(j-1,i,2));
2001  glNormal3d (n(j-1,i,0)/d, n(j-1,i,1)/d, n(j-1,i,2)/d);
2002  }
2003  glVertex3d (x(j1,i), y(j-1,i2), z(j-1,i));
2004 
2005  // Vertex 2
2006  if (ec_mode == INTERP)
2007  {
2008  for (int k = 0; k < 3; k++)
2009  cb[k] = c(j, i, k);
2010  glColor3fv (cb);
2011 
2012  if (fl_mode > 0)
2013  {
2014  for (int k = 0; k < 3; k++)
2015  cb[k] *= as;
2016  glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
2017 
2018  for (int k = 0; k < 3; k++)
2019  cb[k] = ds * c(j, i, k);
2020  glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
2021  }
2022  }
2023  if (el_mode == GOURAUD)
2024  {
2025  d = sqrt (n(j,i,0) * n(j,i,0)
2026  + n(j,i,1) * n(j,i,1)
2027  + n(j,i,2) * n(j,i,2));
2028  glNormal3d (n(j,i,0)/d, n(j,i,1)/d, n(j,i,2)/d);
2029  }
2030  glVertex3d (x(j2,i), y(j,i2), z(j,i));
2031 
2032  glEnd ();
2033  }
2034  }
2035  }
2036 
2037  // Mesh along X-axis
2038 
2039  if (props.meshstyle_is ("both") || props.meshstyle_is ("row"))
2040  {
2041  for (int j = 0; j < zr; j++)
2042  {
2043  if (x_mat)
2044  {
2045  j1 = j-1;
2046  j2 = j;
2047  }
2048 
2049  for (int i = 1; i < zc; i++)
2050  {
2051  if (clip(j,i-1) || clip(j,i))
2052  continue;
2053 
2054  if (ec_mode == FLAT)
2055  {
2056  // "flat" only needs color at lower-left vertex
2057  if (! xfinite (c(j,i-1)))
2058  continue;
2059  }
2060  else if (ec_mode == INTERP)
2061  {
2062  // "interp" needs valid color at both vertices
2063  if (! (xfinite (c(j, i-1)) && xfinite (c(j, i))))
2064  continue;
2065  }
2066 
2067  if (y_mat)
2068  {
2069  i1 = i-1;
2070  i2 = i;
2071  }
2072 
2073  glBegin (GL_LINES);
2074 
2075  // Vertex 1
2076  if (ec_mode > 0)
2077  {
2078  for (int k = 0; k < 3; k++)
2079  cb[k] = c(j, i-1, k);
2080  glColor3fv (cb);
2081 
2082  if (fl_mode > 0)
2083  {
2084  for (int k = 0; k < 3; k++)
2085  cb[k] *= as;
2086  glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
2087 
2088  for (int k = 0; k < 3; k++)
2089  cb[k] = ds * c(j, i-1, k);
2090  glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
2091  }
2092  }
2093  if (el_mode > 0)
2094  {
2095  d = sqrt (n(j,i-1,0) * n(j,i-1,0)
2096  + n(j,i-1,1) * n(j,i-1,1)
2097  + n(j,i-1,2) * n(j,i-1,2));
2098  glNormal3d (n(j,i-1,0)/d, n(j,i-1,1)/d, n(j,i-1,2)/d);
2099  }
2100  glVertex3d (x(j2,i-1), y(j,i1), z(j,i-1));
2101 
2102  // Vertex 2
2103  if (ec_mode == INTERP)
2104  {
2105  for (int k = 0; k < 3; k++)
2106  cb[k] = c(j, i, k);
2107  glColor3fv (cb);
2108 
2109  if (fl_mode > 0)
2110  {
2111  for (int k = 0; k < 3; k++)
2112  cb[k] *= as;
2113  glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
2114 
2115  for (int k = 0; k < 3; k++)
2116  cb[k] = ds * c(j, i, k);
2117  glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
2118  }
2119  }
2120  if (el_mode == GOURAUD)
2121  {
2122  d = sqrt (n(j,i,0) * n(j,i,0)
2123  + n(j,i,1) * n(j,i,1)
2124  + n(j,i,2) * n(j,i,2));
2125  glNormal3d (n(j,i,0)/d, n(j,i,1)/d, n(j,i,2)/d);
2126  }
2127  glVertex3d (x(j2,i), y(j,i2), z(j,i));
2128 
2129  glEnd ();
2130  }
2131  }
2132  }
2133 
2134  set_linestyle ("-");
2135  set_linewidth (0.5);
2136 
2137  if (el_mode > 0)
2138  glDisable (GL_LIGHTING);
2139  }
2140  else
2141  {
2142  // FIXME: implement transparency
2143  }
2144  }
2145 
2146  if (! props.marker_is ("none")
2147  && ! (props.markeredgecolor_is ("none")
2148  && props.markerfacecolor_is ("none")))
2149  {
2150  // FIXME: check how transparency should be handled in markers
2151  // FIXME: check what to do with marker facecolor set to auto
2152  // and facecolor set to none.
2153 
2154  bool do_edge = ! props.markeredgecolor_is ("none");
2155  bool do_face = ! props.markerfacecolor_is ("none");
2156 
2157  Matrix mecolor = props.get_markeredgecolor_rgb ();
2158  Matrix mfcolor = props.get_markerfacecolor_rgb ();
2159  Matrix cc (1, 3, 0.0);
2160 
2161  if (mecolor.numel () == 0 && props.markeredgecolor_is ("auto"))
2162  {
2163  mecolor = props.get_edgecolor_rgb ();
2164  do_edge = ! props.edgecolor_is ("none");
2165  }
2166 
2167  if (mfcolor.numel () == 0 && props.markerfacecolor_is ("auto"))
2168  {
2169  mfcolor = props.get_facecolor_rgb ();
2170  do_face = ! props.facecolor_is ("none");
2171  }
2172 
2173  if ((mecolor.numel () == 0 || mfcolor.numel () == 0)
2174  && c.numel () == 0)
2175  c = props.get_color_data ().array_value ();
2176 
2177  init_marker (props.get_marker (), props.get_markersize (),
2178  props.get_linewidth ());
2179 
2180  for (int i = 0; i < zc; i++)
2181  {
2182  if (y_mat)
2183  i1 = i;
2184 
2185  for (int j = 0; j < zr; j++)
2186  {
2187  if (clip(j,i))
2188  continue;
2189 
2190  if (x_mat)
2191  j1 = j;
2192 
2193  if ((do_edge && mecolor.numel () == 0)
2194  || (do_face && mfcolor.numel () == 0))
2195  {
2196  if (! xfinite (c(j,i)))
2197  continue; // Skip NaNs in color data
2198 
2199  for (int k = 0; k < 3; k++)
2200  cc(k) = c(j,i,k);
2201  }
2202 
2203  Matrix lc = (do_edge ? (mecolor.numel () == 0 ? cc : mecolor)
2204  : Matrix ());
2205  Matrix fc = (do_face ? (mfcolor.numel () == 0 ? cc : mfcolor)
2206  : Matrix ());
2207 
2208  draw_marker (x(j1,i), y(j,i1), z(j,i), lc, fc);
2209  }
2210  }
2211 
2212  end_marker ();
2213  }
2214 }
2215 
2216 // FIXME: global optimization (rendering, data structures...),
2217 // there is probably a smarter/faster/less-memory-consuming way to do this.
2218 void
2219 opengl_renderer::draw_patch (const patch::properties &props)
2220 {
2221  // Do not render if the patch has incoherent data
2222  std::string msg;
2223  if (props.has_bad_data (msg))
2224  {
2225  warning ("opengl_renderer: %s. Not rendering.", msg.c_str ());
2226  return;
2227  }
2228 
2229  const Matrix f = props.get_faces ().matrix_value ();
2230  const Matrix v = xform.scale (props.get_vertices ().matrix_value ());
2231  Matrix c;
2232  const Matrix n = props.get_vertexnormals ().matrix_value ();
2233  Matrix a;
2234 
2235  int nv = v.rows ();
2236  int nf = f.rows ();
2237  int fcmax = f.columns ();
2238 
2239  bool has_z = (v.columns () > 2);
2240  bool has_facecolor = false;
2241  bool has_facealpha = false;
2242 
2243  int fc_mode = ((props.facecolor_is ("none")
2244  || props.facecolor_is_rgb ()) ? 0 :
2245  (props.facecolor_is ("flat") ? 1 : 2));
2246  int fl_mode = (props.facelighting_is ("none") ? 0 :
2247  (props.facelighting_is ("flat") ? 1 : 2));
2248  int fa_mode = (props.facealpha_is_double () ? 0 :
2249  (props.facealpha_is ("flat") ? 1 : 2));
2250  int ec_mode = ((props.edgecolor_is ("none")
2251  || props.edgecolor_is_rgb ()) ? 0 :
2252  (props.edgecolor_is ("flat") ? 1 : 2));
2253  int el_mode = (props.edgelighting_is ("none") ? 0 :
2254  (props.edgelighting_is ("flat") ? 1 : 2));
2255  int ea_mode = (props.edgealpha_is_double () ? 0 :
2256  (props.edgealpha_is ("flat") ? 1 : 2));
2257 
2258  Matrix fcolor = props.get_facecolor_rgb ();
2259  Matrix ecolor = props.get_edgecolor_rgb ();
2260 
2261  float as = props.get_ambientstrength ();
2262  float ds = props.get_diffusestrength ();
2263  float ss = props.get_specularstrength ();
2264  float se = props.get_specularexponent ();
2265 
2266  boolMatrix clip (1, nv, false);
2267 
2268  if (has_z)
2269  for (int i = 0; i < nv; i++)
2270  clip(i) = is_nan_or_inf (v(i,0), v(i,1), v(i,2));
2271  else
2272  for (int i = 0; i < nv; i++)
2273  clip(i) = is_nan_or_inf (v(i,0), v(i,1), 0);
2274 
2275  boolMatrix clip_f (1, nf, false);
2276  Array<int> count_f (dim_vector (nf, 1), 0);
2277 
2278  for (int i = 0; i < nf; i++)
2279  {
2280  bool fclip = false;
2281  int count = 0;
2282 
2283  for (int j = 0; j < fcmax && ! xisnan (f(i,j)); j++, count++)
2284  fclip = (fclip || clip(int (f(i,j) - 1)));
2285 
2286  clip_f(i) = fclip;
2287  count_f(i) = count;
2288  }
2289 
2290  if (fc_mode > 0 || ec_mode > 0)
2291  {
2292  c = props.get_color_data ().matrix_value ();
2293 
2294  if (c.rows () == 1)
2295  {
2296  // Single color specifications, we can simplify a little bit
2297 
2298  if (fc_mode > 0)
2299  {
2300  fcolor = c;
2301  fc_mode = UNIFORM;
2302  }
2303 
2304  if (ec_mode > 0)
2305  {
2306  ecolor = c;
2307  ec_mode = UNIFORM;
2308  }
2309 
2310  c = Matrix ();
2311  }
2312  else
2313  has_facecolor = ((c.numel () > 0) && (c.rows () == f.rows ()));
2314  }
2315 
2316  if (fa_mode > 0 || ea_mode > 0)
2317  {
2318  // FIXME: retrieve alpha data from patch object
2319  //a = props.get_alpha_data ();
2320  has_facealpha = ((a.numel () > 0) && (a.rows () == f.rows ()));
2321  }
2322 
2323  octave_idx_type fr = f.rows ();
2324  std::vector<vertex_data> vdata (f.numel ());
2325 
2326  for (int i = 0; i < nf; i++)
2327  for (int j = 0; j < count_f(i); j++)
2328  {
2329  int idx = int (f(i,j) - 1);
2330 
2331  Matrix vv (1, 3, 0.0);
2332  Matrix cc;
2333  Matrix nn (1, 3, 0.0);
2334  double aa = 1.0;
2335 
2336  vv(0) = v(idx,0); vv(1) = v(idx,1);
2337  if (has_z)
2338  vv(2) = v(idx,2);
2339  // FIXME: uncomment when patch object has normal computation
2340  //nn(0) = n(idx,0); nn(1) = n(idx,1); nn(2) = n(idx,2);
2341  if (c.numel () > 0)
2342  {
2343  cc.resize (1, 3);
2344  if (has_facecolor)
2345  cc(0) = c(i,0), cc(1) = c(i,1), cc(2) = c(i,2);
2346  else
2347  cc(0) = c(idx,0), cc(1) = c(idx,1), cc(2) = c(idx,2);
2348  }
2349  if (a.numel () > 0)
2350  {
2351  if (has_facealpha)
2352  aa = a(i);
2353  else
2354  aa = a(idx);
2355  }
2356 
2357  vdata[i+j*fr] = vertex_data (vv, cc, nn, aa, as, ds, ss, se);
2358  }
2359 
2360  if (fl_mode > 0 || el_mode > 0)
2361  {
2362  float buf[4] = { ss, ss, ss, 1 };
2363 
2364  glMaterialfv (LIGHT_MODE, GL_SPECULAR, buf);
2365  glMaterialf (LIGHT_MODE, GL_SHININESS, se);
2366  }
2367 
2368  if (! props.facecolor_is ("none"))
2369  {
2370  // FIXME: adapt to double-radio property
2371  if (props.get_facealpha_double () == 1)
2372  {
2373  if (fc_mode == UNIFORM)
2374  {
2375  glColor3dv (fcolor.data ());
2376  if (fl_mode > 0)
2377  {
2378  float cb[4] = { 0, 0, 0, 1 };
2379 
2380  for (int i = 0; i < 3; i++)
2381  cb[i] = (as * fcolor(i));
2382  glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
2383 
2384  for (int i = 0; i < 3; i++)
2385  cb[i] = ds * fcolor(i);
2386  glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
2387  }
2388  }
2389 
2390  if (fl_mode > 0)
2391  glEnable (GL_LIGHTING);
2392 
2393  // NOTE: Push filled part of patch backwards to avoid Z-fighting with
2394  // tesselator outline. A value of 1.0 seems to work fine. Value
2395  // can't be too large or the patch will be pushed below the axes
2396  // planes at +2.5.
2397  patch_tesselator tess (this, fc_mode, fl_mode, 1.0);
2398 
2399  for (int i = 0; i < nf; i++)
2400  {
2401  if (clip_f(i))
2402  continue;
2403 
2404  tess.begin_polygon (true);
2405  tess.begin_contour ();
2406 
2407  // Add vertices in reverse order for Matlab compatibility
2408  for (int j = count_f(i)-1; j > 0; j--)
2409  {
2410  vertex_data::vertex_data_rep *vv = vdata[i+j*fr].get_rep ();
2411 
2412  tess.add_vertex (vv->coords.fortran_vec (), vv);
2413  }
2414 
2415  if (count_f(i) > 0)
2416  {
2417  vertex_data::vertex_data_rep *vv = vdata[i].get_rep ();
2418 
2419  if (fc_mode == FLAT)
2420  {
2421  // For "flat" shading, use color of 1st vertex.
2422  Matrix col = vv->color;
2423 
2424  if (col.numel () == 3)
2425  {
2426  glColor3dv (col.data ());
2427  if (fl_mode > 0)
2428  {
2429  float cb[4] = { 0, 0, 0, 1 };
2430 
2431  for (int k = 0; k < 3; k++)
2432  cb[k] = (vv->ambient * col(k));
2433  glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
2434 
2435  for (int k = 0; k < 3; k++)
2436  cb[k] = (vv->diffuse * col(k));
2437  glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
2438  }
2439  }
2440  }
2441 
2442  tess.add_vertex (vv->coords.fortran_vec (), vv);
2443  }
2444 
2445  tess.end_contour ();
2446  tess.end_polygon ();
2447  }
2448 
2449  if (fl_mode > 0)
2450  glDisable (GL_LIGHTING);
2451  }
2452  else
2453  {
2454  // FIXME: implement transparency
2455  }
2456  }
2457 
2458  if (! props.edgecolor_is ("none"))
2459  {
2460  // FIXME: adapt to double-radio property
2461  if (props.get_edgealpha_double () == 1)
2462  {
2463  if (ec_mode == UNIFORM)
2464  {
2465  glColor3dv (ecolor.data ());
2466  if (el_mode > 0)
2467  {
2468  float cb[4] = { 0, 0, 0, 1 };
2469 
2470  for (int i = 0; i < 3; i++)
2471  cb[i] = (as * ecolor(i));
2472  glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
2473 
2474  for (int i = 0; i < 3; i++)
2475  cb[i] = ds * ecolor(i);
2476  glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
2477  }
2478  }
2479 
2480  if (el_mode > 0)
2481  glEnable (GL_LIGHTING);
2482 
2483  set_linestyle (props.get_linestyle (), false);
2484  set_linewidth (props.get_linewidth ());
2485 
2486  // NOTE: patch contour cannot be offset. Offset must occur with the
2487  // filled portion of the patch above. The tesselator uses
2488  // GLU_TESS_BOUNDARY_ONLY to get the outline of the patch and OpenGL
2489  // automatically sets the glType to GL_LINE_LOOP. This primitive is
2490  // not supported by glPolygonOffset which is used to do Z offsets.
2491  patch_tesselator tess (this, ec_mode, el_mode);
2492 
2493  for (int i = 0; i < nf; i++)
2494  {
2495  if (clip_f(i))
2496  {
2497  // This is an unclosed contour. Draw it as a line.
2498  bool flag = false;
2499 
2500  glShadeModel ((ec_mode == INTERP || el_mode == GOURAUD)
2501  ? GL_SMOOTH : GL_FLAT);
2502 
2503  // Add vertices in reverse order for Matlab compatibility
2504  for (int j = count_f(i)-1; j >= 0; j--)
2505  {
2506  if (! clip(int (f(i,j) - 1)))
2507  {
2508  vertex_data::vertex_data_rep *vv
2509  = vdata[i+j*fr].get_rep ();
2510  const Matrix m = vv->coords;
2511  if (! flag)
2512  {
2513  flag = true;
2514  glBegin (GL_LINE_STRIP);
2515  }
2516  if (ec_mode != UNIFORM)
2517  {
2518  Matrix col = vv->color;
2519 
2520  if (col.numel () == 3)
2521  glColor3dv (col.data ());
2522  }
2523  glVertex3d (m(0), m(1), m(2));
2524  }
2525  else if (flag)
2526  {
2527  flag = false;
2528  glEnd ();
2529  }
2530  }
2531  // Do loop body with vertex N to "close" GL_LINE_STRIP
2532  // from vertex 0 to vertex N.
2533  int j = count_f(i)-1;
2534  if (flag && ! clip(int (f(i,j) - 1)))
2535  {
2536  vertex_data::vertex_data_rep *vv
2537  = vdata[i+j*fr].get_rep ();
2538  const Matrix m = vv->coords;
2539  if (ec_mode != UNIFORM)
2540  {
2541  Matrix col = vv->color;
2542 
2543  if (col.numel () == 3)
2544  glColor3dv (col.data ());
2545  }
2546  glVertex3d (m(0), m(1), m(2));
2547  }
2548 
2549  if (flag)
2550  glEnd ();
2551  }
2552  else // Normal edge contour drawn with tesselator
2553  {
2554  tess.begin_polygon (false);
2555  tess.begin_contour ();
2556 
2557  for (int j = count_f(i)-1; j >= 0; j--)
2558  {
2559  vertex_data::vertex_data_rep *vv
2560  = vdata[i+j*fr].get_rep ();
2561  tess.add_vertex (vv->coords.fortran_vec (), vv);
2562  }
2563 
2564  tess.end_contour ();
2565  tess.end_polygon ();
2566  }
2567  }
2568 
2569  set_linestyle ("-");
2570  set_linewidth (0.5);
2571 
2572  if (el_mode > 0)
2573  glDisable (GL_LIGHTING);
2574  }
2575  else
2576  {
2577  // FIXME: implement transparency
2578  }
2579  }
2580 
2581  if (! props.marker_is ("none")
2582  && ! (props.markeredgecolor_is ("none")
2583  && props.markerfacecolor_is ("none")))
2584  {
2585  bool do_edge = ! props.markeredgecolor_is ("none");
2586  bool do_face = ! props.markerfacecolor_is ("none");
2587 
2588  Matrix mecolor = props.get_markeredgecolor_rgb ();
2589  Matrix mfcolor = props.get_markerfacecolor_rgb ();
2590 
2591  bool has_markerfacecolor = false;
2592 
2593  if ((mecolor.numel () == 0 && ! props.markeredgecolor_is ("none"))
2594  || (mfcolor.numel () == 0 && ! props.markerfacecolor_is ("none")))
2595  {
2596  Matrix mc = props.get_color_data ().matrix_value ();
2597 
2598  if (mc.rows () == 1)
2599  {
2600  // Single color specifications, we can simplify a little bit
2601 
2602  if (mfcolor.numel () == 0
2603  && ! props.markerfacecolor_is ("none"))
2604  mfcolor = mc;
2605 
2606  if (mecolor.numel () == 0
2607  && ! props.markeredgecolor_is ("none"))
2608  mecolor = mc;
2609  }
2610  else
2611  {
2612  if (c.numel () == 0)
2613  c = props.get_color_data ().matrix_value ();
2614  has_markerfacecolor = ((c.numel () > 0)
2615  && (c.rows () == f.rows ()));
2616  }
2617  }
2618 
2619 
2620  init_marker (props.get_marker (), props.get_markersize (),
2621  props.get_linewidth ());
2622 
2623  for (int i = 0; i < nf; i++)
2624  for (int j = 0; j < count_f(i); j++)
2625  {
2626  int idx = int (f(i,j) - 1);
2627 
2628  if (clip(idx))
2629  continue;
2630 
2631  Matrix cc;
2632  if (c.numel () > 0)
2633  {
2634  cc.resize (1, 3);
2635  if (has_markerfacecolor)
2636  cc(0) = c(i,0), cc(1) = c(i,1), cc(2) = c(i,2);
2637  else
2638  cc(0) = c(idx,0), cc(1) = c(idx,1), cc(2) = c(idx,2);
2639  }
2640 
2641  Matrix lc = (do_edge ? (mecolor.numel () == 0 ? cc : mecolor)
2642  : Matrix ());
2643  Matrix fc = (do_face ? (mfcolor.numel () == 0 ? cc : mfcolor)
2644  : Matrix ());
2645 
2646  draw_marker (v(idx,0), v(idx,1), (has_z ? v(idx,2) : 0), lc, fc);
2647  }
2648 
2649  end_marker ();
2650  }
2651 }
2652 
2653 void
2654 opengl_renderer::draw_hggroup (const hggroup::properties &props)
2655 {
2656  draw (props.get_children ());
2657 }
2658 
2659 void
2660 opengl_renderer::draw_text (const text::properties& props)
2661 {
2662  if (props.get_string ().is_empty ())
2663  return;
2664 
2665  set_font (props);
2666 
2667  Matrix pos = xform.scale (props.get_data_position ());
2668  const Matrix bbox = props.get_extent_matrix ();
2669 
2670  // FIXME: handle margin and surrounding box
2671  bool blend = glIsEnabled (GL_BLEND);
2672 
2673  glEnable (GL_BLEND);
2674  glEnable (GL_ALPHA_TEST);
2675  glRasterPos3d (pos(0), pos(1), pos.numel () > 2 ? pos(2) : 0.0);
2676  glBitmap (0, 0, 0, 0, bbox(0), bbox(1), 0);
2677  glDrawPixels (bbox(2), bbox(3),
2678  GL_RGBA, GL_UNSIGNED_BYTE, props.get_pixels ().data ());
2679  glDisable (GL_ALPHA_TEST);
2680  if (! blend)
2681  glDisable (GL_BLEND);
2682 
2683 }
2684 
2685 void
2686 opengl_renderer::draw_image (const image::properties& props)
2687 {
2688  octave_value cdata = props.get_color_data ();
2689  dim_vector dv (cdata.dims ());
2690  int h = dv(0);
2691  int w = dv(1);
2692 
2693  Matrix x = props.get_xdata ().matrix_value ();
2694  Matrix y = props.get_ydata ().matrix_value ();
2695 
2696  // Someone wants us to draw an empty image? No way.
2697  if (x.is_empty () || y.is_empty ())
2698  return;
2699 
2700  if (w > 1 && x(1) == x(0))
2701  x(1) = x(1) + (w-1);
2702 
2703  if (h > 1 && y(1) == y(0))
2704  y(1) = y(1) + (h-1);
2705 
2706  const ColumnVector p0 = xform.transform (x(0), y(0), 0);
2707  const ColumnVector p1 = xform.transform (x(1), y(1), 0);
2708 
2709  if (xisnan (p0(0)) || xisnan (p0(1)) || xisnan (p1(0)) || xisnan (p1(1)))
2710  {
2711  warning ("opengl_renderer: image X,Y data too large to draw");
2712  return;
2713  }
2714 
2715  // image pixel size in screen pixel units
2716  float pix_dx, pix_dy;
2717  // image pixel size in normalized units
2718  float nor_dx, nor_dy;
2719 
2720  if (w > 1)
2721  {
2722  pix_dx = (p1(0) - p0(0))/(w-1);
2723  nor_dx = (x(1) - x(0))/(w-1);
2724  }
2725  else
2726  {
2727  const ColumnVector p1w = xform.transform (x(1) + 1, y(1), 0);
2728  pix_dx = p1w(0) - p0(0);
2729  nor_dx = 1;
2730  }
2731 
2732  if (h > 1)
2733  {
2734  pix_dy = (p1(1) - p0(1))/(h-1);
2735  nor_dy = (y(1) - y(0))/(h-1);
2736  }
2737  else
2738  {
2739  const ColumnVector p1h = xform.transform (x(1), y(1) + 1, 0);
2740  pix_dy = p1h(1) - p0(1);
2741  nor_dy = 1;
2742  }
2743 
2744  // OpenGL won't draw any of the image if it's origin is outside the
2745  // viewport/clipping plane so we must do the clipping ourselves.
2746 
2747  int j0, j1, i0, i1;
2748  j0 = 0, j1 = w;
2749  i0 = 0, i1 = h;
2750 
2751  float im_xmin = x(0) - nor_dx/2;
2752  float im_xmax = x(1) + nor_dx/2;
2753  float im_ymin = y(0) - nor_dy/2;
2754  float im_ymax = y(1) + nor_dy/2;
2755  if (props.is_clipping ()) // clip to axes
2756  {
2757  if (im_xmin < xmin)
2758  j0 += (xmin - im_xmin)/nor_dx + 1;
2759  if (im_xmax > xmax)
2760  j1 -= (im_xmax - xmax)/nor_dx ;
2761 
2762  if (im_ymin < ymin)
2763  i0 += (ymin - im_ymin)/nor_dy + 1;
2764  if (im_ymax > ymax)
2765  i1 -= (im_ymax - ymax)/nor_dy;
2766  }
2767  else // clip to viewport
2768  {
2769  GLfloat vp[4];
2770  glGetFloatv (GL_VIEWPORT, vp);
2771  // FIXME: actually add the code to do it!
2772 
2773  }
2774 
2775  if (i0 >= i1 || j0 >= j1)
2776  return;
2777 
2778  glPixelZoom (pix_dx, -pix_dy);
2779  glRasterPos3d (im_xmin + nor_dx*j0, im_ymin + nor_dy*i0, 0);
2780 
2781  // by default this is 4
2782  glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
2783 
2784  // Expect RGB data
2785  if (dv.length () == 3 && dv(2) == 3)
2786  {
2787  if (cdata.is_double_type ())
2788  {
2789  const NDArray xcdata = cdata.array_value ();
2790 
2791  OCTAVE_LOCAL_BUFFER (GLfloat, a, 3*(j1-j0)*(i1-i0));
2792 
2793  for (int i = i0; i < i1; i++)
2794  {
2795  for (int j = j0, idx = (i-i0)*(j1-j0)*3; j < j1; j++, idx += 3)
2796  {
2797  a[idx] = xcdata(i,j,0);
2798  a[idx+1] = xcdata(i,j,1);
2799  a[idx+2] = xcdata(i,j,2);
2800  }
2801  }
2802 
2803  draw_pixels (j1-j0, i1-i0, GL_RGB, GL_FLOAT, a);
2804 
2805  }
2806  else if (cdata.is_single_type ())
2807  {
2808  const FloatNDArray xcdata = cdata.float_array_value ();
2809 
2810  OCTAVE_LOCAL_BUFFER (GLfloat, a, 3*(j1-j0)*(i1-i0));
2811 
2812  for (int i = i0; i < i1; i++)
2813  {
2814  for (int j = j0, idx = (i-i0)*(j1-j0)*3; j < j1; j++, idx += 3)
2815  {
2816  a[idx] = xcdata(i,j,0);
2817  a[idx+1] = xcdata(i,j,1);
2818  a[idx+2] = xcdata(i,j,2);
2819  }
2820  }
2821 
2822  draw_pixels (j1-j0, i1-i0, GL_RGB, GL_FLOAT, a);
2823 
2824  }
2825  else if (cdata.is_uint8_type ())
2826  {
2827  const uint8NDArray xcdata = cdata.uint8_array_value ();
2828 
2829  OCTAVE_LOCAL_BUFFER (GLubyte, a, 3*(j1-j0)*(i1-i0));
2830 
2831  for (int i = i0; i < i1; i++)
2832  {
2833  for (int j = j0, idx = (i-i0)*(j1-j0)*3; j < j1; j++, idx += 3)
2834  {
2835  a[idx] = xcdata(i,j,0);
2836  a[idx+1] = xcdata(i,j,1);
2837  a[idx+2] = xcdata(i,j,2);
2838  }
2839  }
2840 
2841  draw_pixels (j1-j0, i1-i0, GL_RGB, GL_UNSIGNED_BYTE, a);
2842 
2843  }
2844  else if (cdata.is_uint16_type ())
2845  {
2846  const uint16NDArray xcdata = cdata.uint16_array_value ();
2847 
2848  OCTAVE_LOCAL_BUFFER (GLushort, a, 3*(j1-j0)*(i1-i0));
2849 
2850  for (int i = i0; i < i1; i++)
2851  {
2852  for (int j = j0, idx = (i-i0)*(j1-j0)*3; j < j1; j++, idx += 3)
2853  {
2854  a[idx] = xcdata(i,j,0);
2855  a[idx+1] = xcdata(i,j,1);
2856  a[idx+2] = xcdata(i,j,2);
2857  }
2858  }
2859 
2860  draw_pixels (j1-j0, i1-i0, GL_RGB, GL_UNSIGNED_SHORT, a);
2861 
2862  }
2863  else
2864  warning ("opengl_renderer: invalid image data type (expected double, single, uint8, or uint16)");
2865  }
2866  else
2867  warning ("opengl_renderer: invalid image size (expected MxNx3 or MxN)");
2868 
2869  glPixelZoom (1, 1);
2870 }
2871 
2872 void
2873 opengl_renderer::set_viewport (int w, int h)
2874 {
2875  glViewport (0, 0, w, h);
2876 }
2877 
2878 void
2879 opengl_renderer::draw_pixels (GLsizei width, GLsizei height, GLenum format,
2880  GLenum type, const GLvoid *data)
2881 {
2882  glDrawPixels (width, height, format, type, data);
2883 }
2884 
2885 void
2886 opengl_renderer::set_color (const Matrix& c)
2887 {
2888  glColor3dv (c.data ());
2889 #if HAVE_FREETYPE
2890  text_renderer.set_color (c);
2891 #endif
2892 }
2893 
2894 void
2895 opengl_renderer::set_font (const base_properties& props)
2896 {
2897 #if HAVE_FREETYPE
2898  text_renderer.set_font (props.get ("fontname").string_value (),
2899  props.get ("fontweight").string_value (),
2900  props.get ("fontangle").string_value (),
2901  props.get ("fontsize_points").double_value ());
2902 #endif
2903 }
2904 
2905 void
2906 opengl_renderer::set_polygon_offset (bool on, float offset)
2907 {
2908  if (on)
2909  {
2910  glEnable (GL_POLYGON_OFFSET_FILL);
2911  glEnable (GL_POLYGON_OFFSET_LINE);
2912  glPolygonOffset (offset, offset);
2913  }
2914  else
2915  {
2916  glDisable (GL_POLYGON_OFFSET_FILL);
2917  glDisable (GL_POLYGON_OFFSET_LINE);
2918  }
2919 }
2920 
2921 void
2922 opengl_renderer::set_linewidth (float w)
2923 {
2924  glLineWidth (w);
2925 }
2926 
2927 void
2928 opengl_renderer::set_linestyle (const std::string& s, bool use_stipple)
2929 {
2930  bool solid = false;
2931 
2932  if (s == "-")
2933  {
2934  glLineStipple (1, static_cast<unsigned short> (0xFFFF));
2935  solid = true;
2936  }
2937  else if (s == ":")
2938  glLineStipple (1, static_cast<unsigned short> (0x8888));
2939  else if (s == "--")
2940  glLineStipple (1, static_cast<unsigned short> (0xF0F0));
2941  else if (s == "-.")
2942  glLineStipple (1, static_cast<unsigned short> (0x020F));
2943  else
2944  glLineStipple (1, static_cast<unsigned short> (0x0000));
2945 
2946  if (solid && ! use_stipple)
2947  glDisable (GL_LINE_STIPPLE);
2948  else
2949  glEnable (GL_LINE_STIPPLE);
2950 }
2951 
2952 void
2953 opengl_renderer::set_clipbox (double x1, double x2, double y1, double y2,
2954  double z1, double z2)
2955 {
2956  double dx = (x2-x1);
2957  double dy = (y2-y1);
2958  double dz = (z2-z1);
2959 
2960  x1 -= 0.001*dx; x2 += 0.001*dx;
2961  y1 -= 0.001*dy; y2 += 0.001*dy;
2962  z1 -= 0.001*dz; z2 += 0.001*dz;
2963 
2964  ColumnVector p (4, 0.0);
2965 
2966  p(0) = -1; p(3) = x2;
2967  glClipPlane (GL_CLIP_PLANE0, p.data ());
2968  p(0) = 1; p(3) = -x1;
2969  glClipPlane (GL_CLIP_PLANE1, p.data ());
2970  p(0) = 0; p(1) = -1; p(3) = y2;
2971  glClipPlane (GL_CLIP_PLANE2, p.data ());
2972  p(1) = 1; p(3) = -y1;
2973  glClipPlane (GL_CLIP_PLANE3, p.data ());
2974  p(1) = 0; p(2) = -1; p(3) = z2;
2975  glClipPlane (GL_CLIP_PLANE4, p.data ());
2976  p(2) = 1; p(3) = -z1;
2977  glClipPlane (GL_CLIP_PLANE5, p.data ());
2978 
2979  xmin = x1; xmax = x2;
2980  ymin = y1; ymax = y2;
2981  zmin = z1; zmax = z2;
2982 }
2983 
2984 void
2985 opengl_renderer::set_clipping (bool enable)
2986 {
2987  bool has_clipping = (glIsEnabled (GL_CLIP_PLANE0) == GL_TRUE);
2988 
2989  if (enable != has_clipping)
2990  {
2991  if (enable)
2992  for (int i = 0; i < 6; i++)
2993  glEnable (GL_CLIP_PLANE0+i);
2994  else
2995  for (int i = 0; i < 6; i++)
2996  glDisable (GL_CLIP_PLANE0+i);
2997  }
2998 }
2999 
3000 void
3001 opengl_renderer::init_marker (const std::string& m, double size, float width)
3002 {
3003 #if defined (HAVE_FRAMEWORK_OPENGL)
3004  GLint vw[4];
3005 #else
3006  int vw[4];
3007 #endif
3008 
3009  glGetIntegerv (GL_VIEWPORT, vw);
3010 
3011  glMatrixMode (GL_PROJECTION);
3012  glPushMatrix ();
3013  glLoadIdentity ();
3014  glOrtho (0, vw[2], vw[3], 0, xZ1, xZ2);
3015  glMatrixMode (GL_MODELVIEW);
3016  glPushMatrix ();
3017 
3018  set_clipping (false);
3019  set_linewidth (width);
3020 
3021  marker_id = make_marker_list (m, size, false);
3022  filled_marker_id = make_marker_list (m, size, true);
3023 }
3024 
3025 void
3026 opengl_renderer::end_marker (void)
3027 {
3028  glDeleteLists (marker_id, 1);
3029  glDeleteLists (filled_marker_id, 1);
3030 
3031  glMatrixMode (GL_MODELVIEW);
3032  glPopMatrix ();
3033  glMatrixMode (GL_PROJECTION);
3034  glPopMatrix ();
3035  set_linewidth (0.5f);
3036 }
3037 
3038 void
3039 opengl_renderer::draw_marker (double x, double y, double z,
3040  const Matrix& lc, const Matrix& fc)
3041 {
3042  ColumnVector tmp = xform.transform (x, y, z, false);
3043 
3044  glLoadIdentity ();
3045  glTranslated (tmp(0), tmp(1), -tmp(2));
3046 
3047  if (filled_marker_id > 0 && fc.numel () > 0)
3048  {
3049  glColor3dv (fc.data ());
3050  set_polygon_offset (true, -1.0);
3051  glCallList (filled_marker_id);
3052  if (lc.numel () > 0)
3053  {
3054  glColor3dv (lc.data ());
3055  glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
3056  glEdgeFlag (GL_TRUE);
3057  set_polygon_offset (true, -2.0);
3058  glCallList (filled_marker_id);
3059  glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
3060  }
3061  set_polygon_offset (false);
3062  }
3063  else if (marker_id > 0 && lc.numel () > 0)
3064  {
3065  glColor3dv (lc.data ());
3066  glCallList (marker_id);
3067  }
3068 }
3069 
3070 unsigned int
3071 opengl_renderer::make_marker_list (const std::string& marker, double size,
3072  bool filled) const
3073 {
3074  char c = marker[0];
3075 
3076  if (filled && (c == '+' || c == 'x' || c == '*' || c == '.'))
3077  return 0;
3078 
3079  unsigned int ID = glGenLists (1);
3080  double sz = size * toolkit.get_screen_resolution () / 72.0;
3081 
3082  // constants for the * marker
3083  const double sqrt2d4 = 0.35355339059327;
3084  double tt = sz*sqrt2d4;
3085 
3086  glNewList (ID, GL_COMPILE);
3087 
3088  switch (marker[0])
3089  {
3090  case '+':
3091  glBegin (GL_LINES);
3092  glVertex2d (-sz/2, 0);
3093  glVertex2d (sz/2, 0);
3094  glVertex2d (0, -sz/2);
3095  glVertex2d (0, sz/2);
3096  glEnd ();
3097  break;
3098  case 'x':
3099  glBegin (GL_LINES);
3100  glVertex2d (-sz/2, -sz/2);
3101  glVertex2d (sz/2, sz/2);
3102  glVertex2d (-sz/2, sz/2);
3103  glVertex2d (sz/2, -sz/2);
3104  glEnd ();
3105  break;
3106  case '*':
3107  glBegin (GL_LINES);
3108  glVertex2d (-sz/2, 0);
3109  glVertex2d (sz/2, 0);
3110  glVertex2d (0, -sz/2);
3111  glVertex2d (0, sz/2);
3112  glVertex2d (-tt, -tt);
3113  glVertex2d (+tt, +tt);
3114  glVertex2d (-tt, +tt);
3115  glVertex2d (+tt, -tt);
3116  glEnd ();
3117  break;
3118  case '.':
3119  {
3120  double ang_step = M_PI / 5;
3121 
3122  glBegin (GL_POLYGON);
3123  for (double ang = 0; ang < (2*M_PI); ang += ang_step)
3124  glVertex2d (sz*cos (ang)/3, sz*sin (ang)/3);
3125  glEnd ();
3126  }
3127  break;
3128  case 's':
3129  glBegin ((filled ? GL_POLYGON : GL_LINE_LOOP));
3130  glVertex2d (-sz/2, -sz/2);
3131  glVertex2d (-sz/2, sz/2);
3132  glVertex2d (sz/2, sz/2);
3133  glVertex2d (sz/2, -sz/2);
3134  glEnd ();
3135  break;
3136  case 'o':
3137  {
3138  double ang_step = M_PI / 5;
3139 
3140  glBegin ((filled ? GL_POLYGON : GL_LINE_LOOP));
3141  for (double ang = 0; ang < (2*M_PI); ang += ang_step)
3142  glVertex2d (sz*cos (ang)/2, sz*sin (ang)/2);
3143  glEnd ();
3144  }
3145  break;
3146  case 'd':
3147  glBegin ((filled ? GL_POLYGON : GL_LINE_LOOP));
3148  glVertex2d (0, -sz/2);
3149  glVertex2d (sz/2, 0);
3150  glVertex2d (0, sz/2);
3151  glVertex2d (-sz/2, 0);
3152  glEnd ();
3153  break;
3154  case 'v':
3155  glBegin ((filled ? GL_POLYGON : GL_LINE_LOOP));
3156  glVertex2d (0, sz/2);
3157  glVertex2d (sz/2, -sz/2);
3158  glVertex2d (-sz/2, -sz/2);
3159  glEnd ();
3160  break;
3161  case '^':
3162  glBegin ((filled ? GL_POLYGON : GL_LINE_LOOP));
3163  glVertex2d (0, -sz/2);
3164  glVertex2d (-sz/2, sz/2);
3165  glVertex2d (sz/2, sz/2);
3166  glEnd ();
3167  break;
3168  case '>':
3169  glBegin ((filled ? GL_POLYGON : GL_LINE_LOOP));
3170  glVertex2d (sz/2, 0);
3171  glVertex2d (-sz/2, sz/2);
3172  glVertex2d (-sz/2, -sz/2);
3173  glEnd ();
3174  break;
3175  case '<':
3176  glBegin ((filled ? GL_POLYGON : GL_LINE_LOOP));
3177  glVertex2d (-sz/2, 0);
3178  glVertex2d (sz/2, -sz/2);
3179  glVertex2d (sz/2, sz/2);
3180  glEnd ();
3181  break;
3182  case 'p':
3183  {
3184  double ang;
3185  double r;
3186  double dr = 1.0 - sin (M_PI/10)/sin (3*M_PI/10)*1.02;
3187 
3188  glBegin ((filled ? GL_POLYGON : GL_LINE_LOOP));
3189  for (int i = 0; i < 2*5; i++)
3190  {
3191  ang = (-0.5 + double(i+1)/5) * M_PI;
3192  r = 1.0 - (dr * fmod (double(i+1), 2.0));
3193  glVertex2d (sz*r*cos (ang)/2, sz*r*sin (ang)/2);
3194  }
3195  glEnd ();
3196  }
3197  break;
3198  case 'h':
3199  {
3200  double ang;
3201  double r;
3202  double dr = 1.0 - 0.5/sin (M_PI/3)*1.02;
3203 
3204  glBegin ((filled ? GL_POLYGON : GL_LINE_LOOP));
3205  for (int i = 0; i < 2*6; i++)
3206  {
3207  ang = (0.5 + double(i+1)/6.0) * M_PI;
3208  r = 1.0 - (dr * fmod (double(i+1), 2.0));
3209  glVertex2d (sz*r*cos (ang)/2, sz*r*sin (ang)/2);
3210  }
3211  glEnd ();
3212  }
3213  break;
3214  default:
3215  warning ("opengl_renderer: unsupported marker '%s'", marker.c_str ());
3216  break;
3217  }
3218 
3219  glEndList ();
3220 
3221  return ID;
3222 }
3223 
3224 void
3225 opengl_renderer::text_to_pixels (const std::string& txt,
3226  uint8NDArray& pixels,
3227  Matrix& bbox,
3228  int halign, int valign, double rotation)
3229 {
3230 #if HAVE_FREETYPE
3231  text_renderer.text_to_pixels (txt, pixels, bbox,
3232  halign, valign, rotation, "none");
3233 #endif
3234 }
3235 
3236 Matrix
3237 opengl_renderer::render_text (const std::string& txt,
3238  double x, double y, double z,
3239  int halign, int valign, double rotation)
3240 {
3241 #if HAVE_FREETYPE
3242  if (txt.empty ())
3243  return Matrix (1, 4, 0.0);
3244 
3245  uint8NDArray pixels;
3246  Matrix bbox;
3247  text_to_pixels (txt, pixels, bbox, halign, valign, rotation);
3248 
3249  bool blend = glIsEnabled (GL_BLEND);
3250 
3251  glEnable (GL_BLEND);
3252  glEnable (GL_ALPHA_TEST);
3253  glRasterPos3d (x, y, z);
3254  glBitmap(0, 0, 0, 0, bbox(0), bbox(1), 0);
3255  glDrawPixels (bbox(2), bbox(3),
3256  GL_RGBA, GL_UNSIGNED_BYTE, pixels.data ());
3257  glDisable (GL_ALPHA_TEST);
3258  if (! blend)
3259  glDisable (GL_BLEND);
3260 
3261  return bbox;
3262 #else
3263  warning ("opengl_renderer: cannot render text, FreeType library not available");
3264  return Matrix (1, 4, 0.0);
3265 #endif
3266 }
3267 
3268 #endif
uint8NDArray uint8_array_value(void) const
Definition: ov.h:882
std::string get_linestyle(void) const
Definition: graphics.h:10153
std::string get_marker(void) const
Definition: graphics.h:7401
bool facealpha_is_double(void) const
Definition: graphics.h:10136
Matrix get_color_rgb(void) const
Definition: graphics.h:4163
octave_value get_xticklabel(void) const
Definition: graphics.h:5645
bool is_empty(void) const
Definition: Array.h:472
double get_zPlaneN(void) const
Definition: graphics.h:5144
Matrix get_markeredgecolor_rgb(void) const
Definition: graphics.h:7405
Matrix get_opengl_matrix_1(void) const
Definition: graphics.h:5132
octave_value get_color_data(void) const
Definition: graphics.cc:8288
Matrix get_markeredgecolor_rgb(void) const
Definition: graphics.h:9271
Matrix get_facecolor_rgb(void) const
Definition: graphics.h:10143
int get_zstate(void) const
Definition: graphics.h:5138
double get_edgealpha_double(void) const
Definition: graphics.h:9225
bool is_visible(void) const
Definition: graphics.h:2758
Matrix get_backgroundcolor_rgb(void) const
Definition: graphics.h:12199
double get_x_max(void) const
Definition: graphics.h:5152
Matrix get_data_position(void) const
Definition: graphics.cc:8098
void resize(octave_idx_type nr, octave_idx_type nc, double rfv=0)
Definition: dMatrix.h:130
bool xisnan(double x)
Definition: lo-mappers.cc:144
bool edgealpha_is(const std::string &v) const
Definition: graphics.h:9224
graphics_handle get_xlabel(void) const
Definition: graphics.h:5627
bool isa(const std::string &go_name) const
Definition: graphics.h:3375
bool is_uint16_type(void) const
Definition: ov.h:634
graphics_handle get_zlabel(void) const
Definition: graphics.h:5704
bool linestyle_is(const std::string &v) const
Definition: graphics.h:7395
octave_idx_type numel(void) const
Number of elements in the array.
Definition: Array.h:275
bool get_nearhoriz(void) const
Definition: graphics.h:5173
static octave_idx_type nn
Definition: DASPK.cc:71
Matrix get_color_rgb(void) const
Definition: graphics.h:5535
octave_value get_zdata(void) const
Definition: graphics.h:7423
std::string get_minorgridlinestyle(void) const
Definition: graphics.h:5577
double get_z_max(void) const
Definition: graphics.h:5156
octave_value get_faces(void) const
Definition: graphics.h:9252
double get_fy(void) const
Definition: graphics.h:5158
Complex xmax(const Complex &x, const Complex &y)
Definition: lo-mappers.cc:269
bool markerfacecolor_is(const std::string &v) const
Definition: graphics.h:9275
virtual std::string graphics_object_name(void) const
Definition: graphics.h:2485
bool edgelighting_is(const std::string &v) const
Definition: graphics.h:10130
void error(const char *fmt,...)
Definition: error.cc:476
std::string get_gridlinestyle(void) const
Definition: graphics.h:5564
bool xisinf(double x)
Definition: lo-mappers.cc:160
double get_linewidth(void) const
Definition: graphics.h:5574
double get_diffusestrength(void) const
Definition: graphics.h:10116
double get_ambientstrength(void) const
Definition: graphics.h:9209
Complex xmin(const Complex &x, const Complex &y)
Definition: lo-mappers.cc:263
octave_value get_xdata(void) const
Definition: graphics.h:8618
octave_value get_ymtick(void) const
Definition: graphics.h:5750
bool has_property(const caseless_str &pname) const
double get_markersize(void) const
Definition: graphics.h:9279
bool facecolor_is(const std::string &v) const
Definition: graphics.h:10142
bool markeredgecolor_is(const std::string &v) const
Definition: graphics.h:10161
octave_value get_ytick(void) const
Definition: graphics.h:5683
std::string get_marker(void) const
Definition: graphics.h:9267
bool edgecolor_is(const std::string &v) const
Definition: graphics.h:10126
octave_value get_xmtick(void) const
Definition: graphics.h:5748
double get_xticklen(void) const
Definition: graphics.h:5160
double get_facealpha_double(void) const
Definition: graphics.h:10138
bool is_zminortick(void) const
Definition: graphics.h:5714
Matrix get_edgecolor_rgb(void) const
Definition: graphics.h:10127
bool markerfacecolor_is(const std::string &v) const
Definition: graphics.h:10166
Matrix get_markerfacecolor_rgb(void) const
Definition: graphics.h:9276
octave_idx_type rows(void) const
Definition: Array.h:313
octave_value get(bool all=false) const
Definition: graphics.h:3300
F77_RET_T const double const double double * d
double get_xpTickN(void) const
Definition: graphics.h:5146
string_vector all_strings(bool pad=false) const
Definition: ov.h:894
graphics_xform get_transform(void) const
Definition: graphics.h:5127
octave_value get_xdata(void) const
Definition: graphics.h:10186
octave_value get_ydata(void) const
Definition: graphics.h:8620
double get_edgealpha_double(void) const
Definition: graphics.h:10122
double get_specularexponent(void) const
Definition: graphics.h:9286
double get_diffusestrength(void) const
Definition: graphics.h:9219
bool marker_is(const std::string &v) const
Definition: graphics.h:9266
bool edgealpha_is_double(void) const
Definition: graphics.h:9223
bool edgecolor_is(const std::string &v) const
Definition: graphics.h:9229
const dim_vector & dims(void) const
Return a const-reference so that dims ()(i) works efficiently.
Definition: Array.h:337
double signum(double x)
Definition: lo-mappers.cc:80
double get_zpTickN(void) const
Definition: graphics.h:5150
bool get_xyzSym(void) const
Definition: graphics.h:5171
FloatNDArray float_array_value(bool frc_str_conv=false) const
Definition: ov.h:782
bool is___enhanced__(void) const
Definition: graphics.h:4299
F77_RET_T const double const double * f
double get_specularstrength(void) const
Definition: graphics.h:10182
Matrix get_markerfacecolor_rgb(void) const
Definition: graphics.h:7410
Matrix get_children(void) const
Definition: graphics.h:2571
Matrix get_ycolor_rgb(void) const
Definition: graphics.h:5658
octave_value get_zticklabel(void) const
Definition: graphics.h:5722
std::string string_value(bool force=false) const
Definition: ov.h:897
#define loc(X, Y)
Definition: Screen.cpp:56
double get_markersize(void) const
Definition: graphics.h:7413
int get_ystate(void) const
Definition: graphics.h:5137
std::complex< double > w(std::complex< double > z, double relerr=0)
double get_fx(void) const
Definition: graphics.h:5157
Matrix get_extent_matrix(void) const
Definition: graphics.cc:8109
Matrix get_zcolor_rgb(void) const
Definition: graphics.h:5695
double get_yPlane(void) const
Definition: graphics.h:5141
octave_value get_zmtick(void) const
Definition: graphics.h:5752
octave_value get_ydata(void) const
Definition: graphics.h:7419
double get_ypTickN(void) const
Definition: graphics.h:5148
bool facealpha_is(const std::string &v) const
Definition: graphics.h:9240
bool facealpha_is(const std::string &v) const
Definition: graphics.h:10137
bool is_double_type(void) const
Definition: ov.h:608
octave_value get_vertexnormals(void) const
Definition: graphics.h:9290
const T * data(void) const
Definition: Array.h:479
bool get_y2Dright(void) const
Definition: graphics.h:5167
Matrix get_edgecolor_rgb(void) const
Definition: graphics.h:9230
bool edgecolor_is_rgb(void) const
Definition: graphics.h:10125
double get_specularstrength(void) const
Definition: graphics.h:9288
bool markeredgecolor_is(const std::string &v) const
Definition: graphics.h:9270
std::string get_linestyle(void) const
Definition: graphics.h:9262
double get_y_max(void) const
Definition: graphics.h:5154
base_properties & get_properties(void)
Definition: graphics.h:3377
double get_ytickoffset(void) const
Definition: graphics.h:5164
Matrix get_color_rgb(void) const
Definition: graphics.h:7384
double get_xPlaneN(void) const
Definition: graphics.h:5140
std::string get_marker(void) const
Definition: graphics.h:10158
Definition: dMatrix.h:35
bool get_layer2Dtop(void) const
Definition: graphics.h:5168
size_t size(T const (&)[z])
Definition: help.cc:103
bool marker_is(const std::string &v) const
Definition: graphics.h:7400
graphics_object get_ancestor(const std::string &type) const
Definition: graphics.cc:3394
dim_vector dims(void) const
Definition: ov.h:470
Matrix matrix_value(bool frc_str_conv=false) const
Definition: ov.h:773
double get_linewidth(void) const
Definition: graphics.h:10155
Matrix get_xcolor_rgb(void) const
Definition: graphics.h:5618
octave_value get_vertices(void) const
Definition: graphics.h:9292
bool is_clipping(void) const
Definition: graphics.h:2724
static void end_contour(void)
Definition: __contourc__.cc:71
double get_xPlane(void) const
Definition: graphics.h:5139
bool get_zSign(void) const
Definition: graphics.h:5172
octave_value get_string(void) const
Definition: graphics.h:7956
bool edgealpha_is(const std::string &v) const
Definition: graphics.h:10121
double get_yPlaneN(void) const
Definition: graphics.h:5142
bool is_zminorgrid(void) const
Definition: graphics.h:5711
bool edgealpha_is_double(void) const
Definition: graphics.h:10120
static bool is_nan_or_inf(const octave_value &val)
Definition: oct-stream.cc:2424
double get_ypTick(void) const
Definition: graphics.h:5147
void warning(const char *fmt,...)
Definition: error.cc:681
bool get_xySym(void) const
Definition: graphics.h:5170
bool valid_object(void) const
Definition: graphics.h:3395
Handles the reference counting for all the derived classes.
Definition: Array.h:45
bool facecolor_is_rgb(void) const
Definition: graphics.h:9244
charNDArray max(char d, const charNDArray &m)
Definition: chNDArray.cc:233
octave_idx_type length(void) const
Number of elements in the array.
Definition: Array.h:267
octave_value get_ydata(void) const
Definition: graphics.h:10190
bool is_empty(void) const
Definition: ov.h:526
double get_facealpha_double(void) const
Definition: graphics.h:9241
Matrix get_opengl_matrix_2(void) const
Definition: graphics.h:5133
NDArray array_value(bool frc_str_conv=false) const
Definition: ov.h:779
virtual octave_value get(const caseless_str &pname) const
bool xfinite(double x)
Definition: lo-mappers.cc:152
bool edgelighting_is(const std::string &v) const
Definition: graphics.h:9233
double get_xtickoffset(void) const
Definition: graphics.h:5163
double get_fz(void) const
Definition: graphics.h:5159
bool is_ygrid(void) const
Definition: graphics.h:5664
bool is_box(void) const
Definition: graphics.h:5505
double get_yticklen(void) const
Definition: graphics.h:5161
double get_markersize(void) const
Definition: graphics.h:10170
bool is_uint8_type(void) const
Definition: ov.h:631
virtual graphics_toolkit get_toolkit(void) const
Definition: graphics.cc:3123
int get_xstate(void) const
Definition: graphics.h:5136
double get_z_min(void) const
Definition: graphics.h:5155
bool is_yminorgrid(void) const
Definition: graphics.h:5674
Matrix get_all_children(void) const
Definition: graphics.h:2576
double get_specularexponent(void) const
Definition: graphics.h:10180
bool is_xminortick(void) const
Definition: graphics.h:5637
double get_x_min(void) const
Definition: graphics.h:5151
double get_y_min(void) const
Definition: graphics.h:5153
double get_xpTick(void) const
Definition: graphics.h:5145
bool facealpha_is_double(void) const
Definition: graphics.h:9239
#define OCTAVE_LOCAL_BUFFER(T, buf, size)
Definition: oct-locbuf.h:197
static graphics_object get_object(double val)
Definition: graphics.h:13212
bool is_xminorgrid(void) const
Definition: graphics.h:5634
bool get_is2D(void) const
Definition: graphics.h:5169
double get_zpTick(void) const
Definition: graphics.h:5149
double get_linewidth(void) const
Definition: graphics.h:7398
double get_ambientstrength(void) const
Definition: graphics.h:10104
Matrix get_markeredgecolor_rgb(void) const
Definition: graphics.h:10162
octave_value get_ztick(void) const
Definition: graphics.h:5720
octave_value get_color_data(void) const
Definition: graphics.cc:8297
double get_zticklen(void) const
Definition: graphics.h:5162
octave_value get_vertexnormals(void) const
Definition: graphics.h:10184
bool facecolor_is(const std::string &v) const
Definition: graphics.h:9245
octave_value get_color_data(void) const
Definition: graphics.cc:8500
octave_value get_xdata(void) const
Definition: graphics.h:7415
bool is_single_type(void) const
Definition: ov.h:611
bool marker_is(const std::string &v) const
Definition: graphics.h:10157
Matrix get_markerfacecolor_rgb(void) const
Definition: graphics.h:10167
double double_value(bool frc_str_conv=false) const
Definition: ov.h:759
bool edgecolor_is_rgb(void) const
Definition: graphics.h:9228
bool markerfacecolor_is(const std::string &v) const
Definition: graphics.h:7409
double get_linewidth(void) const
Definition: graphics.h:9264
bool facelighting_is(const std::string &v) const
Definition: graphics.h:10146
Matrix get_transform_zlim(void) const
Definition: graphics.h:5134
bool is_yminortick(void) const
Definition: graphics.h:5677
bool markeredgecolor_is(const std::string &v) const
Definition: graphics.h:7404
bool meshstyle_is(const std::string &v) const
Definition: graphics.h:10172
const uint8NDArray & get_pixels(void) const
Definition: graphics.h:8393
uint16NDArray uint16_array_value(void) const
Definition: ov.h:885
bool is_zgrid(void) const
Definition: graphics.h:5701
octave_idx_type columns(void) const
Definition: Array.h:322
double get_ztickoffset(void) const
Definition: graphics.h:5165
octave_value get_zdata(void) const
Definition: graphics.h:10194
bool has_bad_data(std::string &msg) const
Definition: graphics.h:9046
void xform(ColumnVector &v, const Matrix &m)
Definition: graphics.cc:5293
bool facecolor_is_rgb(void) const
Definition: graphics.h:10141
double get_zPlane(void) const
Definition: graphics.h:5143
bool facelighting_is(const std::string &v) const
Definition: graphics.h:9249
std::string get_linestyle(void) const
Definition: graphics.h:7396
graphics_handle get_ylabel(void) const
Definition: graphics.h:5667
F77_RET_T const double * x
charNDArray min(char d, const charNDArray &m)
Definition: chNDArray.cc:210
bool get_x2Dtop(void) const
Definition: graphics.h:5166
Matrix get_facecolor_rgb(void) const
Definition: graphics.h:9246
octave_value get_yticklabel(void) const
Definition: graphics.h:5685
octave_value get_xtick(void) const
Definition: graphics.h:5643
bool is_xgrid(void) const
Definition: graphics.h:5624