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