gl-render.cc

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 2008-2012 Michael Goffioul
00004 
00005 This file is part of Octave.
00006 
00007 Octave is free software; you can redistribute it and/or modify it
00008 under the terms of the GNU General Public License as published by the
00009 Free Software Foundation; either version 3 of the License, or (at your
00010 option) any later version.
00011 
00012 Octave is distributed in the hope that it will be useful, but WITHOUT
00013 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00014 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00015 for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Octave; see the file COPYING.  If not, see
00019 <http://www.gnu.org/licenses/>.
00020 
00021 */
00022 
00023 #ifdef HAVE_CONFIG_H
00024 #include <config.h>
00025 #endif
00026 
00027 #if defined (HAVE_OPENGL)
00028 
00029 #include <iostream>
00030 
00031 #include <lo-mappers.h>
00032 #include "oct-locbuf.h"
00033 #include "oct-refcount.h"
00034 #include "gl-render.h"
00035 #include "txt-eng.h"
00036 #include "txt-eng-ft.h"
00037 
00038 #define LIGHT_MODE GL_FRONT_AND_BACK
00039 
00040 // Win32 API requires the CALLBACK attributes for
00041 // GLU callback functions. Define it to empty on
00042 // other platforms.
00043 #ifndef CALLBACK
00044 #define CALLBACK
00045 #endif
00046 
00047 static octave_idx_type
00048 xmin (octave_idx_type x, octave_idx_type y)
00049 {
00050   return x < y ? x : y;
00051 }
00052 
00053 class
00054 opengl_texture
00055 {
00056 protected:
00057   class texture_rep
00058   {
00059   public:
00060     texture_rep (void)
00061       : id (), w (), h (), tw (), th (), tx (), ty (),
00062         valid (false), count (1)
00063     { }
00064 
00065     texture_rep (GLuint id_arg, int w_arg, int h_arg, int tw_arg, int th_arg)
00066         : id (id_arg), w (w_arg), h (h_arg), tw (tw_arg), th (th_arg),
00067           tx (double(w)/tw), ty (double(h)/th), valid (true),
00068           count (1) { }
00069 
00070     ~texture_rep (void)
00071       {
00072         if (valid)
00073           glDeleteTextures (1, &id);
00074       }
00075 
00076     void bind (int mode) const
00077       { if (valid) glBindTexture (mode, id); }
00078 
00079     void tex_coord (double q, double r) const
00080       { if (valid) glTexCoord2d (q*tx, r*ty); }
00081 
00082     GLuint id;
00083     int w, h;
00084     int tw, th;
00085     double tx, ty;
00086     bool valid;
00087     octave_refcount<int> count;
00088   };
00089 
00090   texture_rep *rep;
00091 
00092 private:
00093   opengl_texture (texture_rep *_rep) : rep (_rep) { }
00094 
00095 public:
00096   opengl_texture (void) : rep (new texture_rep ()) { }
00097 
00098   opengl_texture (const opengl_texture& tx)
00099       : rep (tx.rep)
00100     {
00101       rep->count++;
00102     }
00103 
00104   ~opengl_texture (void)
00105     {
00106       if (--rep->count == 0)
00107         delete rep;
00108     }
00109 
00110   opengl_texture& operator = (const opengl_texture& tx)
00111     {
00112       if (--rep->count == 0)
00113         delete rep;
00114 
00115       rep = tx.rep;
00116       rep->count++;
00117 
00118       return *this;
00119     }
00120 
00121   static opengl_texture create (const octave_value& data);
00122 
00123   void bind (int mode = GL_TEXTURE_2D) const
00124     { rep->bind (mode); }
00125 
00126   void tex_coord (double q, double r) const
00127     { rep->tex_coord (q, r); }
00128 
00129   bool is_valid (void) const
00130     { return rep->valid; }
00131 };
00132 
00133 static int
00134 next_power_of_2 (int n)
00135 {
00136   int m = 1;
00137 
00138   while (m < n && m < INT_MAX)
00139     m <<= 1;
00140 
00141   return m;
00142 }
00143 
00144 opengl_texture
00145 opengl_texture::create (const octave_value& data)
00146 {
00147   opengl_texture retval;
00148 
00149   dim_vector dv (data.dims ());
00150 
00151   // Expect RGB data
00152   if (dv.length () == 3 && dv(2) == 3)
00153     {
00154       // FIXME -- dim_vectors hold octave_idx_type values.  Should we
00155       // check for dimensions larger than intmax?
00156       int h = dv(0), w = dv(1), tw, th;
00157       GLuint id;
00158       bool ok = true;
00159 
00160       tw = next_power_of_2 (w);
00161       th = next_power_of_2 (w);
00162 
00163       glGenTextures (1, &id);
00164       glBindTexture (GL_TEXTURE_2D, id);
00165 
00166       if (data.is_double_type ())
00167         {
00168           const NDArray xdata = data.array_value ();
00169 
00170           OCTAVE_LOCAL_BUFFER (float, a, (3*tw*th));
00171 
00172           for (int i = 0; i < h; i++)
00173             {
00174               for (int j = 0, idx = i*tw*3; j < w; j++, idx += 3)
00175                 {
00176                   a[idx]   = xdata(i,j,0);
00177                   a[idx+1] = xdata(i,j,1);
00178                   a[idx+2] = xdata(i,j,2);
00179                 }
00180             }
00181 
00182           glTexImage2D (GL_TEXTURE_2D, 0, 3, tw, th, 0,
00183                         GL_RGB, GL_FLOAT, a);
00184         }
00185       else if (data.is_uint8_type ())
00186         {
00187           const uint8NDArray xdata = data.uint8_array_value ();
00188 
00189           OCTAVE_LOCAL_BUFFER (octave_uint8, a, (3*tw*th));
00190 
00191           for (int i = 0; i < h; i++)
00192             {
00193               for (int j = 0, idx = i*tw*3; j < w; j++, idx += 3)
00194                 {
00195                   a[idx]   = xdata(i,j,0);
00196                   a[idx+1] = xdata(i,j,1);
00197                   a[idx+2] = xdata(i,j,2);
00198                 }
00199             }
00200 
00201           glTexImage2D (GL_TEXTURE_2D, 0, 3, tw, th, 0,
00202                         GL_RGB, GL_UNSIGNED_BYTE, a);
00203         }
00204       else
00205         {
00206           ok = false;
00207           warning ("opengl_texture::create: invalid texture data type (expected double or uint8)");
00208         }
00209 
00210       if (ok)
00211         {
00212           glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
00213           glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
00214 
00215           if (glGetError () != GL_NO_ERROR)
00216             warning ("opengl_texture::create: OpenGL error while generating texture data");
00217           else
00218             retval = opengl_texture (new texture_rep (id, w, h, tw, th));
00219         }
00220     }
00221   else
00222     warning ("opengl_texture::create: invalid texture data size");
00223 
00224   return retval;
00225 }
00226 
00227 class
00228 opengl_tesselator
00229 {
00230 public:
00231 #if defined (HAVE_FRAMEWORK_OPENGL) && defined (HAVE_GLUTESSCALLBACK_THREEDOTS)
00232   typedef GLvoid (CALLBACK *fcn) (...);
00233 #else
00234   typedef void (CALLBACK *fcn) (void);
00235 #endif
00236 
00237 public:
00238 
00239   opengl_tesselator (void) : glu_tess (0), fill() { init (); }
00240 
00241   virtual ~opengl_tesselator (void)
00242     { if (glu_tess) gluDeleteTess (glu_tess); }
00243 
00244   void begin_polygon (bool filled = true)
00245     {
00246       gluTessProperty (glu_tess, GLU_TESS_BOUNDARY_ONLY,
00247                        (filled ? GL_FALSE : GL_TRUE));
00248       fill = filled;
00249       gluTessBeginPolygon (glu_tess, this);
00250     }
00251 
00252   void end_polygon (void) const
00253     { gluTessEndPolygon (glu_tess); }
00254 
00255   void begin_contour (void) const
00256     { gluTessBeginContour (glu_tess); }
00257 
00258   void end_contour (void) const
00259     { gluTessEndContour (glu_tess); }
00260 
00261   void add_vertex (double *loc, void *data) const
00262     { gluTessVertex (glu_tess, loc, data); }
00263 
00264 protected:
00265   virtual void begin (GLenum /*type*/) { }
00266 
00267   virtual void end (void) { }
00268 
00269   virtual void vertex (void */*data*/) { }
00270 
00271   virtual void combine (GLdouble /*c*/[3], void */*data*/[4],
00272                         GLfloat /*w*/[4], void **/*out_data*/) { }
00273 
00274   virtual void edge_flag (GLboolean /*flag*/) { }
00275 
00276   virtual void error (GLenum err)
00277     { ::error ("OpenGL tesselation error (%d)", err); }
00278 
00279   virtual void init (void)
00280     {
00281       glu_tess = gluNewTess ();
00282 
00283       gluTessCallback (glu_tess, GLU_TESS_BEGIN_DATA,
00284                        reinterpret_cast<fcn> (tess_begin));
00285       gluTessCallback (glu_tess, GLU_TESS_END_DATA,
00286                        reinterpret_cast<fcn> (tess_end));
00287       gluTessCallback (glu_tess, GLU_TESS_VERTEX_DATA,
00288                        reinterpret_cast<fcn> (tess_vertex));
00289       gluTessCallback (glu_tess, GLU_TESS_COMBINE_DATA,
00290                        reinterpret_cast<fcn> (tess_combine));
00291       gluTessCallback (glu_tess, GLU_TESS_EDGE_FLAG_DATA,
00292                        reinterpret_cast<fcn> (tess_edge_flag));
00293       gluTessCallback (glu_tess, GLU_TESS_ERROR_DATA,
00294                        reinterpret_cast<fcn> (tess_error));
00295     }
00296 
00297   bool is_filled (void) const { return fill; }
00298 
00299 private:
00300   static void CALLBACK tess_begin (GLenum type, void *t)
00301     { reinterpret_cast<opengl_tesselator *> (t)->begin (type); }
00302 
00303   static void CALLBACK tess_end (void *t)
00304     { reinterpret_cast<opengl_tesselator *> (t)->end (); }
00305 
00306   static void CALLBACK tess_vertex (void *v, void *t)
00307     { reinterpret_cast<opengl_tesselator *> (t)->vertex (v); }
00308 
00309   static void CALLBACK tess_combine (GLdouble c[3], void *v[4], GLfloat w[4],
00310                                      void **out,  void *t)
00311     { reinterpret_cast<opengl_tesselator *> (t)->combine (c, v, w, out); }
00312 
00313   static void CALLBACK tess_edge_flag (GLboolean flag, void *t)
00314     { reinterpret_cast<opengl_tesselator *> (t)->edge_flag (flag); }
00315 
00316   static void CALLBACK tess_error (GLenum err, void *t)
00317     { reinterpret_cast<opengl_tesselator *> (t)->error (err); }
00318 
00319 private:
00320 
00321   // No copying!
00322 
00323   opengl_tesselator (const opengl_tesselator&);
00324 
00325   opengl_tesselator operator = (const opengl_tesselator&);
00326 
00327   GLUtesselator *glu_tess;
00328   bool fill;
00329 };
00330 
00331 class
00332 vertex_data
00333 {
00334 public:
00335   class vertex_data_rep
00336   {
00337   public:
00338     Matrix coords;
00339     Matrix color;
00340     Matrix normal;
00341     double alpha;
00342     float ambient;
00343     float diffuse;
00344     float specular;
00345     float specular_exp;
00346 
00347     // reference counter
00348     octave_refcount<int> count;
00349 
00350     vertex_data_rep (void)
00351       : coords (), color (), normal (), alpha (),
00352         ambient (), diffuse (), specular (), specular_exp (),count (1) { }
00353 
00354     vertex_data_rep (const Matrix& c, const Matrix& col, const Matrix& n,
00355                      double a, float as, float ds, float ss, float se)
00356         : coords (c), color (col), normal (n), alpha (a),
00357           ambient (as), diffuse (ds), specular (ss), specular_exp (se),
00358           count (1) { }
00359   };
00360 
00361 private:
00362   vertex_data_rep *rep;
00363 
00364   vertex_data_rep *nil_rep (void) const
00365     {
00366       static vertex_data_rep *nr = new vertex_data_rep ();
00367 
00368       return nr;
00369     }
00370 
00371 public:
00372   vertex_data (void) : rep (nil_rep ())
00373     { rep->count++; }
00374 
00375   vertex_data (const vertex_data& v) : rep (v.rep)
00376     { rep->count++; }
00377 
00378   vertex_data (const Matrix& c, const Matrix& col, const Matrix& n,
00379                double a, float as, float ds, float ss, float se)
00380       : rep (new vertex_data_rep (c, col, n, a, as, ds, ss, se))
00381     { }
00382 
00383   vertex_data (vertex_data_rep *new_rep)
00384       : rep (new_rep) { }
00385 
00386   ~vertex_data (void)
00387     {
00388       if (--rep->count == 0)
00389         delete rep;
00390     }
00391 
00392   vertex_data& operator = (const vertex_data& v)
00393     {
00394       if (--rep->count == 0)
00395         delete rep;
00396 
00397       rep = v.rep;
00398       rep->count++;
00399 
00400       return *this;
00401     }
00402 
00403   vertex_data_rep *get_rep (void) const { return rep; }
00404 };
00405 
00406 class
00407 opengl_renderer::patch_tesselator : public opengl_tesselator
00408 {
00409 public:
00410   patch_tesselator (opengl_renderer *r, int cmode, int lmode, int idx = 0)
00411       : opengl_tesselator (), renderer (r),
00412         color_mode (cmode), light_mode (lmode), index (idx),
00413         first (true), tmp_vdata ()
00414   { }
00415 
00416 protected:
00417   void begin (GLenum type)
00418     {
00419       //printf("patch_tesselator::begin (%d)\n", type);
00420       first = true;
00421 
00422       if (color_mode == 2 || light_mode == 2)
00423         glShadeModel (GL_SMOOTH);
00424       else
00425         glShadeModel (GL_FLAT);
00426 
00427       if (is_filled ())
00428         renderer->set_polygon_offset (true, 1+index);
00429 
00430       glBegin (type);
00431     }
00432 
00433   void end (void)
00434     {
00435       //printf("patch_tesselator::end\n");
00436       glEnd ();
00437       renderer->set_polygon_offset (false);
00438     }
00439 
00440   void vertex (void *data)
00441     {
00442       vertex_data::vertex_data_rep *v
00443           = reinterpret_cast<vertex_data::vertex_data_rep *> (data);
00444       //printf("patch_tesselator::vertex (%g, %g, %g)\n", v->coords(0), v->coords(1), v->coords(2));
00445 
00446       // FIXME: why did I need to keep the first vertex of the face
00447       // in JHandles? I think it's related to the fact that the
00448       // tessellation process might re-order the vertices, such that
00449       // the first one you get here might not be the first one of the face;
00450       // but I can't figure out the actual reason.
00451       if (color_mode > 0 && (first || color_mode == 2))
00452         {
00453           Matrix col = v->color;
00454 
00455           if (col.numel () == 3)
00456             {
00457               glColor3dv (col.data ());
00458               if (light_mode > 0)
00459                 {
00460                   float buf[4] = { 0, 0, 0, 1 };
00461 
00462                   for (int k = 0; k < 3; k++)
00463                     buf[k] = (v->ambient * col(k));
00464                   glMaterialfv (LIGHT_MODE, GL_AMBIENT, buf);
00465 
00466                   for (int k = 0; k < 3; k++)
00467                     buf[k] = (v->diffuse * col(k));
00468                   glMaterialfv (LIGHT_MODE, GL_AMBIENT, buf);
00469                 }
00470             }
00471         }
00472 
00473       if (light_mode > 0 && (first || light_mode == 2))
00474         glNormal3dv (v->normal.data ());
00475 
00476       glVertex3dv (v->coords.data ());
00477 
00478       first = false;
00479     }
00480 
00481   void combine (GLdouble xyz[3], void *data[4], GLfloat w[4],
00482                 void **out_data)
00483     {
00484       //printf("patch_tesselator::combine\n");
00485 
00486       vertex_data::vertex_data_rep *v[4];
00487       int vmax = 4;
00488 
00489       for (int i = 0; i < 4; i++)
00490         {
00491           v[i] = reinterpret_cast<vertex_data::vertex_data_rep *> (data[i]);
00492 
00493           if (vmax == 4 && ! v[i])
00494             vmax = i;
00495         }
00496 
00497       Matrix vv (1, 3, 0.0);
00498       Matrix cc;
00499       Matrix nn (1, 3, 0.0);
00500       double aa = 0.0;
00501 
00502       vv(0) = xyz[0];
00503       vv(1) = xyz[1];
00504       vv(2) = xyz[2];
00505 
00506       if (v[0]->color.numel ())
00507         {
00508           cc.resize (1, 3, 0.0);
00509           for (int ic = 0; ic < 3; ic++)
00510             for (int iv = 0; iv < vmax; iv++)
00511               cc(ic) += (w[iv] * v[iv]->color(ic));
00512         }
00513 
00514       if (v[0]->normal.numel () > 0)
00515         {
00516           for (int in = 0; in < 3; in++)
00517             for (int iv = 0; iv < vmax; iv++)
00518               nn(in) += (w[iv] * v[iv]->normal(in));
00519         }
00520 
00521       for (int iv = 0; iv < vmax; iv++)
00522         aa += (w[iv] * v[iv]->alpha);
00523 
00524       vertex_data new_v (vv, cc, nn, aa, v[0]->ambient, v[0]->diffuse,
00525                          v[0]->specular, v[0]->specular_exp);
00526       tmp_vdata.push_back (new_v);
00527 
00528       *out_data = new_v.get_rep ();
00529     }
00530 
00531 private:
00532 
00533   // No copying!
00534 
00535   patch_tesselator (const patch_tesselator&);
00536 
00537   patch_tesselator& operator = (const patch_tesselator&);
00538 
00539   opengl_renderer *renderer;
00540   int color_mode;       // 0: uni,  1: flat, 2: interp
00541   int light_mode;       // 0: none, 1: flat, 2: gouraud
00542   int index;
00543   bool first;
00544   std::list<vertex_data> tmp_vdata;
00545 };
00546 
00547 void
00548 opengl_renderer::draw (const graphics_object& go, bool toplevel)
00549 {
00550   if (! go.valid_object ())
00551     return;
00552 
00553   const base_properties& props = go.get_properties ();
00554 
00555   if (go.isa ("figure"))
00556     draw_figure (dynamic_cast<const figure::properties&> (props));
00557   else if (go.isa ("axes"))
00558     draw_axes (dynamic_cast<const axes::properties&> (props));
00559   else if (go.isa ("line"))
00560     draw_line (dynamic_cast<const line::properties&> (props));
00561   else if (go.isa ("surface"))
00562     draw_surface (dynamic_cast<const surface::properties&> (props));
00563   else if (go.isa ("patch"))
00564     draw_patch (dynamic_cast<const patch::properties&> (props));
00565   else if (go.isa ("hggroup"))
00566     draw_hggroup (dynamic_cast<const hggroup::properties&> (props));
00567   else if (go.isa ("text"))
00568     draw_text (dynamic_cast<const text::properties&> (props));
00569   else if (go.isa ("image"))
00570     draw_image (dynamic_cast<const image::properties&> (props));
00571   else if (go.isa ("uimenu") || go.isa ("uicontrol")
00572            || go.isa ("uicontextmenu") || go.isa ("uitoolbar")
00573            || go.isa ("uipushtool") || go.isa ("uitoggletool"))
00574     /* SKIP */;
00575   else if (go.isa ("uipanel"))
00576     {
00577       if (toplevel)
00578         draw_uipanel (dynamic_cast<const uipanel::properties&> (props), go);
00579     }
00580   else
00581     {
00582       warning ("opengl_renderer: cannot render object of type '%s'",
00583                props.graphics_object_name ().c_str ());
00584     }
00585 }
00586 
00587 void
00588 opengl_renderer::draw_figure (const figure::properties& props)
00589 {
00590   toolkit = props.get_toolkit ();
00591 
00592   // Initialize OpenGL context
00593 
00594   init_gl_context (props.is___enhanced__ (), props.get_color_rgb ());
00595 
00596   // Draw children
00597 
00598   draw (props.get_all_children (), false);
00599 }
00600 
00601 void
00602 opengl_renderer::draw_uipanel (const uipanel::properties& props,
00603                                const graphics_object& go)
00604 {
00605   graphics_object fig = go.get_ancestor ("figure");
00606   const figure::properties& figProps =
00607     dynamic_cast<const figure::properties&> (fig.get_properties ());
00608 
00609   toolkit = figProps.get_toolkit ();
00610 
00611   // Initialize OpenGL context 
00612 
00613   init_gl_context (figProps.is___enhanced__ (),
00614                    props.get_backgroundcolor_rgb ());
00615 
00616   // Draw children
00617 
00618   draw (props.get_all_children (), false);
00619 }
00620 
00621 void
00622 opengl_renderer::init_gl_context (bool enhanced, const Matrix& c)
00623 {
00624   // Initialize OpenGL context
00625 
00626   glEnable (GL_DEPTH_TEST);
00627   glDepthFunc (GL_LEQUAL);
00628   glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00629   glAlphaFunc (GL_GREATER, 0.0f);
00630   glEnable (GL_NORMALIZE);
00631 
00632   if (enhanced)
00633     {
00634       glEnable (GL_BLEND);
00635       glEnable (GL_LINE_SMOOTH);
00636     }
00637   else
00638     {
00639       glDisable (GL_BLEND);
00640       glDisable (GL_LINE_SMOOTH);
00641     }
00642 
00643   // Clear background
00644 
00645   if (c.length() >= 3)
00646     {
00647       glClearColor (c(0), c(1), c(2), 1);
00648       glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
00649     }
00650 }
00651 
00652 void
00653 opengl_renderer::render_grid (const std::string& gridstyle,
00654                               const Matrix& ticks, double lim1, double lim2,
00655                               double p1, double p1N, double p2, double p2N,
00656                               int xyz, bool is_3D)
00657 {
00658   set_linestyle (gridstyle, true);
00659   glBegin (GL_LINES);
00660   for (int i = 0; i < ticks.numel (); i++)
00661     {
00662       double val = ticks(i);
00663       if (lim1 <= val && val <= lim2)
00664         {
00665           if (xyz == 0) // X
00666             {
00667               glVertex3d (val, p1N, p2);
00668               glVertex3d (val, p1, p2);
00669               if (is_3D)
00670                 {
00671                   glVertex3d (val, p1, p2N);
00672                   glVertex3d (val, p1, p2);
00673                 }
00674             }
00675           else if (xyz == 1) // Y
00676             {
00677               glVertex3d (p1N, val, p2);
00678               glVertex3d (p1, val, p2);
00679               if (is_3D)
00680                 {
00681                   glVertex3d (p1, val, p2N);
00682                   glVertex3d (p1, val, p2);
00683                 }
00684             }
00685           else if (xyz == 2) // Z
00686             {
00687               glVertex3d (p1N, p2, val);
00688               glVertex3d (p1, p2, val);
00689               glVertex3d (p1, p2N, val);
00690               glVertex3d (p1, p2, val);
00691             }
00692         }
00693     }
00694   glEnd ();
00695   set_linestyle ("-", true);
00696 }
00697 
00698 void
00699 opengl_renderer::render_tickmarks (const Matrix& ticks,
00700                                    double lim1, double lim2,
00701                                    double p1, double p1N,
00702                                    double p2, double p2N,
00703                                    double dx, double dy, double dz,
00704                                    int xyz, bool mirror)
00705 {
00706   glBegin (GL_LINES);
00707 
00708   for (int i = 0; i < ticks.numel (); i++)
00709     {
00710       double val = ticks(i);
00711 
00712       if (lim1 <= val && val <= lim2)
00713         {
00714           if (xyz == 0) // X
00715             {
00716               glVertex3d (val, p1, p2);
00717               glVertex3d (val, p1+dy, p2+dz);
00718               if (mirror)
00719                 {
00720                   glVertex3d (val, p1N, p2N);
00721                   glVertex3d (val, p1N-dy, p2N-dz);
00722                 }
00723             }
00724           else if (xyz == 1) // Y
00725             {
00726               glVertex3d (p1, val, p2);
00727               glVertex3d (p1+dx, val, p2+dz);
00728               if (mirror)
00729                 {
00730                   glVertex3d (p1N, val, p2N);
00731                   glVertex3d (p1N-dx, val, p2N-dz);
00732                 }
00733             }
00734           else if (xyz == 2) // Z
00735             {
00736               glVertex3d (p1, p2, val);
00737               glVertex3d (p1+dx, p2+dy, val);
00738               if (mirror)
00739                 {
00740                   glVertex3d (p1N, p2N, val);
00741                   glVertex3d (p1N-dx, p2N-dy, val);
00742                 }
00743             }
00744         }
00745     }
00746 
00747   glEnd ();
00748 }
00749 
00750 void
00751 opengl_renderer::render_ticktexts (const Matrix& ticks,
00752                                    const string_vector& ticklabels,
00753                                    double lim1, double lim2,
00754                                    double p1, double p2,
00755                                    int xyz, int ha, int va,
00756                                    int& wmax, int& hmax)
00757 {
00758   int n = std::min (ticklabels.numel (), ticks.numel ());
00759 
00760   for (int i = 0; i < n; i++)
00761     {
00762       double val = ticks(i);
00763 
00764       if (lim1 <= val && val <= lim2)
00765         {
00766           Matrix b;
00767           // FIXME: as tick text is transparent, shouldn't be
00768           //        drawn after axes object, for correct rendering?
00769           if (xyz == 0) // X
00770             {
00771               b = render_text (ticklabels(i), val, p1, p2, ha, va);
00772             }
00773           else if (xyz == 1) // Y
00774             {
00775               b = render_text (ticklabels(i), p1, val, p2, ha, va);
00776             }
00777           else if (xyz == 2) // Z
00778             {
00779               b = render_text (ticklabels(i), p1, p2, val, ha, va);
00780             }
00781 
00782           wmax = std::max (wmax, static_cast<int> (b(2)));
00783           hmax = std::max (hmax, static_cast<int> (b(3)));
00784         }
00785     }
00786 }
00787 
00788 void
00789 opengl_renderer::setup_opengl_transformation (const axes::properties& props)
00790 {
00791   // setup OpenGL transformation
00792 
00793   Matrix x_zlim = props.get_transform_zlim ();
00794 
00795   xZ1 = x_zlim(0)-(x_zlim(1)-x_zlim(0))/2;
00796   xZ2 = x_zlim(1)+(x_zlim(1)-x_zlim(0))/2;
00797 
00798   Matrix x_mat1 = props.get_opengl_matrix_1 ();
00799   Matrix x_mat2 = props.get_opengl_matrix_2 ();
00800 
00801 #if defined (HAVE_FRAMEWORK_OPENGL)
00802   GLint vw[4];
00803 #else
00804   int vw[4];
00805 #endif
00806 
00807   glGetIntegerv (GL_VIEWPORT, vw);
00808 
00809   glMatrixMode (GL_MODELVIEW);
00810   glLoadIdentity ();
00811   glScaled(1, 1, -1);
00812   glMultMatrixd (x_mat1.data ());
00813   glMatrixMode (GL_PROJECTION);
00814   glLoadIdentity ();
00815   glOrtho (0, vw[2], vw[3], 0, xZ1, xZ2);
00816   glMultMatrixd (x_mat2.data ());
00817   glMatrixMode (GL_MODELVIEW);
00818 
00819   glClear (GL_DEPTH_BUFFER_BIT);
00820 
00821   glDisable (GL_LINE_SMOOTH);
00822 
00823   // store axes transformation data
00824 
00825   xform = props.get_transform ();
00826 }
00827 
00828 void
00829 opengl_renderer::draw_axes_planes (const axes::properties& props)
00830 {
00831   double xPlane = props.get_xPlane ();
00832   double yPlane = props.get_yPlane ();
00833   double zPlane = props.get_zPlane ();
00834   double xPlaneN = props.get_xPlaneN ();
00835   double yPlaneN = props.get_yPlaneN ();
00836   double zPlaneN = props.get_zPlaneN ();
00837 
00838   // Axes planes
00839   Matrix axe_color = props.get_color_rgb ();
00840   if (axe_color.numel () > 0 && props.is_visible ())
00841     {
00842       set_color (axe_color);
00843       set_polygon_offset (true, 2.5);
00844 
00845       glBegin (GL_QUADS);
00846 
00847       // X plane
00848       glVertex3d (xPlane, yPlaneN, zPlaneN);
00849       glVertex3d (xPlane, yPlane, zPlaneN);
00850       glVertex3d (xPlane, yPlane, zPlane);
00851       glVertex3d (xPlane, yPlaneN, zPlane);
00852 
00853       // Y plane
00854       glVertex3d (xPlaneN, yPlane, zPlaneN);
00855       glVertex3d (xPlane, yPlane, zPlaneN);
00856       glVertex3d (xPlane, yPlane, zPlane);
00857       glVertex3d (xPlaneN, yPlane, zPlane);
00858 
00859       // Z plane
00860       glVertex3d (xPlaneN, yPlaneN, zPlane);
00861       glVertex3d (xPlane, yPlaneN, zPlane);
00862       glVertex3d (xPlane, yPlane, zPlane);
00863       glVertex3d (xPlaneN, yPlane, zPlane);
00864 
00865       glEnd ();
00866 
00867       set_polygon_offset (false);
00868     }
00869 }
00870 
00871 void
00872 opengl_renderer::draw_axes_boxes (const axes::properties& props)
00873 {
00874   bool xySym = props.get_xySym ();
00875   double xPlane = props.get_xPlane ();
00876   double yPlane = props.get_yPlane ();
00877   double zPlane = props.get_zPlane ();
00878   double xPlaneN = props.get_xPlaneN ();
00879   double yPlaneN = props.get_yPlaneN ();
00880   double zPlaneN = props.get_zPlaneN ();
00881   double xpTick = props.get_xpTick ();
00882   double ypTick = props.get_ypTick ();
00883   double zpTick = props.get_zpTick ();
00884   double xpTickN = props.get_xpTickN ();
00885   double ypTickN = props.get_ypTickN ();
00886   double zpTickN = props.get_zpTickN ();
00887 
00888   bool plotyy = (props.has_property ("__plotyy_axes__"));
00889 
00890   // Axes box
00891 
00892   set_linestyle ("-", true);
00893   set_linewidth (props.get_linewidth ());
00894 
00895   if (props.is_visible ())
00896     {
00897       glBegin (GL_LINES);
00898 
00899       // X box
00900       set_color (props.get_xcolor_rgb ());
00901       glVertex3d (xPlaneN, ypTick, zpTick);
00902       glVertex3d (xPlane, ypTick, zpTick);
00903 
00904       if (props.is_box ())
00905         {
00906           glVertex3d (xPlaneN, ypTickN, zpTick);
00907           glVertex3d (xPlane, ypTickN, zpTick);
00908           glVertex3d (xPlaneN, ypTickN, zpTickN);
00909           glVertex3d (xPlane, ypTickN, zpTickN);
00910           glVertex3d (xPlaneN, ypTick, zpTickN);
00911           glVertex3d (xPlane, ypTick, zpTickN);
00912         }
00913 
00914       // Y box
00915       set_color (props.get_ycolor_rgb ());
00916       glVertex3d (xpTick, yPlaneN, zpTick);
00917       glVertex3d (xpTick, yPlane, zpTick);
00918 
00919       if (props.is_box () && ! plotyy)
00920         {
00921           glVertex3d (xpTickN, yPlaneN, zpTick);
00922           glVertex3d (xpTickN, yPlane, zpTick);
00923           glVertex3d (xpTickN, yPlaneN, zpTickN);
00924           glVertex3d (xpTickN, yPlane, zpTickN);
00925           glVertex3d (xpTick, yPlaneN, zpTickN);
00926           glVertex3d (xpTick, yPlane, zpTickN);
00927         }
00928 
00929       // Z box
00930       set_color (props.get_zcolor_rgb ());
00931 
00932       if (xySym)
00933         {
00934           glVertex3d (xPlaneN, yPlane, zPlaneN);
00935           glVertex3d (xPlaneN, yPlane, zPlane);
00936         }
00937       else
00938         {
00939           glVertex3d (xPlane, yPlaneN, zPlaneN);
00940           glVertex3d (xPlane, yPlaneN, zPlane);
00941         }
00942 
00943       if (props.is_box ())
00944         {
00945           glVertex3d (xPlane, yPlane, zPlaneN);
00946           glVertex3d (xPlane, yPlane, zPlane);
00947 
00948           if (xySym)
00949             {
00950               glVertex3d (xPlane, yPlaneN, zPlaneN);
00951               glVertex3d (xPlane, yPlaneN, zPlane);
00952             }
00953           else
00954             {
00955               glVertex3d (xPlaneN, yPlane, zPlaneN);
00956               glVertex3d (xPlaneN, yPlane, zPlane);
00957             }
00958 
00959           glVertex3d (xPlaneN, yPlaneN, zPlaneN);
00960           glVertex3d (xPlaneN, yPlaneN, zPlane);
00961         }
00962 
00963       glEnd ();
00964     }
00965 }
00966 
00967 void
00968 opengl_renderer::draw_axes_x_grid (const axes::properties& props)
00969 {
00970   int xstate = props.get_xstate ();
00971   int zstate = props.get_zstate ();
00972   bool x2Dtop = props.get_x2Dtop ();
00973   bool layer2Dtop = props.get_layer2Dtop ();
00974   bool xyzSym = props.get_xyzSym ();
00975   bool nearhoriz = props.get_nearhoriz ();
00976   double xticklen = props.get_xticklen ();
00977   double xtickoffset = props.get_xtickoffset ();
00978   double fy = props.get_fy ();
00979   double fz = props.get_fz ();
00980   double x_min = props.get_x_min ();
00981   double x_max = props.get_x_max ();
00982   double yPlane = props.get_yPlane ();
00983   double yPlaneN = props.get_yPlaneN ();
00984   double ypTick = props.get_ypTick ();
00985   double ypTickN = props.get_ypTickN ();
00986   double zPlane = props.get_zPlane ();
00987   double zPlaneN = props.get_zPlaneN ();
00988   double zpTick = props.get_zpTick ();
00989   double zpTickN = props.get_zpTickN ();
00990 
00991   // X grid
00992 
00993   if (props.is_visible () && xstate != AXE_DEPTH_DIR)
00994     {
00995       std::string gridstyle = props.get_gridlinestyle ();
00996       std::string minorgridstyle = props.get_minorgridlinestyle ();
00997       bool do_xgrid = (props.is_xgrid () && (gridstyle != "none"));
00998       bool do_xminorgrid = (props.is_xminorgrid () && (minorgridstyle != "none"));
00999       bool do_xminortick = props.is_xminortick ();
01000       Matrix xticks = xform.xscale (props.get_xtick ().matrix_value ());
01001       Matrix xmticks = xform.xscale (props.get_xmtick ().matrix_value ());
01002       string_vector xticklabels = props.get_xticklabel ().all_strings ();
01003       int wmax = 0, hmax = 0;
01004       bool tick_along_z = nearhoriz || xisinf (fy);
01005       bool mirror = props.is_box () && xstate != AXE_ANY_DIR;
01006 
01007       set_color (props.get_xcolor_rgb ());
01008 
01009       // grid lines
01010       if (do_xgrid)
01011         render_grid (gridstyle, xticks, x_min, x_max,
01012                      yPlane, yPlaneN, layer2Dtop ? zPlaneN : zPlane,
01013                      zPlaneN, 0, (zstate != AXE_DEPTH_DIR));
01014 
01015       // tick marks
01016       if (tick_along_z)
01017         {
01018           render_tickmarks (xticks, x_min, x_max, ypTick, ypTick,
01019                             zpTick, zpTickN, 0., 0.,
01020                             signum(zpTick-zpTickN)*fz*xticklen,
01021                             0, mirror);
01022         }
01023       else
01024         {
01025           render_tickmarks (xticks, x_min, x_max, ypTick, ypTickN,
01026                             zpTick, zpTick, 0.,
01027                             signum(ypTick-ypTickN)*fy*xticklen,
01028                             0., 0, mirror);
01029         }
01030 
01031       // tick texts
01032       if (xticklabels.numel () > 0)
01033         {
01034           int halign = (xstate == AXE_HORZ_DIR ? 1 : (xyzSym ? 0 : 2));
01035           int valign = (xstate == AXE_VERT_DIR ? 1 : (x2Dtop ? 0 : 2));
01036 
01037           if (tick_along_z)
01038             render_ticktexts (xticks, xticklabels, x_min, x_max, ypTick,
01039                               zpTick+signum(zpTick-zpTickN)*fz*xtickoffset,
01040                               0, halign, valign, wmax, hmax);
01041           else
01042             render_ticktexts (xticks, xticklabels, x_min, x_max,
01043                               ypTick+signum(ypTick-ypTickN)*fy*xtickoffset,
01044                               zpTick, 0, halign, valign, wmax, hmax);
01045         }
01046 
01047       // minor grid lines
01048       if (do_xminorgrid)
01049         render_grid (minorgridstyle, xmticks, x_min, x_max,
01050                      yPlane, yPlaneN, layer2Dtop ? zPlaneN : zPlane,
01051                      zPlaneN, 0, (zstate != AXE_DEPTH_DIR));
01052 
01053       // minor tick marks
01054       if (do_xminortick)
01055         {
01056           if (tick_along_z)
01057             render_tickmarks (xmticks, x_min, x_max, ypTick, ypTick,
01058                               zpTick, zpTickN, 0., 0.,
01059                               signum(zpTick-zpTickN)*fz*xticklen/2,
01060                               0, mirror);
01061           else
01062             render_tickmarks (xmticks, x_min, x_max, ypTick, ypTickN,
01063                               zpTick, zpTick, 0.,
01064                               signum(ypTick-ypTickN)*fy*xticklen/2,
01065                               0., 0, mirror);
01066         }
01067 
01068       gh_manager::get_object (props.get_xlabel ()).set ("visible", "on");
01069     }
01070   else
01071     gh_manager::get_object (props.get_xlabel ()).set ("visible", "off");
01072 }
01073 
01074 void
01075 opengl_renderer::draw_axes_y_grid (const axes::properties& props)
01076 {
01077   int ystate = props.get_ystate ();
01078   int zstate = props.get_zstate ();
01079   bool y2Dright = props.get_y2Dright ();
01080   bool layer2Dtop = props.get_layer2Dtop ();
01081   bool xyzSym = props.get_xyzSym ();
01082   bool nearhoriz = props.get_nearhoriz ();
01083   double yticklen = props.get_yticklen ();
01084   double ytickoffset = props.get_ytickoffset ();
01085   double fx = props.get_fx ();
01086   double fz = props.get_fz ();
01087   double xPlane = props.get_xPlane ();
01088   double xPlaneN = props.get_xPlaneN ();
01089   double xpTick = props.get_xpTick ();
01090   double xpTickN = props.get_xpTickN ();
01091   double y_min = props.get_y_min ();
01092   double y_max = props.get_y_max ();
01093   double zPlane = props.get_zPlane ();
01094   double zPlaneN = props.get_zPlaneN ();
01095   double zpTick = props.get_zpTick ();
01096   double zpTickN = props.get_zpTickN ();
01097 
01098   // Y grid
01099 
01100   if (ystate != AXE_DEPTH_DIR && props.is_visible ())
01101     {
01102       std::string gridstyle = props.get_gridlinestyle ();
01103       std::string minorgridstyle = props.get_minorgridlinestyle ();
01104       bool do_ygrid = (props.is_ygrid () && (gridstyle != "none"));
01105       bool do_yminorgrid = (props.is_yminorgrid () && (minorgridstyle != "none"));
01106       bool do_yminortick = props.is_yminortick ();
01107       Matrix yticks = xform.yscale (props.get_ytick ().matrix_value ());
01108       Matrix ymticks = xform.yscale (props.get_ymtick ().matrix_value ());
01109       string_vector yticklabels = props.get_yticklabel ().all_strings ();
01110       int wmax = 0, hmax = 0;
01111       bool tick_along_z = nearhoriz || xisinf (fx);
01112       bool mirror = props.is_box () && ystate != AXE_ANY_DIR
01113                     && (! props.has_property ("__plotyy_axes__"));
01114 
01115       set_color (props.get_ycolor_rgb ());
01116 
01117       // grid lines
01118       if (do_ygrid)
01119         render_grid (gridstyle, yticks, y_min, y_max,
01120                      xPlane, xPlaneN, layer2Dtop ? zPlaneN : zPlane,
01121                      zPlaneN, 1, (zstate != AXE_DEPTH_DIR));
01122 
01123       // tick marks
01124       if (tick_along_z)
01125         render_tickmarks (yticks, y_min, y_max, xpTick, xpTick,
01126                           zpTick, zpTickN, 0., 0.,
01127                           signum(zpTick-zpTickN)*fz*yticklen,
01128                           1, mirror);
01129       else
01130         render_tickmarks (yticks, y_min, y_max, xpTick, xpTickN,
01131                           zpTick, zpTick,
01132                           signum(xPlaneN-xPlane)*fx*yticklen,
01133                           0., 0., 1, mirror);
01134 
01135       // tick texts
01136       if (yticklabels.numel () > 0)
01137         {
01138           int halign = (ystate == AXE_HORZ_DIR
01139                         ? 1 : (!xyzSym || y2Dright ? 0 : 2));
01140           int valign = (ystate == AXE_VERT_DIR ? 1 : 2);
01141 
01142           if (tick_along_z)
01143             render_ticktexts (yticks, yticklabels, y_min, y_max, xpTick,
01144                               zpTick+signum(zpTick-zpTickN)*fz*ytickoffset,
01145                               1, halign, valign, wmax, hmax);
01146           else
01147             render_ticktexts (yticks, yticklabels, y_min, y_max,
01148                               xpTick+signum(xpTick-xpTickN)*fx*ytickoffset,
01149                               zpTick, 1, halign, valign, wmax, hmax);
01150         }
01151 
01152       // minor grid lines
01153       if (do_yminorgrid)
01154         render_grid (minorgridstyle, ymticks, y_min, y_max,
01155                      xPlane, xPlaneN, layer2Dtop ? zPlaneN : zPlane,
01156                      zPlaneN, 1, (zstate != AXE_DEPTH_DIR));
01157 
01158       // minor tick marks
01159       if (do_yminortick)
01160         {
01161           if (tick_along_z)
01162             render_tickmarks (ymticks, y_min, y_max, xpTick, xpTick,
01163                               zpTick, zpTickN, 0., 0.,
01164                               signum(zpTick-zpTickN)*fz*yticklen/2,
01165                               1, mirror);
01166           else
01167             render_tickmarks (ymticks, y_min, y_max, xpTick, xpTickN,
01168                               zpTick, zpTick,
01169                               signum(xpTick-xpTickN)*fx*yticklen/2,
01170                               0., 0., 1, mirror);
01171         }
01172 
01173       gh_manager::get_object (props.get_ylabel ()).set ("visible", "on");
01174     }
01175   else
01176     gh_manager::get_object (props.get_ylabel ()).set ("visible", "off");
01177 }
01178 
01179 void
01180 opengl_renderer::draw_axes_z_grid (const axes::properties& props)
01181 {
01182   int zstate = props.get_zstate ();
01183   bool xySym = props.get_xySym ();
01184   bool zSign = props.get_zSign ();
01185   double zticklen = props.get_zticklen ();
01186   double ztickoffset = props.get_ztickoffset ();
01187   double fx = props.get_fx ();
01188   double fy = props.get_fy ();
01189   double xPlane = props.get_xPlane ();
01190   double xPlaneN = props.get_xPlaneN ();
01191   double yPlane = props.get_yPlane ();
01192   double yPlaneN = props.get_yPlaneN ();
01193   double z_min = props.get_z_min ();
01194   double z_max = props.get_z_max ();
01195 
01196   // Z Grid
01197 
01198   if (zstate != AXE_DEPTH_DIR && props.is_visible ())
01199     {
01200       std::string gridstyle = props.get_gridlinestyle ();
01201       std::string minorgridstyle = props.get_minorgridlinestyle ();
01202       bool do_zgrid = (props.is_zgrid () && (gridstyle != "none"));
01203       bool do_zminorgrid = (props.is_zminorgrid () && (minorgridstyle != "none"));
01204       bool do_zminortick = props.is_zminortick ();
01205       Matrix zticks = xform.zscale (props.get_ztick ().matrix_value ());
01206       Matrix zmticks = xform.zscale (props.get_zmtick ().matrix_value ());
01207       string_vector zticklabels = props.get_zticklabel ().all_strings ();
01208       int wmax = 0, hmax = 0;
01209       bool mirror = props.is_box () && zstate != AXE_ANY_DIR;
01210 
01211       set_color (props.get_zcolor_rgb ());
01212 
01213       // grid lines
01214       if (do_zgrid)
01215         render_grid (gridstyle, zticks, z_min, z_max,
01216                      xPlane, xPlaneN, yPlane, yPlaneN, 2, true);
01217 
01218       // tick marks
01219       if (xySym)
01220         {
01221           if (xisinf (fy))
01222             render_tickmarks (zticks, z_min, z_max, xPlaneN, xPlane,
01223                               yPlane, yPlane,
01224                               signum(xPlaneN-xPlane)*fx*zticklen,
01225                               0., 0., 2, mirror);
01226           else
01227             render_tickmarks (zticks, z_min, z_max, xPlaneN, xPlaneN,
01228                               yPlane, yPlane, 0.,
01229                               signum(yPlane-yPlaneN)*fy*zticklen,
01230                               0., 2, false);
01231         }
01232       else
01233         {
01234           if (xisinf (fx))
01235             render_tickmarks (zticks, z_min, z_max, xPlaneN, xPlane,
01236                               yPlaneN, yPlane, 0.,
01237                               signum(yPlaneN-yPlane)*fy*zticklen,
01238                               0., 2, mirror);
01239           else
01240             render_tickmarks (zticks, z_min, z_max, xPlane, xPlane,
01241                               yPlaneN, yPlane,
01242                               signum(xPlane-xPlaneN)*fx*zticklen,
01243                               0., 0., 2, false);
01244         }
01245 
01246       // FIXME: tick texts
01247       if (zticklabels.numel () > 0)
01248         {
01249           int halign = 2;
01250           int valign = (zstate == AXE_VERT_DIR ? 1 : (zSign ? 3 : 2));
01251 
01252           if (xySym)
01253             {
01254               if (xisinf (fy))
01255                 render_ticktexts (zticks, zticklabels, z_min, z_max,
01256                                   xPlaneN+signum(xPlaneN-xPlane)*fx*ztickoffset,
01257                                   yPlane, 2, halign, valign, wmax, hmax);
01258               else
01259                 render_ticktexts (zticks, zticklabels, z_min, z_max, xPlaneN,
01260                                   yPlane+signum(yPlane-yPlaneN)*fy*ztickoffset,
01261                                   2, halign, valign, wmax, hmax);
01262             }
01263           else
01264             {
01265               if (xisinf (fx))
01266                 render_ticktexts (zticks, zticklabels, z_min, z_max, xPlane,
01267                                   yPlaneN+signum(yPlaneN-yPlane)*fy*ztickoffset,
01268                                   2, halign, valign, wmax, hmax);
01269               else
01270                 render_ticktexts (zticks, zticklabels, z_min, z_max,
01271                                   xPlane+signum(xPlane-xPlaneN)*fx*ztickoffset,
01272                                   yPlaneN, 2, halign, valign, wmax, hmax);
01273             }
01274         }
01275 
01276       // minor grid lines
01277       if (do_zminorgrid)
01278         render_grid (minorgridstyle, zmticks, z_min, z_max,
01279                      xPlane, xPlaneN, yPlane, yPlaneN, 2, true);
01280 
01281       // minor tick marks
01282       if (do_zminortick)
01283         {
01284           if (xySym)
01285             {
01286               if (xisinf (fy))
01287                 render_tickmarks (zmticks, z_min, z_max, xPlaneN, xPlane,
01288                                   yPlane, yPlane,
01289                                   signum(xPlaneN-xPlane)*fx*zticklen/2,
01290                                   0., 0., 2, mirror);
01291               else
01292                 render_tickmarks (zmticks, z_min, z_max, xPlaneN, xPlaneN,
01293                                   yPlane, yPlane, 0.,
01294                                   signum(yPlane-yPlaneN)*fy*zticklen/2,
01295                                   0., 2, false);
01296             }
01297           else
01298             {
01299               if (xisinf (fx))
01300                 render_tickmarks (zmticks, z_min, z_max, xPlane, xPlane,
01301                                   yPlaneN, yPlane, 0.,
01302                                   signum(yPlaneN-yPlane)*fy*zticklen/2,
01303                                   0., 2, mirror);
01304               else
01305                 render_tickmarks (zmticks, z_min, z_max, xPlane, xPlane,
01306                                   yPlaneN, yPlaneN,
01307                                   signum(xPlane-xPlaneN)*fx*zticklen/2,
01308                                   0., 0., 2, false);
01309             }
01310         }
01311 
01312       gh_manager::get_object (props.get_zlabel ()).set ("visible", "on");
01313     }
01314   else
01315     gh_manager::get_object (props.get_zlabel ()).set ("visible", "off");
01316 }
01317 
01318 void
01319 opengl_renderer::draw_axes_children (const axes::properties& props)
01320 {
01321   // Children
01322 
01323   GLboolean antialias;
01324   glGetBooleanv (GL_LINE_SMOOTH, &antialias);
01325 
01326   if (antialias == GL_TRUE)
01327     glEnable (GL_LINE_SMOOTH);
01328 
01329   Matrix children = props.get_all_children ();
01330   std::list<graphics_object> obj_list;
01331   std::list<graphics_object>::iterator it;
01332 
01333   // 1st pass: draw light objects
01334 
01335   // Start with the last element of the array of child objects to
01336   // display them in the oder they were added to the array.
01337 
01338   for (octave_idx_type i = children.numel () - 1; i >= 0; i--)
01339     {
01340       graphics_object go = gh_manager::get_object (children (i));
01341 
01342       if (go.get_properties ().is_visible ())
01343         {
01344           if (go.isa ("light"))
01345             draw (go);
01346           else
01347             obj_list.push_back (go);
01348         }
01349     }
01350 
01351   // 2nd pass: draw other objects (with units set to "data")
01352 
01353   it = obj_list.begin ();
01354   while (it != obj_list.end ())
01355     {
01356       graphics_object go = (*it);
01357 
01358       // FIXME: check whether object has "units" property and it is set
01359       // to "data"
01360       if (! go.isa ("text") || go.get ("units").string_value () == "data")
01361         {
01362           set_clipping (go.get_properties ().is_clipping ());
01363           draw (go);
01364 
01365           it = obj_list.erase (it);
01366         }
01367       else
01368         it++;
01369     }
01370 
01371   // 3rd pass: draw remaining objects
01372 
01373   glDisable (GL_DEPTH_TEST);
01374 
01375   for (it = obj_list.begin (); it != obj_list.end (); it++)
01376     {
01377       graphics_object go = (*it);
01378 
01379       set_clipping (go.get_properties ().is_clipping ());
01380       draw (go);
01381     }
01382 
01383   glEnable (GL_DEPTH_TEST);
01384 
01385   set_clipping (false);
01386 
01387   // FIXME: finalize rendering (transparency processing)
01388   // FIXME: draw zoom box, if needed
01389 }
01390 
01391 void
01392 opengl_renderer::draw_axes (const axes::properties& props)
01393 {
01394   double x_min = props.get_x_min ();
01395   double x_max = props.get_x_max ();
01396   double y_min = props.get_y_min ();
01397   double y_max = props.get_y_max ();
01398   double z_min = props.get_z_min ();
01399   double z_max = props.get_z_max ();
01400 
01401   setup_opengl_transformation (props);
01402 
01403   // draw axes object
01404 
01405   draw_axes_planes (props);
01406   draw_axes_boxes (props);
01407 
01408   set_font (props);
01409 
01410   draw_axes_x_grid (props);
01411   draw_axes_y_grid (props);
01412   draw_axes_z_grid (props);
01413 
01414   set_linestyle ("-");
01415 
01416   set_clipbox (x_min, x_max, y_min, y_max, z_min, z_max);
01417 
01418   draw_axes_children (props);
01419 }
01420 
01421 void
01422 opengl_renderer::draw_line (const line::properties& props)
01423 {
01424   Matrix x = xform.xscale (props.get_xdata ().matrix_value ());
01425   Matrix y = xform.yscale (props.get_ydata ().matrix_value ());
01426   Matrix z = xform.zscale (props.get_zdata ().matrix_value ());
01427 
01428   bool has_z = (z.numel () > 0);
01429   int n = static_cast<int> (::xmin (::xmin (x.numel (), y.numel ()), (has_z ? z.numel () : INT_MAX)));
01430   octave_uint8 clip_mask = (props.is_clipping () ? 0x7F : 0x40), clip_ok (0x40);
01431 
01432   std::vector<octave_uint8> clip (n);
01433 
01434   if (has_z)
01435     for (int i = 0; i < n; i++)
01436       clip[i] = (clip_code (x(i), y(i), z(i)) & clip_mask);
01437   else
01438     {
01439       double z_mid = (zmin+zmax)/2;
01440 
01441       for (int i = 0; i < n; i++)
01442         clip[i] = (clip_code (x(i), y(i), z_mid) & clip_mask);
01443     }
01444 
01445   if (! props.linestyle_is ("none"))
01446     {
01447       set_color (props.get_color_rgb ());
01448       set_linestyle (props.get_linestyle (), false);
01449       set_linewidth (props.get_linewidth ());
01450 
01451       if (has_z)
01452         {
01453           bool flag = false;
01454 
01455           for (int i = 1; i < n; i++)
01456             {
01457               if ((clip[i-1] & clip[i]) == clip_ok)
01458                 {
01459                   if (! flag)
01460                     {
01461                       flag = true;
01462                       glBegin (GL_LINE_STRIP);
01463                       glVertex3d (x(i-1), y(i-1), z(i-1));
01464                     }
01465                   glVertex3d (x(i), y(i), z(i));
01466                 }
01467               else if (flag)
01468                 {
01469                   flag = false;
01470                   glEnd ();
01471                 }
01472             }
01473 
01474           if (flag)
01475             glEnd ();
01476         }
01477       else
01478         {
01479           bool flag = false;
01480 
01481           for (int i = 1; i < n; i++)
01482             {
01483               if ((clip[i-1] & clip[i]) == clip_ok)
01484                 {
01485                   if (! flag)
01486                     {
01487                       flag = true;
01488                       glBegin (GL_LINE_STRIP);
01489                       glVertex2d (x(i-1), y(i-1));
01490                     }
01491                   glVertex2d (x(i), y(i));
01492                 }
01493               else if (flag)
01494                 {
01495                   flag = false;
01496                   glEnd ();
01497                 }
01498             }
01499 
01500           if (flag)
01501             glEnd ();
01502         }
01503 
01504       set_linewidth (0.5);
01505       set_linestyle ("-");
01506     }
01507 
01508   set_clipping (false);
01509 
01510   if (! props.marker_is ("none") &&
01511       ! (props.markeredgecolor_is ("none")
01512          && props.markerfacecolor_is ("none")))
01513     {
01514       Matrix lc, fc;
01515 
01516       if (props.markeredgecolor_is ("auto"))
01517         lc = props.get_color_rgb ();
01518       else if (! props.markeredgecolor_is ("none"))
01519         lc = props.get_markeredgecolor_rgb ();
01520 
01521       if (props.markerfacecolor_is ("auto"))
01522         fc = props.get_color_rgb ();
01523       else if (! props.markerfacecolor_is ("none"))
01524         fc = props.get_markerfacecolor_rgb ();
01525 
01526       init_marker (props.get_marker (), props.get_markersize (),
01527                    props.get_linewidth ());
01528 
01529       for (int i = 0; i < n; i++)
01530         {
01531           if (clip[i] == clip_ok)
01532             draw_marker (x(i), y(i),
01533                          has_z ? z(i) : static_cast<double> (i) / n,
01534                          lc, fc);
01535         }
01536 
01537       end_marker ();
01538     }
01539 
01540   set_clipping (props.is_clipping ());
01541 }
01542 
01543 void
01544 opengl_renderer::draw_surface (const surface::properties& props)
01545 {
01546   const Matrix x = xform.xscale (props.get_xdata ().matrix_value ());
01547   const Matrix y = xform.yscale (props.get_ydata ().matrix_value ());
01548   const Matrix z = xform.zscale (props.get_zdata ().matrix_value ());
01549 
01550   int zr = z.rows (), zc = z.columns ();
01551 
01552   NDArray c;
01553   const NDArray n = props.get_vertexnormals ().array_value ();
01554 
01555   // FIXME: handle transparency
01556   Matrix a;
01557 
01558   if (props.facelighting_is ("phong") || props.edgelighting_is ("phong"))
01559     warning ("opengl_renderer::draw: phong light model not supported");
01560 
01561   int fc_mode = (props.facecolor_is_rgb () ? 0 :
01562                  (props.facecolor_is ("flat") ? 1 :
01563                   (props.facecolor_is ("interp") ? 2 :
01564                    (props.facecolor_is ("texturemap") ? 3 : -1))));
01565   int fl_mode = (props.facelighting_is ("none") ? 0 :
01566                  (props.facelighting_is ("flat") ? 1 : 2));
01567   int fa_mode = (props.facealpha_is_double () ? 0 :
01568                  (props.facealpha_is ("flat") ? 1 : 2));
01569   int ec_mode = (props.edgecolor_is_rgb () ? 0 :
01570                  (props.edgecolor_is ("flat") ? 1 :
01571                   (props.edgecolor_is ("interp") ? 2 : -1)));
01572   int el_mode = (props.edgelighting_is ("none") ? 0 :
01573                  (props.edgelighting_is ("flat") ? 1 : 2));
01574   int ea_mode = (props.edgealpha_is_double () ? 0 :
01575                  (props.edgealpha_is ("flat") ? 1 : 2));
01576 
01577   Matrix fcolor = (fc_mode == 3 ? Matrix (1, 3, 1.0) : props.get_facecolor_rgb ());
01578   Matrix ecolor = props.get_edgecolor_rgb ();
01579 
01580   float as = props.get_ambientstrength ();
01581   float ds = props.get_diffusestrength ();
01582   float ss = props.get_specularstrength ();
01583   float se = props.get_specularexponent ();
01584   float cb[4] = { 0.0, 0.0, 0.0, 1.0 };
01585   double d = 1.0;
01586 
01587   opengl_texture tex;
01588 
01589   int i1, i2, j1, j2;
01590   bool x_mat = (x.rows () == z.rows ());
01591   bool y_mat = (y.columns () == z.columns ());
01592 
01593   i1 = i2 = j1 = j2 = 0;
01594 
01595   boolMatrix clip (z.dims (), false);
01596 
01597   for (int i = 0; i < zr; i++)
01598     {
01599       if (x_mat)
01600         i1 = i;
01601 
01602       for (int j = 0; j < zc; j++)
01603         {
01604           if (y_mat)
01605             j1 = j;
01606 
01607           clip(i,j) = is_nan_or_inf (x(i1,j), y(i,j1), z(i,j));
01608         }
01609     }
01610 
01611   if ((fc_mode > 0 && fc_mode < 3) || ec_mode > 0)
01612     c = props.get_color_data ().array_value ();
01613 
01614   if (fa_mode > 0 || ea_mode > 0)
01615     {
01616       // FIXME: implement alphadata conversion
01617       //a = props.get_alpha_data ();
01618     }
01619 
01620   if (fl_mode > 0 || el_mode > 0)
01621     {
01622       float buf[4] = { ss, ss, ss, 1 };
01623 
01624       glMaterialfv (LIGHT_MODE, GL_SPECULAR, buf);
01625       glMaterialf (LIGHT_MODE, GL_SHININESS, se);
01626     }
01627 
01628   // FIXME: good candidate for caching, transfering pixel
01629   // data to OpenGL is time consuming.
01630   if (fc_mode == 3)
01631     tex = opengl_texture::create (props.get_color_data ());
01632 
01633   if (! props.facecolor_is ("none"))
01634     {
01635       if (props.get_facealpha_double () == 1)
01636         {
01637           if (fc_mode == 0 || fc_mode == 3)
01638             {
01639               glColor3dv (fcolor.data ());
01640               if (fl_mode > 0)
01641                 {
01642                   for (int i = 0; i < 3; i++)
01643                     cb[i] = as * fcolor(i);
01644                   glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
01645 
01646                   for (int i = 0; i < 3; i++)
01647                     cb[i] = ds * fcolor(i);
01648                   glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
01649                 }
01650             }
01651 
01652           if (fl_mode > 0)
01653             glEnable (GL_LIGHTING);
01654           glShadeModel ((fc_mode == 2 || fl_mode == 2) ? GL_SMOOTH : GL_FLAT);
01655           set_polygon_offset (true, 1);
01656           if (fc_mode == 3)
01657             glEnable (GL_TEXTURE_2D);
01658 
01659           for (int i = 1; i < zc; i++)
01660             {
01661               if (y_mat)
01662                 {
01663                   i1 = i-1;
01664                   i2 = i;
01665                 }
01666 
01667               for (int j = 1; j < zr; j++)
01668                 {
01669                   if (clip(j-1, i-1) || clip (j, i-1)
01670                       || clip (j-1, i) || clip (j, i))
01671                     continue;
01672 
01673                   if (x_mat)
01674                     {
01675                       j1 = j-1;
01676                       j2 = j;
01677                     }
01678 
01679                   glBegin (GL_QUADS);
01680 
01681                   // Vertex 1
01682                   if (fc_mode == 3)
01683                     tex.tex_coord (double (i-1) / (zc-1), double (j-1) / (zr-1));
01684                   else if (fc_mode > 0)
01685                     {
01686                       // FIXME: is there a smarter way to do this?
01687                       for (int k = 0; k < 3; k++)
01688                         cb[k] = c(j-1, i-1, k);
01689                       glColor3fv (cb);
01690 
01691                       if (fl_mode > 0)
01692                         {
01693                           for (int k = 0; k < 3; k++)
01694                             cb[k] *= as;
01695                           glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
01696 
01697                           for (int k = 0; k < 3; k++)
01698                             cb[k] = ds * c(j-1, i-1, k);
01699                           glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
01700                         }
01701                     }
01702                   if (fl_mode > 0)
01703                     {
01704                       d = sqrt (n(j-1,i-1,0) * n(j-1,i-1,0)
01705                                 + n(j-1,i-1,1) * n(j-1,i-1,1)
01706                                 + n(j-1,i-1,2) * n(j-1,i-1,2));
01707                       glNormal3d (n(j-1,i-1,0)/d, n(j-1,i-1,1)/d, n(j-1,i-1,2)/d);
01708                     }
01709                   glVertex3d (x(j1,i-1), y(j-1,i1), z(j-1,i-1));
01710 
01711                   // Vertex 2
01712                   if (fc_mode == 3)
01713                     tex.tex_coord (double (i) / (zc-1), double (j-1) / (zr-1));
01714                   else if (fc_mode == 2)
01715                     {
01716                       for (int k = 0; k < 3; k++)
01717                         cb[k] = c(j-1, i, k);
01718                       glColor3fv (cb);
01719 
01720                       if (fl_mode > 0)
01721                         {
01722                           for (int k = 0; k < 3; k++)
01723                             cb[k] *= as;
01724                           glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
01725 
01726                           for (int k = 0; k < 3; k++)
01727                             cb[k] = ds * c(j-1, i, k);
01728                           glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
01729                         }
01730                     }
01731 
01732                   if (fl_mode == 2)
01733                     {
01734                       d = sqrt (n(j-1,i,0) * n(j-1,i,0)
01735                                 + n(j-1,i,1) * n(j-1,i,1)
01736                                 + n(j-1,i,2) * n(j-1,i,2));
01737                       glNormal3d (n(j-1,i,0)/d, n(j-1,i,1)/d, n(j-1,i,2)/d);
01738                     }
01739 
01740                   glVertex3d (x(j1,i), y(j-1,i2), z(j-1,i));
01741 
01742                   // Vertex 3
01743                   if (fc_mode == 3)
01744                     tex.tex_coord (double (i) / (zc-1), double (j) / (zr-1));
01745                   else if (fc_mode == 2)
01746                     {
01747                       for (int k = 0; k < 3; k++)
01748                         cb[k] = c(j, i, k);
01749                       glColor3fv (cb);
01750 
01751                       if (fl_mode > 0)
01752                         {
01753                           for (int k = 0; k < 3; k++)
01754                             cb[k] *= as;
01755                           glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
01756 
01757                           for (int k = 0; k < 3; k++)
01758                             cb[k] = ds * c(j, i, k);
01759                           glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
01760                         }
01761                     }
01762                   if (fl_mode == 2)
01763                     {
01764                       d = sqrt (n(j,i,0) * n(j,i,0)
01765                                 + n(j,i,1) * n(j,i,1)
01766                                 + n(j,i,2) * n(j,i,2));
01767                       glNormal3d (n(j,i,0)/d, n(j,i,1)/d, n(j,i,2)/d);
01768                     }
01769                   glVertex3d (x(j2,i), y(j,i2), z(j,i));
01770 
01771                   // Vertex 4
01772                   if (fc_mode == 3)
01773                     tex.tex_coord (double (i-1) / (zc-1), double (j) / (zr-1));
01774                   else if (fc_mode == 2)
01775                     {
01776                       for (int k = 0; k < 3; k++)
01777                         cb[k] = c(j, i-1, k);
01778                       glColor3fv (cb);
01779 
01780                       if (fl_mode > 0)
01781                         {
01782                           for (int k = 0; k < 3; k++)
01783                             cb[k] *= as;
01784                           glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
01785 
01786                           for (int k = 0; k < 3; k++)
01787                             cb[k] = ds * c(j, i-1, k);
01788                           glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
01789                         }
01790                     }
01791                   if (fl_mode == 2)
01792                     {
01793                       d = sqrt (n(j,i-1,0) * n(j,i-1,0)
01794                                 + n(j,i-1,1) * n(j,i-1,1)
01795                                 + n(j,i-1,2) * n(j,i-1,2));
01796                       glNormal3d (n(j,i-1,0)/d, n(j,i-1,1)/d, n(j,i-1,2)/d);
01797                     }
01798                   glVertex3d (x(j2,i-1), y(j,i1), z(j,i-1));
01799 
01800                   glEnd ();
01801                 }
01802             }
01803 
01804           set_polygon_offset (false);
01805           if (fc_mode == 3)
01806             glDisable (GL_TEXTURE_2D);
01807 
01808           if (fl_mode > 0)
01809             glDisable (GL_LIGHTING);
01810         }
01811       else
01812         {
01813           // FIXME: implement transparency
01814         }
01815     }
01816 
01817   if (! props.edgecolor_is ("none"))
01818     {
01819       if (props.get_edgealpha_double () == 1)
01820         {
01821           if (ec_mode == 0)
01822             {
01823               glColor3dv (ecolor.data ());
01824               if (fl_mode > 0)
01825                 {
01826                   for (int i = 0; i < 3; i++)
01827                     cb[i] = as * ecolor(i);
01828                   glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
01829 
01830                   for (int i = 0; i < 3; i++)
01831                     cb[i] = ds * ecolor(i);
01832                   glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
01833                 }
01834             }
01835 
01836           if (el_mode > 0)
01837             glEnable (GL_LIGHTING);
01838           glShadeModel ((ec_mode == 2 || el_mode == 2) ? GL_SMOOTH : GL_FLAT);
01839 
01840           set_linestyle (props.get_linestyle (), false);
01841           set_linewidth (props.get_linewidth ());
01842 
01843           // Mesh along Y-axis
01844 
01845           if (props.meshstyle_is ("both") || props.meshstyle_is ("column"))
01846             {
01847               for (int i = 0; i < zc; i++)
01848                 {
01849                   if (y_mat)
01850                     {
01851                       i1 = i-1;
01852                       i2 = i;
01853                     }
01854 
01855                   for (int j = 1; j < zr; j++)
01856                     {
01857                       if (clip(j-1,i) || clip(j,i))
01858                         continue;
01859 
01860                       if (x_mat)
01861                         {
01862                           j1 = j-1;
01863                           j2 = j;
01864                         }
01865 
01866                       glBegin (GL_LINES);
01867 
01868                       // Vertex 1
01869                       if (ec_mode > 0)
01870                         {
01871                           for (int k = 0; k < 3; k++)
01872                             cb[k] = c(j-1, i, k);
01873                           glColor3fv (cb);
01874 
01875                           if (fl_mode > 0)
01876                             {
01877                               for (int k = 0; k < 3; k++)
01878                                 cb[k] *= as;
01879                               glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
01880 
01881                               for (int k = 0; k < 3; k++)
01882                                 cb[k] = ds * c(j-1, i, k);
01883                               glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
01884                             }
01885                         }
01886                       if (el_mode > 0)
01887                         {
01888                           d = sqrt (n(j-1,i,0) * n(j-1,i,0)
01889                                     + n(j-1,i,1) * n(j-1,i,1)
01890                                     + n(j-1,i,2) * n(j-1,i,2));
01891                           glNormal3d (n(j-1,i,0)/d, n(j-1,i,1)/d, n(j-1,i,2)/d);
01892                         }
01893                       glVertex3d (x(j1,i), y(j-1,i2), z(j-1,i));
01894 
01895                       // Vertex 2
01896                       if (ec_mode == 2)
01897                         {
01898                           for (int k = 0; k < 3; k++)
01899                             cb[k] = c(j, i, k);
01900                           glColor3fv (cb);
01901 
01902                           if (fl_mode > 0)
01903                             {
01904                               for (int k = 0; k < 3; k++)
01905                                 cb[k] *= as;
01906                               glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
01907 
01908                               for (int k = 0; k < 3; k++)
01909                                 cb[k] = ds * c(j, i, k);
01910                               glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
01911                             }
01912                         }
01913                       if (el_mode == 2)
01914                         {
01915                           d = sqrt (n(j,i,0) * n(j,i,0)
01916                                     + n(j,i,1) * n(j,i,1)
01917                                     + n(j,i,2) * n(j,i,2));
01918                           glNormal3d (n(j,i,0)/d, n(j,i,1)/d, n(j,i,2)/d);
01919                         }
01920                       glVertex3d (x(j2,i), y(j,i2), z(j,i));
01921 
01922                       glEnd ();
01923                     }
01924                 }
01925             }
01926 
01927           // Mesh along X-axis
01928 
01929           if (props.meshstyle_is ("both") || props.meshstyle_is ("row"))
01930             {
01931               for (int j = 0; j < zr; j++)
01932                 {
01933                   if (x_mat)
01934                     {
01935                       j1 = j-1;
01936                       j2 = j;
01937                     }
01938 
01939                   for (int i = 1; i < zc; i++)
01940                     {
01941                       if (clip(j,i-1) || clip(j,i))
01942                         continue;
01943 
01944                       if (y_mat)
01945                         {
01946                           i1 = i-1;
01947                           i2 = i;
01948                         }
01949 
01950                       glBegin (GL_LINES);
01951 
01952                       // Vertex 1
01953                       if (ec_mode > 0)
01954                         {
01955                           for (int k = 0; k < 3; k++)
01956                             cb[k] = c(j, i-1, k);
01957                           glColor3fv (cb);
01958 
01959                           if (fl_mode > 0)
01960                             {
01961                               for (int k = 0; k < 3; k++)
01962                                 cb[k] *= as;
01963                               glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
01964 
01965                               for (int k = 0; k < 3; k++)
01966                                 cb[k] = ds * c(j, i-1, k);
01967                               glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
01968                             }
01969                         }
01970                       if (el_mode > 0)
01971                         {
01972                           d = sqrt (n(j,i-1,0) * n(j,i-1,0)
01973                                     + n(j,i-1,1) * n(j,i-1,1)
01974                                     + n(j,i-1,2) * n(j,i-1,2));
01975                           glNormal3d (n(j,i-1,0)/d, n(j,i-1,1)/d, n(j,i-1,2)/d);
01976                         }
01977                       glVertex3d (x(j2,i-1), y(j,i1), z(j,i-1));
01978 
01979                       // Vertex 2
01980                       if (ec_mode == 2)
01981                         {
01982                           for (int k = 0; k < 3; k++)
01983                             cb[k] = c(j, i, k);
01984                           glColor3fv (cb);
01985 
01986                           if (fl_mode > 0)
01987                             {
01988                               for (int k = 0; k < 3; k++)
01989                                 cb[k] *= as;
01990                               glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
01991 
01992                               for (int k = 0; k < 3; k++)
01993                                 cb[k] = ds * c(j, i, k);
01994                               glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
01995                             }
01996                         }
01997                       if (el_mode == 2)
01998                         {
01999                           d = sqrt (n(j,i,0) * n(j,i,0)
02000                                     + n(j,i,1) * n(j,i,1)
02001                                     + n(j,i,2) * n(j,i,2));
02002                           glNormal3d (n(j,i,0)/d, n(j,i,1)/d, n(j,i,2)/d);
02003                         }
02004                       glVertex3d (x(j2,i), y(j,i2), z(j,i));
02005 
02006                       glEnd ();
02007                     }
02008                 }
02009             }
02010 
02011           set_linestyle ("-");
02012           set_linewidth (0.5);
02013 
02014           if (el_mode > 0)
02015             glDisable (GL_LIGHTING);
02016         }
02017       else
02018         {
02019           // FIXME: implement transparency
02020         }
02021     }
02022 
02023   if (! props.marker_is ("none") &&
02024       ! (props.markeredgecolor_is ("none")
02025          && props.markerfacecolor_is ("none")))
02026     {
02027       // FIXME: check how transparency should be handled in markers
02028       // FIXME: check what to do with marker facecolor set to auto
02029       //        and facecolor set to none.
02030 
02031       bool do_edge = ! props.markeredgecolor_is ("none");
02032       bool do_face = ! props.markerfacecolor_is ("none");
02033 
02034       Matrix mecolor = props.get_markeredgecolor_rgb ();
02035       Matrix mfcolor = props.get_markerfacecolor_rgb ();
02036       Matrix cc (1, 3, 0.0);
02037 
02038       if (mecolor.numel () == 0 && props.markeredgecolor_is ("auto"))
02039         {
02040           mecolor = props.get_edgecolor_rgb ();
02041           do_edge = ! props.edgecolor_is ("none");
02042         }
02043 
02044       if (mfcolor.numel () == 0 && props.markerfacecolor_is ("auto"))
02045         {
02046           mfcolor = props.get_facecolor_rgb ();
02047           do_face = ! props.facecolor_is ("none");
02048         }
02049 
02050       if ((mecolor.numel () == 0 || mfcolor.numel () == 0)
02051           && c.numel () == 0)
02052         c = props.get_color_data ().array_value ();
02053 
02054       init_marker (props.get_marker (), props.get_markersize (),
02055                    props.get_linewidth ());
02056 
02057       for (int i = 0; i < zc; i++)
02058         {
02059           if (y_mat)
02060             i1 = i;
02061 
02062           for (int j = 0; j < zr; j++)
02063             {
02064               if (clip(j,i))
02065                 continue;
02066 
02067               if (x_mat)
02068                 j1 = j;
02069 
02070               if ((do_edge && mecolor.numel () == 0)
02071                   || (do_face && mfcolor.numel () == 0))
02072                 {
02073                   for (int k = 0; k < 3; k++)
02074                     cc(k) = c(j,i,k);
02075                 }
02076 
02077               Matrix lc = (do_edge ? (mecolor.numel () == 0 ? cc : mecolor) : Matrix ());
02078               Matrix fc = (do_face ? (mfcolor.numel () == 0 ? cc : mfcolor) : Matrix ());
02079 
02080               draw_marker (x(j1,i), y(j,i1), z(j,i), lc, fc);
02081             }
02082         }
02083 
02084       end_marker ();
02085     }
02086 }
02087 
02088 // FIXME: global optimization (rendering, data structures...), there
02089 // is probably a smarter/faster/less-memory-consuming way to do this.
02090 void
02091 opengl_renderer::draw_patch (const patch::properties &props)
02092 {
02093   const Matrix f = props.get_faces ().matrix_value ();
02094   const Matrix v = xform.scale (props.get_vertices ().matrix_value ());
02095   Matrix c;
02096   const Matrix n = props.get_vertexnormals ().matrix_value ();
02097   Matrix a;
02098 
02099   int nv = v.rows ();
02100   // int vmax = v.columns ();
02101   int nf = f.rows ();
02102   int fcmax = f.columns ();
02103 
02104   bool has_z = (v.columns () > 2);
02105   bool has_facecolor = false;
02106   bool has_facealpha = false;
02107 
02108   int fc_mode = ((props.facecolor_is("none")
02109                   || props.facecolor_is_rgb ()) ? 0 :
02110                  (props.facecolor_is("flat") ? 1 : 2));
02111   int fl_mode = (props.facelighting_is ("none") ? 0 :
02112                  (props.facelighting_is ("flat") ? 1 : 2));
02113   int fa_mode = (props.facealpha_is_double () ? 0 :
02114                  (props.facealpha_is ("flat") ? 1 : 2));
02115   int ec_mode = ((props.edgecolor_is("none")
02116                   || props.edgecolor_is_rgb ()) ? 0 :
02117                  (props.edgecolor_is("flat") ? 1 : 2));
02118   int el_mode = (props.edgelighting_is ("none") ? 0 :
02119                  (props.edgelighting_is ("flat") ? 1 : 2));
02120   int ea_mode = (props.edgealpha_is_double () ? 0 :
02121                  (props.edgealpha_is ("flat") ? 1 : 2));
02122 
02123   Matrix fcolor = props.get_facecolor_rgb ();
02124   Matrix ecolor = props.get_edgecolor_rgb ();
02125 
02126   float as = props.get_ambientstrength ();
02127   float ds = props.get_diffusestrength ();
02128   float ss = props.get_specularstrength ();
02129   float se = props.get_specularexponent ();
02130 
02131   boolMatrix clip (1, nv, false);
02132 
02133   if (has_z)
02134     for (int i = 0; i < nv; i++)
02135       clip(i) = is_nan_or_inf (v(i,0), v(i,1), v(i,2));
02136   else
02137     for (int i = 0; i < nv; i++)
02138       clip(i) = is_nan_or_inf (v(i,0), v(i,1), 0);
02139 
02140   boolMatrix clip_f (1, nf, false);
02141   Array<int> count_f (dim_vector (nf, 1), 0);
02142 
02143   for (int i = 0; i < nf; i++)
02144     {
02145       bool fclip = false;
02146       int count = 0;
02147 
02148       for (int j = 0; j < fcmax && ! xisnan (f(i,j)); j++, count++)
02149         fclip = (fclip || clip(int (f(i,j) - 1)));
02150 
02151       clip_f(i) = fclip;
02152       count_f(i) = count;
02153     }
02154 
02155   if (fc_mode > 0 || ec_mode > 0)
02156     {
02157       c = props.get_color_data ().matrix_value ();
02158 
02159       if (c.rows () == 1)
02160         {
02161           // Single color specifications, we can simplify a little bit
02162 
02163           if (fc_mode > 0)
02164             {
02165               fcolor = c;
02166               fc_mode = 0;
02167             }
02168 
02169           if (ec_mode > 0)
02170             {
02171               ecolor = c;
02172               ec_mode = 0;
02173             }
02174 
02175           c = Matrix ();
02176         }
02177       else
02178         has_facecolor = ((c.numel () > 0) && (c.rows () == f.rows ()));
02179     }
02180 
02181   if (fa_mode > 0 || ea_mode > 0)
02182     {
02183       // FIXME: retrieve alpha data from patch object
02184       //a = props.get_alpha_data ();
02185       has_facealpha = ((a.numel () > 0) && (a.rows () == f.rows ()));
02186     }
02187 
02188   octave_idx_type fr = f.rows ();
02189   std::vector<vertex_data> vdata (f.numel ());
02190 
02191   for (int i = 0; i < nf; i++)
02192     for (int j = 0; j < count_f(i); j++)
02193       {
02194         int idx = int (f(i,j) - 1);
02195 
02196         Matrix vv (1, 3, 0.0);
02197         Matrix cc;
02198         Matrix nn(1, 3, 0.0);
02199         double aa = 1.0;
02200 
02201         vv(0) = v(idx,0); vv(1) = v(idx,1);
02202         if (has_z)
02203           vv(2) = v(idx,2);
02204         // FIXME: uncomment when patch object has normal computation
02205         //nn(0) = n(idx,0); nn(1) = n(idx,1); nn(2) = n(idx,2);
02206         if (c.numel () > 0)
02207           {
02208             cc.resize (1, 3);
02209             if (has_facecolor)
02210               cc(0) = c(i,0), cc(1) = c(i,1), cc(2) = c(i,2);
02211             else
02212               cc(0) = c(idx,0), cc(1) = c(idx,1), cc(2) = c(idx,2);
02213           }
02214         if (a.numel () > 0)
02215           {
02216             if (has_facealpha)
02217               aa = a(i);
02218             else
02219               aa = a(idx);
02220           }
02221 
02222         vdata[i+j*fr] =
02223             vertex_data (vv, cc, nn, aa, as, ds, ss, se);
02224       }
02225 
02226   if (fl_mode > 0 || el_mode > 0)
02227     {
02228       float buf[4] = { ss, ss, ss, 1 };
02229 
02230       glMaterialfv (LIGHT_MODE, GL_SPECULAR, buf);
02231       glMaterialf (LIGHT_MODE, GL_SHININESS, se);
02232     }
02233 
02234   if (! props.facecolor_is ("none"))
02235     {
02236       // FIXME: adapt to double-radio property
02237       if (props.get_facealpha_double () == 1)
02238         {
02239           if (fc_mode == 0)
02240             {
02241               glColor3dv (fcolor.data ());
02242               if (fl_mode > 0)
02243                 {
02244                   float cb[4] = { 0, 0, 0, 1 };
02245 
02246                   for (int i = 0; i < 3; i++)
02247                     cb[i] = (as * fcolor(i));
02248                   glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
02249 
02250                   for (int i = 0; i < 3; i++)
02251                     cb[i] = ds * fcolor(i);
02252                   glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
02253                 }
02254             }
02255 
02256           if (fl_mode > 0)
02257             glEnable (GL_LIGHTING);
02258 
02259           // FIXME: use __index__ property from patch object
02260           patch_tesselator tess (this, fc_mode, fl_mode, 0);
02261 
02262           for (int i = 0; i < nf; i++)
02263             {
02264               if (clip_f(i))
02265                 continue;
02266 
02267               tess.begin_polygon (true);
02268               tess.begin_contour ();
02269 
02270               for (int j = 0; j < count_f(i); j++)
02271                 {
02272                   vertex_data::vertex_data_rep *vv = vdata[i+j*fr].get_rep ();
02273 
02274                   tess.add_vertex (vv->coords.fortran_vec (), vv);
02275                 }
02276 
02277               tess.end_contour ();
02278               tess.end_polygon ();
02279             }
02280 
02281           if (fl_mode > 0)
02282             glDisable (GL_LIGHTING);
02283         }
02284       else
02285         {
02286           // FIXME: implement transparency
02287         }
02288     }
02289 
02290   if (! props.edgecolor_is ("none"))
02291     {
02292       // FIXME: adapt to double-radio property
02293       if (props.get_edgealpha_double () == 1)
02294         {
02295           if (ec_mode == 0)
02296             {
02297               glColor3dv (ecolor.data ());
02298               if (el_mode > 0)
02299                 {
02300                   float cb[4] = { 0, 0, 0, 1 };
02301 
02302                   for (int i = 0; i < 3; i++)
02303                     cb[i] = (as * ecolor(i));
02304                   glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb);
02305 
02306                   for (int i = 0; i < 3; i++)
02307                     cb[i] = ds * ecolor(i);
02308                   glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb);
02309                 }
02310             }
02311 
02312           if (el_mode > 0)
02313             glEnable (GL_LIGHTING);
02314 
02315           set_linestyle (props.get_linestyle (), false);
02316           set_linewidth (props.get_linewidth ());
02317 
02318 
02319           // FIXME: use __index__ property from patch object; should we
02320           // offset patch contour as well?
02321           patch_tesselator tess (this, ec_mode, el_mode);
02322 
02323           for (int i = 0; i < nf; i++)
02324             {
02325               if (clip_f(i))
02326                 {
02327                   // This is an unclosed contour. Draw it as a line
02328                   bool flag = false;
02329 
02330                   for (int j = 0; j < count_f(i); j++)
02331                     {
02332                       if (! clip(int (f(i,j) - 1)))
02333                         {
02334                           vertex_data::vertex_data_rep *vv = vdata[i+j*fr].get_rep ();
02335                           const Matrix m = vv->coords;
02336                           if (! flag)
02337                             {
02338                               flag = true;
02339                               glBegin (GL_LINE_STRIP);
02340                             }
02341                           glVertex3d (m(0), m(1), m(2));
02342                         }
02343                       else if (flag)
02344                         {
02345                           flag = false;
02346                           glEnd ();
02347                         }
02348                     }
02349 
02350                   if (flag)
02351                     glEnd ();
02352                 }
02353               else
02354                 {
02355                   tess.begin_polygon (false);
02356                   tess.begin_contour ();
02357 
02358                   for (int j = 0; j < count_f(i); j++)
02359                     {
02360                       vertex_data::vertex_data_rep *vv = vdata[i+j*fr].get_rep ();
02361                       tess.add_vertex (vv->coords.fortran_vec (), vv);
02362                     }
02363 
02364                   tess.end_contour ();
02365                   tess.end_polygon ();
02366                 }
02367             }
02368 
02369           set_linestyle ("-");
02370           set_linewidth (0.5);
02371 
02372           if (el_mode > 0)
02373             glDisable (GL_LIGHTING);
02374         }
02375       else
02376         {
02377           // FIXME: implement transparency
02378         }
02379     }
02380 
02381   if (! props.marker_is ("none") &&
02382       ! (props.markeredgecolor_is ("none") && props.markerfacecolor_is ("none")))
02383     {
02384       bool do_edge = ! props.markeredgecolor_is ("none");
02385       bool do_face = ! props.markerfacecolor_is ("none");
02386 
02387       Matrix mecolor = props.get_markeredgecolor_rgb ();
02388       Matrix mfcolor = props.get_markerfacecolor_rgb ();
02389 
02390       bool has_markerfacecolor = false;
02391 
02392       if ((mecolor.numel () == 0 && ! props.markeredgecolor_is ("none"))
02393           || (mfcolor.numel () == 0 && ! props.markerfacecolor_is ("none")))
02394         {
02395           Matrix mc = props.get_color_data ().matrix_value ();
02396 
02397           if (mc.rows () == 1)
02398             {
02399               // Single color specifications, we can simplify a little bit
02400 
02401               if (mfcolor.numel () == 0
02402                    && ! props.markerfacecolor_is ("none"))
02403                 mfcolor = mc;
02404 
02405               if (mecolor.numel () == 0
02406                    && ! props.markeredgecolor_is ("none"))
02407                 mecolor = mc;
02408             }
02409           else
02410             {
02411               if (c.numel () == 0)
02412                 c = props.get_color_data ().matrix_value ();
02413               has_markerfacecolor = ((c.numel () > 0)
02414                                     && (c.rows () == f.rows ()));
02415             }
02416         }
02417 
02418 
02419       init_marker (props.get_marker (), props.get_markersize (),
02420                    props.get_linewidth ());
02421 
02422       for (int i = 0; i < nf; i++)
02423         for (int j = 0; j < count_f(i); j++)
02424           {
02425             int idx = int (f(i,j) - 1);
02426 
02427             if (clip(idx))
02428               continue;
02429 
02430             Matrix cc;
02431             if (c.numel () > 0)
02432               {
02433                 cc.resize (1, 3);
02434                 if (has_markerfacecolor)
02435                   cc(0) = c(i,0), cc(1) = c(i,1), cc(2) = c(i,2);
02436                 else
02437                   cc(0) = c(idx,0), cc(1) = c(idx,1), cc(2) = c(idx,2);
02438               }
02439 
02440             Matrix lc = (do_edge ? (mecolor.numel () == 0 ? cc : mecolor)
02441                          : Matrix ());
02442             Matrix fc = (do_face ? (mfcolor.numel () == 0 ? cc : mfcolor)
02443                          : Matrix ());
02444 
02445             draw_marker (v(idx,0), v(idx,1), (has_z ? v(idx,2) : 0), lc, fc);
02446           }
02447 
02448       end_marker ();
02449     }
02450 }
02451 
02452 void
02453 opengl_renderer::draw_hggroup (const hggroup::properties &props)
02454 {
02455   draw (props.get_children ());
02456 }
02457 
02458 void
02459 opengl_renderer::draw_text (const text::properties& props)
02460 {
02461   if (props.get_string ().is_empty ())
02462     return;
02463 
02464   Matrix pos = xform.scale (props.get_data_position ());
02465   const Matrix bbox = props.get_extent_matrix ();
02466 
02467   // FIXME: handle margin and surrounding box
02468   bool blend = glIsEnabled (GL_BLEND);
02469 
02470   glEnable (GL_BLEND);
02471   glEnable (GL_ALPHA_TEST);
02472   glRasterPos3d (pos(0), pos(1), pos.numel () > 2 ? pos(2) : 0.0);
02473   glBitmap(0, 0, 0, 0, bbox(0), bbox(1), 0);
02474   glDrawPixels (bbox(2), bbox(3),
02475                 GL_RGBA, GL_UNSIGNED_BYTE, props.get_pixels ().data ());
02476   glDisable (GL_ALPHA_TEST);
02477   if (! blend)
02478     glDisable (GL_BLEND);
02479 
02480 }
02481 
02482 void
02483 opengl_renderer::draw_image (const image::properties& props)
02484 {
02485   octave_value cdata = props.get_color_data ();
02486   dim_vector dv (cdata.dims ());
02487   int h = dv(0), w = dv(1);
02488 
02489   Matrix x = props.get_xdata ().matrix_value ();
02490   Matrix y = props.get_ydata ().matrix_value ();
02491 
02492   if (w > 1 && x(1) == x(0))
02493     x(1) = x(1) + (w-1);
02494 
02495   if (h > 1 && y(1) == y(0))
02496     y(1) = y(1) + (h-1);
02497 
02498   const ColumnVector p0 = xform.transform (x(0), y(0), 0);
02499   const ColumnVector p1 = xform.transform (x(1), y(1), 0);
02500 
02501   // image pixel size in screen pixel units
02502   float pix_dx, pix_dy;
02503   // image pixel size in normalized units
02504   float nor_dx, nor_dy;
02505 
02506   if (w > 1)
02507     {
02508       pix_dx = (p1(0) - p0(0))/(w-1);
02509       nor_dx = (x(1) - x(0))/(w-1);
02510     }
02511   else
02512     {
02513       const ColumnVector p1w = xform.transform (x(1) + 1, y(1), 0);
02514       pix_dx = p1w(0) - p0(0);
02515       nor_dx = 1;
02516     }
02517 
02518   if (h > 1)
02519     {
02520       pix_dy = (p1(1) - p0(1))/(h-1);
02521       nor_dy = (y(1) - y(0))/(h-1);
02522     }
02523   else
02524     {
02525       const ColumnVector p1h = xform.transform (x(1), y(1) + 1, 0);
02526       pix_dy = p1h(1) - p0(1);
02527       nor_dy = 1;
02528     }
02529 
02530 
02531   // OpenGL won't draw the image if it's origin is outside the
02532   // viewport/clipping plane so we must do the clipping
02533   // ourselfes - only draw part of the image
02534 
02535   int j0 = 0, j1 = w;
02536   int i0 = 0, i1 = h;
02537 
02538   float im_xmin = x(0) - nor_dx/2;
02539   float im_xmax = x(1) + nor_dx/2;
02540   float im_ymin = y(0) - nor_dy/2;
02541   float im_ymax = y(1) + nor_dy/2;
02542   if (props.is_clipping ()) // clip to axes
02543     {
02544       if (im_xmin < xmin)
02545         j0 += (xmin - im_xmin)/nor_dx + 1;
02546       if (im_xmax > xmax)
02547         j1 -= (im_xmax - xmax)/nor_dx ;
02548 
02549       if (im_ymin < ymin)
02550         i0 += (ymin - im_ymin)/nor_dy + 1;
02551       if (im_ymax > ymax)
02552         i1 -= (im_ymax - ymax)/nor_dy;
02553     }
02554   else // clip to viewport
02555     {
02556       GLfloat vp[4];
02557       glGetFloatv(GL_VIEWPORT, vp);
02558       // FIXME -- actually add the code to do it!
02559 
02560     }
02561 
02562   if (i0 >= i1 || j0 >= j1)
02563     return;
02564 
02565   glPixelZoom (pix_dx, -pix_dy);
02566   glRasterPos3d (im_xmin + nor_dx*j0, im_ymin + nor_dy*i0, 0);
02567 
02568   // by default this is 4
02569   glPixelStorei (GL_UNPACK_ALIGNMENT,1);
02570 
02571   // Expect RGB data
02572   if (dv.length () == 3 && dv(2) == 3)
02573     {
02574       if (cdata.is_double_type ())
02575         {
02576           const NDArray xcdata = cdata.array_value ();
02577 
02578           OCTAVE_LOCAL_BUFFER (GLfloat, a, 3*(j1-j0)*(i1-i0));
02579 
02580           for (int i = i0; i < i1; i++)
02581             {
02582               for (int j = j0, idx = (i-i0)*(j1-j0)*3; j < j1; j++, idx += 3)
02583                 {
02584                   a[idx]   = xcdata(i,j,0);
02585                   a[idx+1] = xcdata(i,j,1);
02586                   a[idx+2] = xcdata(i,j,2);
02587                 }
02588             }
02589 
02590           draw_pixels (j1-j0, i1-i0, GL_RGB, GL_FLOAT, a);
02591 
02592         }
02593       else if (cdata.is_uint16_type ())
02594         {
02595           const uint16NDArray xcdata = cdata.uint16_array_value ();
02596 
02597           OCTAVE_LOCAL_BUFFER (GLushort, a, 3*(j1-j0)*(i1-i0));
02598 
02599           for (int i = i0; i < i1; i++)
02600             {
02601               for (int j = j0, idx = (i-i0)*(j1-j0)*3; j < j1; j++, idx += 3)
02602                 {
02603                   a[idx]   = xcdata(i,j,0);
02604                   a[idx+1] = xcdata(i,j,1);
02605                   a[idx+2] = xcdata(i,j,2);
02606                 }
02607             }
02608 
02609           draw_pixels (j1-j0, i1-i0, GL_RGB, GL_UNSIGNED_SHORT, a);
02610 
02611         }
02612       else if (cdata.is_uint8_type ())
02613         {
02614           const uint8NDArray xcdata = cdata.uint8_array_value ();
02615 
02616           OCTAVE_LOCAL_BUFFER (GLubyte, a, 3*(j1-j0)*(i1-i0));
02617 
02618           for (int i = i0; i < i1; i++)
02619             {
02620               for (int j = j0, idx = (i-i0)*(j1-j0)*3; j < j1; j++, idx += 3)
02621                 {
02622                   a[idx]   = xcdata(i,j,0);
02623                   a[idx+1] = xcdata(i,j,1);
02624                   a[idx+2] = xcdata(i,j,2);
02625                 }
02626             }
02627 
02628           draw_pixels (j1-j0, i1-i0, GL_RGB, GL_UNSIGNED_BYTE, a);
02629         }
02630       else
02631         warning ("opengl_texture::draw: invalid image data type (expected double, uint16, or uint8)");
02632     }
02633   else
02634     warning ("opengl_texture::draw: invalid image size (expected n*m*3 or n*m)");
02635 
02636   glPixelZoom (1, 1);
02637 }
02638 
02639 void
02640 opengl_renderer::set_viewport (int w, int h)
02641 {
02642   glViewport (0, 0, w, h);
02643 }
02644 
02645 void
02646 opengl_renderer::draw_pixels (GLsizei width, GLsizei height, GLenum format,
02647                               GLenum type, const GLvoid *data)
02648 {
02649   glDrawPixels (width, height, format, type, data);
02650 }
02651 
02652 void
02653 opengl_renderer::set_color (const Matrix& c)
02654 {
02655   glColor3dv (c.data ());
02656 #if HAVE_FREETYPE
02657   text_renderer.set_color (c);
02658 #endif
02659 }
02660 
02661 void
02662 opengl_renderer::set_font (const base_properties& props)
02663 {
02664 #if HAVE_FREETYPE
02665   text_renderer.set_font (props.get ("fontname").string_value (),
02666                           props.get ("fontweight").string_value (),
02667                           props.get ("fontangle").string_value (),
02668                           props.get ("fontsize").double_value ());
02669 #endif
02670 }
02671 
02672 void
02673 opengl_renderer::set_polygon_offset (bool on, double offset)
02674 {
02675   if (on)
02676     {
02677       glPolygonOffset (offset, offset);
02678       glEnable (GL_POLYGON_OFFSET_FILL);
02679       glEnable (GL_POLYGON_OFFSET_LINE);
02680     }
02681   else
02682     {
02683       glDisable (GL_POLYGON_OFFSET_FILL);
02684       glDisable (GL_POLYGON_OFFSET_LINE);
02685     }
02686 }
02687 
02688 void
02689 opengl_renderer::set_linewidth (float w)
02690 {
02691   glLineWidth (w);
02692 }
02693 
02694 void
02695 opengl_renderer::set_linestyle (const std::string& s, bool use_stipple)
02696 {
02697   bool solid = false;
02698 
02699   if (s == "-")
02700     {
02701       glLineStipple (1, static_cast<unsigned short> (0xFFFF));
02702       solid = true;
02703     }
02704   else if (s == ":")
02705     glLineStipple (1, static_cast<unsigned short> (0x8888));
02706   else if (s == "--")
02707     glLineStipple (1, static_cast<unsigned short> (0x0FFF));
02708   else if (s == "-.")
02709     glLineStipple (1, static_cast<unsigned short> (0x020F));
02710   else
02711     glLineStipple (1, static_cast<unsigned short> (0x0000));
02712 
02713   if (solid && ! use_stipple)
02714     glDisable (GL_LINE_STIPPLE);
02715   else
02716     glEnable (GL_LINE_STIPPLE);
02717 }
02718 
02719 void
02720 opengl_renderer::set_clipbox (double x1, double x2, double y1, double y2,
02721                               double z1, double z2)
02722 {
02723   double dx = (x2-x1);
02724   double dy = (y2-y1);
02725   double dz = (z2-z1);
02726 
02727   x1 -= 0.001*dx; x2 += 0.001*dx;
02728   y1 -= 0.001*dy; y2 += 0.001*dy;
02729   z1 -= 0.001*dz; z2 += 0.001*dz;
02730 
02731   ColumnVector p (4, 0.0);
02732 
02733   p(0) = -1; p(3) = x2;
02734   glClipPlane (GL_CLIP_PLANE0, p.data ());
02735   p(0) = 1; p(3) = -x1;
02736   glClipPlane (GL_CLIP_PLANE1, p.data ());
02737   p(0) = 0; p(1) = -1; p(3) = y2;
02738   glClipPlane (GL_CLIP_PLANE2, p.data ());
02739   p(1) = 1; p(3) = -y1;
02740   glClipPlane (GL_CLIP_PLANE3, p.data ());
02741   p(1) = 0; p(2) = -1; p(3) = z2;
02742   glClipPlane (GL_CLIP_PLANE4, p.data ());
02743   p(2) = 1; p(3) = -z1;
02744   glClipPlane (GL_CLIP_PLANE5, p.data ());
02745 
02746   xmin = x1; xmax = x2;
02747   ymin = y1; ymax = y2;
02748   zmin = z1; zmax = z2;
02749 }
02750 
02751 void
02752 opengl_renderer::set_clipping (bool enable)
02753 {
02754   bool has_clipping = (glIsEnabled (GL_CLIP_PLANE0) == GL_TRUE);
02755 
02756   if (enable != has_clipping)
02757     {
02758       if (enable)
02759         for (int i = 0; i < 6; i++)
02760           glEnable (GL_CLIP_PLANE0+i);
02761       else
02762         for (int i = 0; i < 6; i++)
02763           glDisable (GL_CLIP_PLANE0+i);
02764     }
02765 }
02766 
02767 void
02768 opengl_renderer::init_marker (const std::string& m, double size, float width)
02769 {
02770 #if defined (HAVE_FRAMEWORK_OPENGL)
02771   GLint vw[4];
02772 #else
02773   int vw[4];
02774 #endif
02775 
02776   glGetIntegerv (GL_VIEWPORT, vw);
02777 
02778   glMatrixMode (GL_PROJECTION);
02779   glPushMatrix ();
02780   glLoadIdentity ();
02781   glOrtho (0, vw[2], vw[3], 0, xZ1, xZ2);
02782   glMatrixMode (GL_MODELVIEW);
02783   glPushMatrix ();
02784 
02785   set_clipping (false);
02786   set_linewidth (width);
02787 
02788   marker_id = make_marker_list (m, size, false);
02789   filled_marker_id = make_marker_list (m, size, true);
02790 }
02791 
02792 void
02793 opengl_renderer::end_marker (void)
02794 {
02795   glDeleteLists (marker_id, 1);
02796   glDeleteLists (filled_marker_id, 1);
02797 
02798   glMatrixMode (GL_MODELVIEW);
02799   glPopMatrix ();
02800   glMatrixMode (GL_PROJECTION);
02801   glPopMatrix ();
02802   set_linewidth (0.5f);
02803 }
02804 
02805 void
02806 opengl_renderer::draw_marker (double x, double y, double z,
02807                               const Matrix& lc, const Matrix& fc)
02808 {
02809   ColumnVector tmp = xform.transform (x, y, z, false);
02810 
02811   glLoadIdentity ();
02812   glTranslated (tmp(0), tmp(1), -tmp(2));
02813 
02814   if (filled_marker_id > 0 && fc.numel () > 0)
02815     {
02816       glColor3dv (fc.data ());
02817       set_polygon_offset (true, -1.0);
02818       glCallList (filled_marker_id);
02819       if (lc.numel () > 0)
02820         {
02821           glColor3dv (lc.data ());
02822           glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
02823           glEdgeFlag (GL_TRUE);
02824           set_polygon_offset (true, -2.0);
02825           glCallList (filled_marker_id);
02826           glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
02827         }
02828       set_polygon_offset (false);
02829     }
02830   else if (marker_id > 0 && lc.numel () > 0)
02831     {
02832       glColor3dv (lc.data ());
02833       glCallList (marker_id);
02834     }
02835 }
02836 
02837 unsigned int
02838 opengl_renderer::make_marker_list (const std::string& marker, double size,
02839                                    bool filled) const
02840 {
02841   char c = marker[0];
02842 
02843   if (filled && (c == '+' || c == 'x' || c == '*' || c == '.'))
02844     return 0;
02845 
02846   unsigned int ID = glGenLists (1);
02847   double sz = size * toolkit.get_screen_resolution () / 72.0;
02848 
02849   // constants for the * marker
02850   const double sqrt2d4 = 0.35355339059327;
02851   double tt = sz*sqrt2d4;
02852 
02853   glNewList (ID, GL_COMPILE);
02854 
02855   switch (marker[0])
02856     {
02857     case '+':
02858       glBegin (GL_LINES);
02859       glVertex2f (-sz/2, 0);
02860       glVertex2f (sz/2, 0);
02861       glVertex2f (0, -sz/2);
02862       glVertex2f (0, sz/2);
02863       glEnd ();
02864       break;
02865     case 'x':
02866       glBegin(GL_LINES);
02867       glVertex2f (-sz/2, -sz/2);
02868       glVertex2f (sz/2, sz/2);
02869       glVertex2f (-sz/2, sz/2);
02870       glVertex2f (sz/2, -sz/2);
02871       glEnd ();
02872       break;
02873     case '*':
02874       glBegin (GL_LINES);
02875       glVertex2f (-sz/2, 0);
02876       glVertex2f (sz/2, 0);
02877       glVertex2f (0, -sz/2);
02878       glVertex2f (0, sz/2);
02879       glVertex2f (-tt, -tt);
02880       glVertex2f (+tt, +tt);
02881       glVertex2f (-tt, +tt);
02882       glVertex2f (+tt, -tt);
02883       glEnd ();
02884       break;
02885     case '.':
02886       {
02887         double ang_step = M_PI / 5;
02888 
02889         glBegin (GL_POLYGON);
02890         for (double ang = 0; ang < (2*M_PI); ang += ang_step)
02891           glVertex2d (sz*cos(ang)/3, sz*sin(ang)/3);
02892         glEnd ();
02893       }
02894       break;
02895     case 's':
02896       glBegin ((filled ? GL_POLYGON : GL_LINE_LOOP));
02897       glVertex2d (-sz/2, -sz/2);
02898       glVertex2d (-sz/2, sz/2);
02899       glVertex2d (sz/2, sz/2);
02900       glVertex2d (sz/2, -sz/2);
02901       glEnd();
02902       break;
02903     case 'o':
02904       {
02905         double ang_step = M_PI / 5;
02906 
02907         glBegin ((filled ? GL_POLYGON : GL_LINE_LOOP));
02908         for (double ang = 0; ang < (2*M_PI); ang += ang_step)
02909           glVertex2d (sz*cos(ang)/2, sz*sin(ang)/2);
02910         glEnd ();
02911       }
02912       break;
02913     case 'd':
02914       glBegin ((filled ? GL_POLYGON : GL_LINE_LOOP));
02915       glVertex2d (0, -sz/2);
02916       glVertex2d (sz/2, 0);
02917       glVertex2d (0, sz/2);
02918       glVertex2d (-sz/2, 0);
02919       glEnd();
02920       break;
02921     case 'v':
02922       glBegin ((filled ? GL_POLYGON : GL_LINE_LOOP));
02923       glVertex2f (0, sz/2);
02924       glVertex2f (sz/2, -sz/2);
02925       glVertex2f (-sz/2, -sz/2);
02926       glEnd ();
02927       break;
02928     case '^':
02929       glBegin ((filled ? GL_POLYGON : GL_LINE_LOOP));
02930       glVertex2f (0, -sz/2);
02931       glVertex2f (-sz/2, sz/2);
02932       glVertex2f (sz/2, sz/2);
02933       glEnd ();
02934       break;
02935     case '>':
02936       glBegin ((filled ? GL_POLYGON : GL_LINE_LOOP));
02937       glVertex2f (sz/2, 0);
02938       glVertex2f (-sz/2, sz/2);
02939       glVertex2f (-sz/2, -sz/2);
02940       glEnd ();
02941       break;
02942     case '<':
02943       glBegin ((filled ? GL_POLYGON : GL_LINE_LOOP));
02944       glVertex2f (-sz/2, 0);
02945       glVertex2f (sz/2, -sz/2);
02946       glVertex2f (sz/2, sz/2);
02947       glEnd ();
02948       break;
02949     case 'p':
02950       {
02951         double ang;
02952         double r;
02953         double dr = 1.0 - sin(M_PI/10)/sin(3*M_PI/10)*1.02;
02954 
02955         glBegin ((filled ? GL_POLYGON : GL_LINE_LOOP));
02956         for (int i = 0; i < 2*5; i++)
02957           {
02958             ang = (-0.5 + double(i+1)/5) * M_PI;
02959             r = 1.0 - (dr * fmod(double(i+1), 2.0));
02960             glVertex2d (sz*r*cos(ang)/2, sz*r*sin(ang)/2);
02961           }
02962         glEnd ();
02963       }
02964       break;
02965     case 'h':
02966       {
02967         double ang;
02968         double r;
02969         double dr = 1.0 - 0.5/sin(M_PI/3)*1.02;
02970 
02971         glBegin ((filled ? GL_POLYGON : GL_LINE_LOOP));
02972         for (int i = 0; i < 2*6; i++)
02973           {
02974             ang = (0.5 + double(i+1)/6.0) * M_PI;
02975             r = 1.0 - (dr * fmod(double(i+1), 2.0));
02976             glVertex2d (sz*r*cos(ang)/2, sz*r*sin(ang)/2);
02977           }
02978         glEnd ();
02979       }
02980       break;
02981     default:
02982       warning ("opengl_renderer: unsupported marker '%s'",
02983                marker.c_str ());
02984       break;
02985     }
02986 
02987   glEndList ();
02988 
02989   return ID;
02990 }
02991 
02992 void
02993 opengl_renderer::text_to_pixels (const std::string& txt,
02994                                  uint8NDArray& pixels,
02995                                  Matrix& bbox,
02996                                  int halign, int valign, double rotation)
02997 {
02998 #if HAVE_FREETYPE
02999   text_renderer.text_to_pixels (txt, pixels, bbox,
03000                                 halign, valign, rotation);
03001 #endif
03002 }
03003 
03004 Matrix
03005 opengl_renderer::render_text (const std::string& txt,
03006                             double x, double y, double z,
03007                             int halign, int valign, double rotation)
03008 {
03009 #if HAVE_FREETYPE
03010   if (txt.empty ())
03011     return Matrix (1, 4, 0.0);
03012 
03013   uint8NDArray pixels;
03014   Matrix bbox;
03015   text_to_pixels (txt, pixels, bbox, halign, valign, rotation);
03016 
03017   bool blend = glIsEnabled (GL_BLEND);
03018 
03019   glEnable (GL_BLEND);
03020   glEnable (GL_ALPHA_TEST);
03021   glRasterPos3d (x, y, z);
03022   glBitmap(0, 0, 0, 0, bbox(0), bbox(1), 0);
03023   glDrawPixels (bbox(2), bbox(3),
03024                 GL_RGBA, GL_UNSIGNED_BYTE, pixels.data ());
03025   glDisable (GL_ALPHA_TEST);
03026   if (! blend)
03027     glDisable (GL_BLEND);
03028 
03029   return bbox;
03030 #else
03031   ::warning ("render_text: cannot render text, Freetype library not available");
03032   return Matrix (1, 4, 0.0);
03033 #endif
03034 }
03035 
03036 #endif
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines