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