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