Mercurial > octave
comparison libinterp/corefcn/gl2ps-print.cc @ 21199:dd6605e1eaea
make gl2ps_renderer implementation private
* gl2ps-print.h: Rename from gl2ps-renderer.h.
* gl2ps-print.cc: Rename from gl2ps-renderer.cc.
* libinterp/corefcn/module.mk: Update.
* Canvas.cc, __init_fltk__.cc, __osmesa_print__.cc: Update.
author | John W. Eaton <jwe@octave.org> |
---|---|
date | Thu, 04 Feb 2016 18:07:46 -0500 |
parents | libinterp/corefcn/gl2ps-renderer.cc@1adcdc518d9e |
children | fcac5dbbf9ed |
comparison
equal
deleted
inserted
replaced
21198:1adcdc518d9e | 21199:dd6605e1eaea |
---|---|
1 /* | |
2 | |
3 Copyright (C) 2009-2015 Shai Ayal | |
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 */ | |
22 | |
23 #ifdef HAVE_CONFIG_H | |
24 #include <config.h> | |
25 #endif | |
26 | |
27 #include "errwarn.h" | |
28 #include "gl2ps-print.h" | |
29 | |
30 #ifdef HAVE_GL2PS_H | |
31 | |
32 #include <cstdio> | |
33 #include <unistd.h> | |
34 | |
35 #include <gl2ps.h> | |
36 | |
37 #include "lo-mappers.h" | |
38 #include "oct-locbuf.h" | |
39 #include "unwind-prot.h" | |
40 | |
41 #include "gl-render.h" | |
42 #include "oct-opengl.h" | |
43 #include "sysdep.h" | |
44 #include "txt-eng-ft.h" | |
45 | |
46 class | |
47 OCTINTERP_API | |
48 gl2ps_renderer : public opengl_renderer | |
49 { | |
50 public: | |
51 | |
52 gl2ps_renderer (FILE *_fp, const std::string& _term) | |
53 : opengl_renderer () , fp (_fp), term (_term), fontsize (), | |
54 fontname (), buffer_overflow (false) | |
55 { } | |
56 | |
57 ~gl2ps_renderer (void) { } | |
58 | |
59 void draw (const graphics_object& go, const std::string& print_cmd); | |
60 | |
61 protected: | |
62 | |
63 Matrix render_text (const std::string& txt, | |
64 double x, double y, double z, | |
65 int halign, int valign, double rotation = 0.0); | |
66 | |
67 void set_font (const base_properties& props); | |
68 | |
69 void draw_axes (const axes::properties& props) | |
70 { | |
71 // Initialize a sorting tree (viewport) in gl2ps for each axes | |
72 GLint vp[4]; | |
73 glGetIntegerv (GL_VIEWPORT, vp); | |
74 gl2psBeginViewport (vp); | |
75 | |
76 // Draw and finish () or there may primitives missing in the | |
77 // gl2ps output. | |
78 opengl_renderer::draw_axes (props); | |
79 finish (); | |
80 | |
81 // Finalize viewport | |
82 GLint state = gl2psEndViewport (); | |
83 if (state == GL2PS_NO_FEEDBACK) | |
84 warning ("gl2ps_renderer::draw_axes: empty feedback buffer and/or nothing else to print"); | |
85 else if (state == GL2PS_ERROR) | |
86 error ("gl2ps_renderer::draw_axes: gl2psEndPage returned GL2PS_ERROR"); | |
87 | |
88 buffer_overflow |= (state == GL2PS_OVERFLOW); | |
89 } | |
90 | |
91 void draw_text (const text::properties& props); | |
92 void draw_pixels (GLsizei w, GLsizei h, GLenum format, | |
93 GLenum type, const GLvoid *data); | |
94 | |
95 void set_linestyle (const std::string& s, bool use_stipple = false) | |
96 { | |
97 opengl_renderer::set_linestyle (s, use_stipple); | |
98 | |
99 if (s == "-" && ! use_stipple) | |
100 gl2psDisable (GL2PS_LINE_STIPPLE); | |
101 else | |
102 gl2psEnable (GL2PS_LINE_STIPPLE); | |
103 } | |
104 | |
105 void set_polygon_offset (bool on, float offset = 0.0f) | |
106 { | |
107 if (on) | |
108 { | |
109 opengl_renderer::set_polygon_offset (on, offset); | |
110 gl2psEnable (GL2PS_POLYGON_OFFSET_FILL); | |
111 } | |
112 else | |
113 { | |
114 gl2psDisable (GL2PS_POLYGON_OFFSET_FILL); | |
115 opengl_renderer::set_polygon_offset (on, offset); | |
116 } | |
117 } | |
118 | |
119 void set_linewidth (float w) | |
120 { | |
121 gl2psLineWidth (w); | |
122 } | |
123 | |
124 private: | |
125 | |
126 // Use xform to compute the coordinates of the ft_string list | |
127 // that have been parsed by freetype | |
128 void fix_strlist_position (double x, double y, double z, | |
129 Matrix box, double rotation, | |
130 std::list<ft_render::ft_string>& lst); | |
131 | |
132 int alignment_to_mode (int ha, int va) const; | |
133 FILE *fp; | |
134 caseless_str term; | |
135 double fontsize; | |
136 std::string fontname; | |
137 bool buffer_overflow; | |
138 }; | |
139 | |
140 void | |
141 gl2ps_renderer::draw (const graphics_object& go, const std::string& print_cmd) | |
142 { | |
143 static bool in_draw = false; | |
144 static std::string old_print_cmd; | |
145 | |
146 if (! in_draw) | |
147 { | |
148 unwind_protect frame; | |
149 | |
150 frame.protect_var (in_draw); | |
151 | |
152 in_draw = true; | |
153 | |
154 GLint gl2ps_term; | |
155 if (term.find ("eps") != std::string::npos) | |
156 gl2ps_term = GL2PS_EPS; | |
157 else if (term.find ("pdf") != std::string::npos) | |
158 gl2ps_term = GL2PS_PDF; | |
159 else if (term.find ("ps") != std::string::npos) | |
160 gl2ps_term = GL2PS_PS; | |
161 else if (term.find ("svg") != std::string::npos) | |
162 gl2ps_term = GL2PS_SVG; | |
163 else if (term.find ("pgf") != std::string::npos) | |
164 gl2ps_term = GL2PS_PGF; | |
165 else if (term.find ("tex") != std::string::npos) | |
166 gl2ps_term = GL2PS_TEX; | |
167 else | |
168 error ("gl2ps_renderer::draw: Unknown terminal %s", term.c_str ()); | |
169 | |
170 GLint gl2ps_text = 0; | |
171 if (term.find ("notxt") != std::string::npos) | |
172 gl2ps_text = GL2PS_NO_TEXT; | |
173 | |
174 // Default sort order optimizes for 3D plots | |
175 GLint gl2ps_sort = GL2PS_BSP_SORT; | |
176 | |
177 // For 2D plots we can use a simpler Z-depth sorting algorithm | |
178 if (term.find ("is2D") != std::string::npos) | |
179 gl2ps_sort = GL2PS_SIMPLE_SORT; | |
180 | |
181 // Use a temporary file in case an overflow happens | |
182 FILE* tmpf = gnulib::tmpfile (); | |
183 | |
184 if (! tmpf) | |
185 error ("gl2ps_renderer::draw: couldn't open temporary file for printing"); | |
186 | |
187 GLint buffsize = 2*1024*1024; | |
188 buffer_overflow = true; | |
189 | |
190 while (buffer_overflow) | |
191 { | |
192 buffer_overflow = false; | |
193 buffsize *= 2; | |
194 gnulib::fseek (tmpf, 0, SEEK_SET); | |
195 gnulib::ftruncate (fileno (tmpf), 0); | |
196 | |
197 // For LaTeX output the fltk print process uses 2 drawnow() commands. | |
198 // The first one is for the pdf/ps/eps graph to be included. The | |
199 // print_cmd is saved as old_print_cmd. Then the second drawnow() | |
200 // outputs the tex-file and the graphic filename to be included is | |
201 // extracted from old_print_cmd. | |
202 | |
203 std::string include_graph; | |
204 | |
205 size_t found_redirect = old_print_cmd.find (">"); | |
206 | |
207 if (found_redirect != std::string::npos) | |
208 include_graph = old_print_cmd.substr (found_redirect + 1); | |
209 else | |
210 include_graph = old_print_cmd; | |
211 | |
212 size_t n_begin = include_graph.find_first_not_of (" "); | |
213 | |
214 if (n_begin != std::string::npos) | |
215 { | |
216 size_t n_end = include_graph.find_last_not_of (" "); | |
217 include_graph = include_graph.substr (n_begin, | |
218 n_end - n_begin + 1); | |
219 } | |
220 else | |
221 include_graph = "foobar-inc"; | |
222 | |
223 // GL2PS_SILENT was removed to allow gl2ps printing errors on stderr | |
224 GLint ret = gl2psBeginPage ("gl2ps_renderer figure", "Octave", 0, | |
225 gl2ps_term, gl2ps_sort, | |
226 (GL2PS_NO_BLENDING | |
227 | GL2PS_OCCLUSION_CULL | |
228 | GL2PS_BEST_ROOT | |
229 | gl2ps_text | |
230 | GL2PS_NO_PS3_SHADING | |
231 | GL2PS_USE_CURRENT_VIEWPORT), | |
232 GL_RGBA, 0, 0, 0, 0, 0, | |
233 buffsize, tmpf, include_graph.c_str ()); | |
234 if (ret == GL2PS_ERROR) | |
235 { | |
236 old_print_cmd.clear (); | |
237 error ("gl2ps_renderer::draw: gl2psBeginPage returned GL2PS_ERROR"); | |
238 } | |
239 | |
240 opengl_renderer::draw (go); | |
241 | |
242 if (! buffer_overflow) | |
243 old_print_cmd = print_cmd; | |
244 | |
245 // Don't check return value of gl2psEndPage, it is not meaningful. | |
246 // Errors and warnings are checked after gl2psEndViewport in | |
247 // gl2ps_renderer::draw_axes instead. | |
248 gl2psEndPage (); | |
249 } | |
250 | |
251 // Copy temporary file to pipe | |
252 gnulib::fseek (tmpf, 0, SEEK_SET); | |
253 char str[256]; | |
254 int nread = 1; | |
255 while (! feof (tmpf) && nread) | |
256 { | |
257 nread = gnulib::fread (str, 1, 256, tmpf); | |
258 if (nread) | |
259 gnulib::fwrite (str, 1, nread, fp); | |
260 } | |
261 } | |
262 else | |
263 opengl_renderer::draw (go); | |
264 } | |
265 | |
266 int | |
267 gl2ps_renderer::alignment_to_mode (int ha, int va) const | |
268 { | |
269 int gl2psa = GL2PS_TEXT_BL; | |
270 | |
271 if (ha == 0) | |
272 { | |
273 if (va == 0 || va == 3) | |
274 gl2psa=GL2PS_TEXT_BL; | |
275 else if (va == 2) | |
276 gl2psa=GL2PS_TEXT_TL; | |
277 else if (va == 1) | |
278 gl2psa=GL2PS_TEXT_CL; | |
279 } | |
280 else if (ha == 2) | |
281 { | |
282 if (va == 0 || va == 3) | |
283 gl2psa=GL2PS_TEXT_BR; | |
284 else if (va == 2) | |
285 gl2psa=GL2PS_TEXT_TR; | |
286 else if (va == 1) | |
287 gl2psa=GL2PS_TEXT_CR; | |
288 } | |
289 else if (ha == 1) | |
290 { | |
291 if (va == 0 || va == 3) | |
292 gl2psa=GL2PS_TEXT_B; | |
293 else if (va == 2) | |
294 gl2psa=GL2PS_TEXT_T; | |
295 else if (va == 1) | |
296 gl2psa=GL2PS_TEXT_C; | |
297 } | |
298 | |
299 return gl2psa; | |
300 } | |
301 | |
302 void | |
303 gl2ps_renderer::fix_strlist_position (double x, double y, double z, | |
304 Matrix box, double rotation, | |
305 std::list<ft_render::ft_string>& lst) | |
306 { | |
307 for (std::list<ft_render::ft_string>::iterator p = lst.begin (); | |
308 p != lst.end (); p++) | |
309 { | |
310 // Get pixel coordinates | |
311 ColumnVector coord_pix = get_transform ().transform (x, y, z, false); | |
312 | |
313 // Translate and rotate | |
314 double rot = rotation * 4.0 * atan (1.0) / 180; | |
315 coord_pix(0) += ((*p).get_x () + box(0))*cos (rot) | |
316 - ((*p).get_y () + box(1))*sin (rot); | |
317 coord_pix(1) -= ((*p).get_y () + box(1))*cos (rot) | |
318 + ((*p).get_x () + box(0))*sin (rot);; | |
319 | |
320 // Turn coordinates back into current gl coordinates | |
321 ColumnVector coord = | |
322 get_transform ().untransform (coord_pix(0), coord_pix(1), | |
323 coord_pix(2), false); | |
324 (*p).set_x (coord(0)); | |
325 (*p).set_y (coord(1)); | |
326 (*p).set_z (coord(2)); | |
327 } | |
328 } | |
329 | |
330 static std::string | |
331 code_to_symbol (uint32_t code) | |
332 { | |
333 std::string retval; | |
334 | |
335 uint32_t idx = code - 945; | |
336 if (idx < 25) | |
337 { | |
338 std::string characters("abgdezhqiklmnxoprVstufcyw"); | |
339 retval = characters[idx]; | |
340 return retval; | |
341 } | |
342 | |
343 idx = code - 913; | |
344 if (idx < 25) | |
345 { | |
346 std::string characters("ABGDEZHQIKLMNXOPRVSTUFCYW"); | |
347 retval = characters[idx]; | |
348 } | |
349 else if (code == 978) | |
350 retval = std::string ("U"); | |
351 else if (code == 215) | |
352 retval = std::string ("\xb4"); | |
353 else if (code == 177) | |
354 retval = std::string ("\xb1"); | |
355 else if (code == 8501) | |
356 retval = std::string ("\xc0"); | |
357 else if (code == 8465) | |
358 retval = std::string ("\xc1"); | |
359 else if (code == 8242) | |
360 retval = std::string ("\xa2"); | |
361 else if (code == 8736) | |
362 retval = std::string ("\xd0"); | |
363 else if (code == 172) | |
364 retval = std::string ("\xd8"); | |
365 else if (code == 9829) | |
366 retval = std::string ("\xa9"); | |
367 else if (code == 8472) | |
368 retval = std::string ("\xc3"); | |
369 else if (code == 8706) | |
370 retval = std::string ("\xb6"); | |
371 else if (code == 8704) | |
372 retval = std::string ("\x22"); | |
373 else if (code == 9827) | |
374 retval = std::string ("\xa7"); | |
375 else if (code == 9824) | |
376 retval = std::string ("\xaa"); | |
377 else if (code == 8476) | |
378 retval = std::string ("\xc2"); | |
379 else if (code == 8734) | |
380 retval = std::string ("\xa5"); | |
381 else if (code == 8730) | |
382 retval = std::string ("\xd6"); | |
383 else if (code == 8707) | |
384 retval = std::string ("\x24"); | |
385 else if (code == 9830) | |
386 retval = std::string ("\xa8"); | |
387 else if (code == 8747) | |
388 retval = std::string ("\xf2"); | |
389 else if (code == 8727) | |
390 retval = std::string ("\x2a"); | |
391 else if (code == 8744) | |
392 retval = std::string ("\xda"); | |
393 else if (code == 8855) | |
394 retval = std::string ("\xc4"); | |
395 else if (code == 8901) | |
396 retval = std::string ("\xd7"); | |
397 else if (code == 8728) | |
398 retval = std::string ("\xb0"); | |
399 else if (code == 8745) | |
400 retval = std::string ("\xc7"); | |
401 else if (code == 8743) | |
402 retval = std::string ("\xd9"); | |
403 else if (code == 8856) | |
404 retval = std::string ("\xc6"); | |
405 else if (code == 8729) | |
406 retval = std::string ("\xb7"); | |
407 else if (code == 8746) | |
408 retval = std::string ("\xc8"); | |
409 else if (code == 8853) | |
410 retval = std::string ("\xc5"); | |
411 else if (code == 8804) | |
412 retval = std::string ("\xa3"); | |
413 else if (code == 8712) | |
414 retval = std::string ("\xce"); | |
415 else if (code == 8839) | |
416 retval = std::string ("\xca"); | |
417 else if (code == 8801) | |
418 retval = std::string ("\xba"); | |
419 else if (code == 8773) | |
420 retval = std::string ("\x40"); | |
421 else if (code == 8834) | |
422 retval = std::string ("\xcc"); | |
423 else if (code == 8805) | |
424 retval = std::string ("\xb3"); | |
425 else if (code == 8715) | |
426 retval = std::string ("\x27"); | |
427 else if (code == 8764) | |
428 retval = std::string ("\x7e"); | |
429 else if (code == 8733) | |
430 retval = std::string ("\xb5"); | |
431 else if (code == 8838) | |
432 retval = std::string ("\xcd"); | |
433 else if (code == 8835) | |
434 retval = std::string ("\xc9"); | |
435 else if (code == 8739) | |
436 retval = std::string ("\xbd"); | |
437 else if (code == 8776) | |
438 retval = std::string ("\xbb"); | |
439 else if (code == 8869) | |
440 retval = std::string ("\x5e"); | |
441 else if (code == 8656) | |
442 retval = std::string ("\xdc"); | |
443 else if (code == 8592) | |
444 retval = std::string ("\xac"); | |
445 else if (code == 8658) | |
446 retval = std::string ("\xde"); | |
447 else if (code == 8594) | |
448 retval = std::string ("\xae"); | |
449 else if (code == 8596) | |
450 retval = std::string ("\xab"); | |
451 else if (code == 8593) | |
452 retval = std::string ("\xad"); | |
453 else if (code == 8595) | |
454 retval = std::string ("\xaf"); | |
455 else if (code == 8970) | |
456 retval = std::string ("\xeb"); | |
457 else if (code == 8971) | |
458 retval = std::string ("\xfb"); | |
459 else if (code == 10216) | |
460 retval = std::string ("\xe1"); | |
461 else if (code == 10217) | |
462 retval = std::string ("\xf1"); | |
463 else if (code == 8968) | |
464 retval = std::string ("\xe9"); | |
465 else if (code == 8969) | |
466 retval = std::string ("\xf9"); | |
467 else if (code == 8800) | |
468 retval = std::string ("\xb9"); | |
469 else if (code == 8230) | |
470 retval = std::string ("\xbc"); | |
471 else if (code == 176) | |
472 retval = std::string ("\xb0"); | |
473 else if (code == 8709) | |
474 retval = std::string ("\xc6"); | |
475 else if (code == 169) | |
476 retval = std::string ("\xd3"); | |
477 | |
478 if (retval.empty ()) | |
479 warning ("print: unhandled symbol %d", code); | |
480 | |
481 return retval; | |
482 } | |
483 | |
484 | |
485 static std::string | |
486 select_font (caseless_str fn, bool isbold, bool isitalic) | |
487 { | |
488 std::transform (fn.begin (), fn.end (), fn.begin (), ::tolower); | |
489 std::string fontname; | |
490 if (fn == "times" || fn == "times-roman") | |
491 { | |
492 if (isitalic && isbold) | |
493 fontname = "Times-BoldItalic"; | |
494 else if (isitalic) | |
495 fontname = "Times-Italic"; | |
496 else if (isbold) | |
497 fontname = "Times-Bold"; | |
498 else | |
499 fontname = "Times-Roman"; | |
500 } | |
501 else if (fn == "courier") | |
502 { | |
503 if (isitalic && isbold) | |
504 fontname = "Courier-BoldOblique"; | |
505 else if (isitalic) | |
506 fontname = "Courier-Oblique"; | |
507 else if (isbold) | |
508 fontname = "Courier-Bold"; | |
509 else | |
510 fontname = "Courier"; | |
511 } | |
512 else if (fn == "symbol") | |
513 fontname = "Symbol"; | |
514 else if (fn == "zapfdingbats") | |
515 fontname = "ZapfDingbats"; | |
516 else | |
517 { | |
518 if (isitalic && isbold) | |
519 fontname = "Helvetica-BoldOblique"; | |
520 else if (isitalic) | |
521 fontname = "Helvetica-Oblique"; | |
522 else if (isbold) | |
523 fontname = "Helvetica-Bold"; | |
524 else | |
525 fontname = "Helvetica"; | |
526 } | |
527 return fontname; | |
528 } | |
529 | |
530 static void | |
531 escape_character (const std::string chr, std::string& str) | |
532 { | |
533 std::size_t idx = str.find (chr); | |
534 while (idx != std::string::npos) | |
535 { | |
536 str.insert (idx, "\\"); | |
537 idx = str.find (chr, idx + 2); | |
538 } | |
539 } | |
540 | |
541 Matrix | |
542 gl2ps_renderer::render_text (const std::string& txt, | |
543 double x, double y, double z, | |
544 int ha, int va, double rotation) | |
545 { | |
546 std::string saved_font = fontname; | |
547 | |
548 if (txt.empty ()) | |
549 return Matrix (1, 4, 0.0); | |
550 | |
551 // We have no way to get a bounding box from gl2ps, so we parse the raw | |
552 // string using freetype | |
553 Matrix bbox; | |
554 std::string str = txt; | |
555 std::list<ft_render::ft_string> lst; | |
556 | |
557 text_to_strlist (str, lst, bbox, ha, va, rotation); | |
558 | |
559 // When using "tex" or when the string has only one line and no | |
560 // special characters, use gl2ps for alignment | |
561 if (lst.empty () || term.find ("tex") != std::string::npos | |
562 || (lst.size () == 1 && ! lst.front ().get_code ())) | |
563 { | |
564 std::string name = fontname; | |
565 int sz = fontsize; | |
566 if (! lst.empty () && term.find ("tex") == std::string::npos) | |
567 { | |
568 ft_render::ft_string s = lst.front (); | |
569 name = select_font (s.get_name (), s.get_weight () == "bold", | |
570 s.get_angle () == "italic"); | |
571 set_color (s.get_color ()); | |
572 str = s.get_string (); | |
573 sz = s.get_size (); | |
574 } | |
575 | |
576 glRasterPos3d (x, y, z); | |
577 | |
578 // Escape parenthesis until gl2ps does it (see bug ##45301). | |
579 if (term.find ("svg") == std::string::npos | |
580 && term.find ("tex") == std::string::npos) | |
581 { | |
582 escape_character ("(", str); | |
583 escape_character (")", str); | |
584 } | |
585 | |
586 gl2psTextOpt (str.c_str (), name.c_str (), sz, | |
587 alignment_to_mode (ha, va), rotation); | |
588 return bbox; | |
589 } | |
590 | |
591 // Translate and rotate coordinates in order to use bottom-left alignment | |
592 fix_strlist_position (x, y, z, bbox, rotation, lst); | |
593 | |
594 for (std::list<ft_render::ft_string>::iterator p = lst.begin (); | |
595 p != lst.end (); p++) | |
596 { | |
597 fontname = select_font ((*p).get_name (), | |
598 (*p).get_weight () == "bold", | |
599 (*p).get_angle () == "italic"); | |
600 if ((*p).get_code ()) | |
601 { | |
602 // This is only one character represented by a uint32 (utf8) code. | |
603 // We replace it by the corresponding character in the | |
604 // "Symbol" font except for svg which has built-in utf8 support. | |
605 if (term.find ("svg") == std::string::npos) | |
606 { | |
607 fontname = "Symbol"; | |
608 str = code_to_symbol ((*p).get_code ()); | |
609 } | |
610 else | |
611 { | |
612 std::stringstream ss; | |
613 ss << (*p).get_code (); | |
614 str = "&#" + ss.str () + ";"; | |
615 } | |
616 } | |
617 else | |
618 { | |
619 str = (*p).get_string (); | |
620 // Escape parenthesis until gl2ps does it (see bug ##45301). | |
621 if (term.find ("svg") == std::string::npos) | |
622 { | |
623 escape_character ("(", str); | |
624 escape_character (")", str); | |
625 } | |
626 } | |
627 | |
628 set_color ((*p).get_color ()); | |
629 glRasterPos3d ((*p).get_x (), (*p).get_y (), (*p).get_z ()); | |
630 gl2psTextOpt (str.c_str (), fontname.c_str (), (*p).get_size (), | |
631 GL2PS_TEXT_BL, rotation); | |
632 } | |
633 | |
634 fontname = saved_font; | |
635 return bbox; | |
636 } | |
637 | |
638 void | |
639 gl2ps_renderer::set_font (const base_properties& props) | |
640 { | |
641 opengl_renderer::set_font (props); | |
642 | |
643 // Set the interpreter so that text_to_pixels can parse strings properly | |
644 if (props.has_property ("interpreter")) | |
645 set_interpreter (props.get ("interpreter").string_value ()); | |
646 | |
647 fontsize = props.get ("fontsize_points").double_value (); | |
648 | |
649 caseless_str fn = props.get ("fontname").xtolower ().string_value (); | |
650 bool isbold = | |
651 (props.get ("fontweight").xtolower ().string_value () == "bold"); | |
652 bool isitalic = | |
653 (props.get ("fontangle").xtolower ().string_value () == "italic"); | |
654 | |
655 fontname = select_font (fn, isbold, isitalic); | |
656 } | |
657 | |
658 template <typename T> | |
659 static void | |
660 draw_pixels (GLsizei w, GLsizei h, GLenum format, const T *data, float maxval) | |
661 { | |
662 OCTAVE_LOCAL_BUFFER (GLfloat, a, 3*w*h); | |
663 | |
664 // Convert to GL_FLOAT as it is the only type gl2ps accepts. | |
665 for (int i = 0; i < 3*w*h; i++) | |
666 a[i] = data[i] / maxval; | |
667 | |
668 gl2psDrawPixels (w, h, 0, 0, format, GL_FLOAT, a); | |
669 } | |
670 | |
671 void | |
672 gl2ps_renderer::draw_pixels (GLsizei w, GLsizei h, GLenum format, | |
673 GLenum type, const GLvoid *data) | |
674 { | |
675 // gl2psDrawPixels only supports the GL_FLOAT type. | |
676 // Other formats, such as uint8, must be converted first. | |
677 if (type == GL_UNSIGNED_BYTE) | |
678 ::draw_pixels (w, h, format, static_cast<const GLubyte *> (data), 255.0f); | |
679 else if (type == GL_UNSIGNED_SHORT) | |
680 ::draw_pixels (w, h, format, static_cast<const GLushort *> (data), 65535.0f); | |
681 else | |
682 gl2psDrawPixels (w, h, 0, 0, format, type, data); | |
683 } | |
684 | |
685 void | |
686 gl2ps_renderer::draw_text (const text::properties& props) | |
687 { | |
688 if (props.get_string ().is_empty ()) | |
689 return; | |
690 | |
691 // First set font properties: freetype will use them to compute | |
692 // coordinates and gl2ps will retrieve the color directly from the | |
693 // feedback buffer | |
694 set_font (props); | |
695 set_color (props.get_color_rgb ()); | |
696 | |
697 std::string saved_font = fontname; | |
698 | |
699 // Alignment | |
700 int halign = 0; | |
701 int valign = 0; | |
702 | |
703 if (props.horizontalalignment_is ("center")) | |
704 halign = 1; | |
705 else if (props.horizontalalignment_is ("right")) | |
706 halign = 2; | |
707 | |
708 if (props.verticalalignment_is ("top")) | |
709 valign = 2; | |
710 else if (props.verticalalignment_is ("baseline")) | |
711 valign = 3; | |
712 else if (props.verticalalignment_is ("middle")) | |
713 valign = 1; | |
714 | |
715 // FIXME: handle margin and surrounding box | |
716 // Matrix bbox; | |
717 | |
718 const Matrix pos = get_transform ().scale (props.get_data_position ()); | |
719 std::string str = props.get_string ().string_vector_value ().join ("\n"); | |
720 | |
721 render_text (str, pos(0), pos(1), pos.numel () > 2 ? pos(2) : 0.0, | |
722 halign, valign, props.get_rotation ()); | |
723 } | |
724 | |
725 #endif | |
726 | |
727 static void | |
728 safe_pclose (FILE *f) | |
729 { | |
730 if (f) | |
731 octave_pclose (f); | |
732 } | |
733 | |
734 static void | |
735 safe_fclose (FILE *f) | |
736 { | |
737 if (f) | |
738 gnulib::fclose (f); | |
739 } | |
740 | |
741 // If the name of the stream begins with '|', open a pipe to the command | |
742 // named by the rest of the string. Otherwise, write to the named file. | |
743 | |
744 void | |
745 gl2ps_print (const graphics_object& fig, const std::string& stream, | |
746 const std::string& term) | |
747 { | |
748 #if defined (HAVE_GL2PS_H) | |
749 | |
750 // FIXME: should we have a way to create a file that begins with the | |
751 // character '|'? | |
752 | |
753 bool have_cmd = stream.length () > 1 && stream[0] == '|'; | |
754 | |
755 FILE *fp = 0; | |
756 | |
757 unwind_protect frame; | |
758 | |
759 if (have_cmd) | |
760 { | |
761 // Create process and pipe gl2ps output to it. | |
762 | |
763 std::string cmd = stream.substr (1); | |
764 | |
765 fp = octave_popen (cmd.c_str (), "w"); | |
766 | |
767 if (! fp) | |
768 error ("print: failed to open pipe \"%s\"", stream.c_str ()); | |
769 | |
770 frame.add_fcn (safe_pclose, fp); | |
771 } | |
772 else | |
773 { | |
774 // Write gl2ps output directly to file. | |
775 | |
776 fp = gnulib::fopen (stream.c_str (), "w"); | |
777 | |
778 if (! fp) | |
779 error ("gl2ps_print: failed to create file \"%s\"", stream.c_str ()); | |
780 | |
781 frame.add_fcn (safe_fclose, fp); | |
782 } | |
783 | |
784 gl2ps_renderer rend (fp, term); | |
785 | |
786 rend.draw (fig, ""); | |
787 | |
788 // Make sure buffered commands are finished!!! | |
789 rend.finish (); | |
790 | |
791 #else | |
792 | |
793 err_disabled_feature ("gl2ps_print", "gl2ps"); | |
794 | |
795 #endif | |
796 } |