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