GNU Octave  4.4.1
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
__osmesa_print__.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 2016-2018 Andreas Weber <andy.weber.aw@gmail.com>
4 
5 This file is part of Octave.
6 
7 Octave is free software: you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11 
12 Octave is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with Octave; see the file COPYING. If not, see
19 <https://www.gnu.org/licenses/>.
20 
21 This code is based on Brian Pauls' src/osdemos/osdemo.c
22 from git://anongit.freedesktop.org/mesa/demos
23 
24 */
25 
26 #if defined (HAVE_CONFIG_H)
27 # include "config.h"
28 #endif
29 
30 #if defined (HAVE_OSMESA_H)
31 # include <osmesa.h>
32 #elif defined (HAVE_GL_OSMESA_H)
33 # include <GL/osmesa.h>
34 #endif
35 
36 #include <string>
37 
38 #include "Array.h"
39 #include "dMatrix.h"
40 #include "oct-locbuf.h"
41 #include "uint8NDArray.h"
42 #include "unwind-prot.h"
43 
44 #include "defun-dld.h"
45 #include "error.h"
46 #include "errwarn.h"
47 #include "gl-render.h"
48 #include "gl2ps-print.h"
49 #include "graphics.h"
50 #include "oct-opengl.h"
51 #include "ov.h"
52 #include "ovl.h"
53 
54 #if defined (HAVE_OSMESA)
55 
56 static void
57 reset_visibility (figure::properties *fp)
58 {
59  fp->set_visible ("on");
60 }
61 
62 #endif
63 
64 DEFUN_DLD(__osmesa_print__, args, ,
65  doc: /* -*- texinfo -*-
66 @deftypefn {} {} __osmesa_print__ (@var{h}, @var{file}, @var{term})
67 @deftypefnx {} {@var{img} =} __osmesa_print__ (@var{h})
68 Print figure @var{h} using OSMesa and gl2ps for vector formats.
69 
70 This is a private internal function.
71 
72 The first method calls gl2ps with the appropriate @var{term} and writes
73 the output of gl2ps to @var{file}. If the first character of @var{file}
74 is @code{|}, then a process is started and the output of gl2ps is piped
75 to it.
76 
77 Valid options for @var{term}, which can be concatenated in one string, are:
78 
79 @table @asis
80 @item @qcode{eps}, @qcode{pdf}, @qcode{ps}, @qcode{svg}, @qcode{pgf}, @qcode{tex}
81 Select output format.
82 
83 @item @code{is2D}
84 Use GL2PS_SIMPLE_SORT instead of GL2PS_BSP_SORT as Z-depth sorting
85 algorithm.
86 
87 @item @code{notext}
88 Don't render text.
89 @end table
90 
91 The second method doesn't use gl2ps and returns a RGB image in @var{img}
92 instead.
93 
94 @end deftypefn */)
95 {
96 #if defined (HAVE_OSMESA)
97 
98  int nargin = args.length ();
99 
100  if (nargin != 1 && nargin != 3)
101  print_usage ();
102 
103  if (nargin == 3)
104  {
105  if (! (args(1).is_string () && args(2).is_string ()))
106  error ("__osmesa_print__: FILE and TERM must be strings");
107  }
108 
110 
111  int h = args(0).double_value ();
113  if (! (fobj && fobj.isa ("figure")))
114  error ("__osmesa_print__: H must be a valid figure handle");
115 
116  figure::properties& fp =
117  dynamic_cast<figure::properties&> (fobj.get_properties ());
118 
119  bool internal = true;
120  Matrix bb = fp.get_boundingbox (internal);
121 
122  GLsizei Width = static_cast<GLsizei> (bb(2));
123  GLsizei Height = static_cast<GLsizei> (bb(3));
124 
125  // Create an RGBA-mode context, specify Z=16, stencil=0, accum=0 sizes
126  OSMesaContext ctx = OSMesaCreateContextExt (OSMESA_RGBA, 16, 0, 0, nullptr);
127  if (! ctx)
128  error ("__osmesa_print__: OSMesaCreateContext failed!\n");
129 
130  // Allocate the image buffer
131  OCTAVE_LOCAL_BUFFER (GLubyte, buffer, 4 * Width * Height);
132 
133  // Bind the buffer to the context and make it current
134  if (! OSMesaMakeCurrent (ctx, buffer, GL_UNSIGNED_BYTE, Width, Height))
135  error ("__osmesa_print__: OSMesaMakeCurrent failed!\n");
136 
137  // Test for a bug in OSMesa with version < 9.0
138  //
139  // Unfortunately the macros OSMESA_MAJOR_VERSION and OSMESA_MINOR_VERSION
140  // weren't updated between many releases and can't be used for detection.
141  // (Version 8.0 until 9.1.4 all return MAJOR 6, MINOR 5)
142  GLint z, s;
143  glGetIntegerv (GL_DEPTH_BITS, &z);
144  glGetIntegerv (GL_STENCIL_BITS, &s);
145  if (z != 16 || s != 0)
146  error ("__osmesa_print__: Depth and stencil doesn't match,"
147  " are you sure you are using OSMesa >= 9.0?");
148 
149  octave::unwind_protect outer_frame;
150 
151  bool v = fp.is_visible ();
152 
153  if (v)
154  {
155  outer_frame.add_fcn (reset_visibility, &fp);
156 
157  fp.set_visible ("off");
158  }
159 
160  if (nargin == 3)
161  {
162  std::string file = args(1).string_value ();
163  std::string term = args(2).string_value ();
164 
165  octave::gl2ps_print (fobj, file, term);
166  }
167  else
168  {
169  // return RGB image
171 
172  // Draw and finish () or there may primitives missing in the
173  // output.
174  rend.draw (fobj);
175  rend.finish ();
176 
177  dim_vector dv (4, Width, Height);
178 
179  // FIXME: We expect that GLubyte is 1 Byte long.
180  // Adapt code if this isn't always true
181  assert (sizeof (GLubyte) == 1);
182  uint8NDArray img (dv);
183  unsigned char *p = reinterpret_cast<unsigned char *>(img.fortran_vec ());
184  memcpy (p, buffer, (4 * Width * Height));
185 
186  Array<octave_idx_type> perm (dim_vector (3, 1));
187  perm(0) = 2;
188  perm(1) = 1;
189  perm(2) = 0;
190 
191  Array<idx_vector> idx (dim_vector (3, 1));
192 
193  // Flip Y
194  idx(0) = idx_vector::make_range (Height - 1, -1, Height);
195  idx(1) = idx_vector::colon;
196 
197  // Remove alpha channel
198  idx(2) = idx_vector (0, 3);
199  retval(0) = octave_value (img.permute (perm).index(idx));
200  }
201 
202  OSMesaDestroyContext (ctx);
203 
204  return retval;
205 
206 #else
207 
208  octave_unused_parameter (args);
209 
210  err_disabled_feature ("__osmesa_print__", "offscreen rendering with OSMesa");
211 
212 #endif
213 }
214 
215 /*
216 ## FIXME: osmesa does not work correctly on Windows platforms.
217 ## This is not critical, since this facility will mostly be used in
218 ## the future for generating the images in Octave's own documentation.
219 ## For the moment, disable these tests on PC's and Macs.
220 %!testif HAVE_OPENGL, HAVE_OSMESA, HAVE_GL2PS_H
221 %! if (isunix ())
222 %! hf = figure ("visible", "off");
223 %! fn = tempname ();
224 %! unwind_protect
225 %! sombrero ();
226 %! __osmesa_print__ (hf, fn, "svg");
227 %! assert (stat (fn).size > 2e6);
228 %! img = __osmesa_print__ (hf);
229 %! assert (size (img), [get(hf, "position")([4, 3]), 3]);
230 %! ## Use pixel sum per RGB channel as fingerprint
231 %! img_fp = squeeze (sum (sum (img), 2));
232 %! assert (img_fp, [52942515; 54167797; 56158178], -0.05);
233 %! unwind_protect_cleanup
234 %! close (hf);
235 %! unlink (fn);
236 %! end_unwind_protect
237 %! endif
238 
239 %!testif HAVE_OPENGL, HAVE_OSMESA, HAVE_GL2PS_H
240 %! if (isunix ())
241 %! hf = figure ("visible", "off");
242 %! fn = tempname ();
243 %! unwind_protect
244 %! plot (sin (0:0.1:2*pi));
245 %! __osmesa_print__ (hf, fn, "svgis2d");
246 %! assert (stat (fn).size, 9022, -0.20);
247 %! img = __osmesa_print__ (hf);
248 %! assert (size (img), [get(hf, "position")([4, 3]), 3]);
249 %! ## Use pixel sum per RGB channel as fingerprint
250 %! img_fp = squeeze (sum (sum (img), 2));
251 %! assert (img_fp, [59281711; 59281711; 59482179], -0.05);
252 %! unwind_protect_cleanup
253 %! close (hf);
254 %! unlink (fn);
255 %! end_unwind_protect
256 %! endif
257 */
void set_visible(const octave_value &val)
Definition: graphics.cc:3926
For example cd octave end example noindent changes the current working directory to file
Definition: dirfns.cc:124
static const idx_vector colon
Definition: idx-vector.h:498
OCTINTERP_API void print_usage(void)
Definition: defun.cc:54
virtual void draw(const graphics_object &go, bool toplevel=true)
Definition: gl-render.cc:620
const T * fortran_vec(void) const
Definition: Array.h:584
Matrix get_boundingbox(bool internal=false, const Matrix &parent_pix_size=Matrix()) const
Definition: graphics.cc:3937
void add_fcn(void(*fcn)(void))
void error(const char *fmt,...)
Definition: error.cc:578
s
Definition: file-io.cc:2729
bool isa(const std::string &go_name) const
Definition: graphics.in.h:2786
MArray< T > permute(const Array< octave_idx_type > &vec, bool inv=false) const
Definition: MArray.h:94
double h
Definition: graphics.cc:11808
void gl2ps_print(const graphics_object &fig, const std::string &stream, const std::string &term)
octave_value retval
Definition: data.cc:6246
base_properties & get_properties(void)
Definition: graphics.in.h:2788
Definition: dMatrix.h:36
return octave_value(v1.char_array_value() . concat(v2.char_array_value(), ra_idx),((a1.is_sq_string()||a2.is_sq_string()) ? '\'' :'"'))
p
Definition: lu.cc:138
#define OCTAVE_LOCAL_BUFFER(T, buf, size)
Definition: oct-locbuf.h:41
static graphics_object get_object(double val)
Definition: graphics.in.h:6098
args.length() nargin
Definition: file-io.cc:589
#define DEFUN_DLD(name, args_name, nargout_name, doc)
Macro to define an at run time dynamically loadable builtin function.
Definition: defun-dld.h:58
virtual void finish(void)
Definition: gl-render.cc:1081
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:87
void err_disabled_feature(const std::string &fcn, const std::string &feature, const std::string &pkg)
Definition: errwarn.cc:50
If this string is the system will ring the terminal sometimes it is useful to be able to print the original representation of the string
Definition: utils.cc:888
static idx_vector make_range(octave_idx_type start, octave_idx_type step, octave_idx_type len)
Definition: idx-vector.h:482
dim_vector dv
Definition: sub2ind.cc:263