Mercurial > octave-nkf
changeset 7874:e3a502930e2a
eliminate src/graphics subdirectory
author | John W. Eaton <jwe@octave.org> |
---|---|
date | Thu, 05 Jun 2008 18:00:37 -0400 |
parents | 02b590f46a29 |
children | bff8dbc1be11 |
files | ChangeLog Makeconf.in configure.in src/ChangeLog src/DLD-FUNCTIONS/fltk_backend.cc src/Makefile.in src/gl-render.cc src/gl-render.h src/graphics/ChangeLog src/graphics/Makefile.in src/graphics/Makerules.in src/graphics/fltk_backend/Makefile.in src/graphics/fltk_backend/fltk_backend.cc src/graphics/opengl/Makefile.in src/graphics/opengl/gl-render.cc src/graphics/opengl/gl-render.h |
diffstat | 16 files changed, 3962 insertions(+), 4322 deletions(-) [+] |
line wrap: on
line diff
--- a/ChangeLog Thu Jun 05 20:42:14 2008 +0200 +++ b/ChangeLog Thu Jun 05 18:00:37 2008 -0400 @@ -1,3 +1,12 @@ +2008-06-05 John W. Eaton <jwe@octave.org> + + * configure.in: Add FT2_CFLAGS to XTRA_CXXFLAGS, not CXXFLAGS. + Don't add FT2_LIBS to LIBS. + Don't generate src/graphics/Makefile, src/graphics/Makerules, + src/graphics/opengl/Makefile, or src/graphics/fltk_backend/Makefile. + + * Makeconf.in (FT2_LIBS, GRAPHICS_LIBS): Substitute here. + 2008-06-04 Shai Ayal <shaiay@users.sourceforge.net> * configure.in: Use AC_TRY_LINK in FTGL test.
--- a/Makeconf.in Thu Jun 05 20:42:14 2008 +0200 +++ b/Makeconf.in Thu Jun 05 18:00:37 2008 -0400 @@ -215,6 +215,8 @@ LIBREADLINE = @LIBREADLINE@ TERMLIBS = @TERMLIBS@ +FT2_LIBS = @FT2_LIBS@ +GRAPHICS_LIBS = @GRAPHICS_LIBS@ QHULL_LIBS = @QHULL_LIBS@ REGEX_LIBS = @REGEX_LIBS@ BLAS_LIBS = @BLAS_LIBS@
--- a/configure.in Thu Jun 05 20:42:14 2008 +0200 +++ b/configure.in Thu Jun 05 18:00:37 2008 -0400 @@ -664,11 +664,12 @@ OPENGL_LIBS="$OPENGL_LIBS $FT2_LIBS -lftgl" LIBS="$save_LIBS" AC_DEFINE(HAVE_FTGL, 1, [Define to 1 if FTGL is present]) - AC_MSG_RESULT(yes)],[ + AC_MSG_RESULT(yes) + XTRA_CXXFLAGS="$XTRA_CXXFLAGS $FT2_CFLAGS"],[ + AC_MSG_RESULT(no)])],[ + warn_graphics="FTGL library not found. Native renderer will not have on-screen text"]) LIBS="$save_LIBS" CXXFLAGS="$save_CXXFLAGS" - AC_MSG_RESULT(no)])],[ - warn_graphics="FTGL library not found. Native renderer will not have on-screen text"]) AC_LANG_POP(C++) fi fi @@ -1961,9 +1962,7 @@ libcruft/qrupdate/Makefile libcruft/ranlib/Makefile libcruft/slatec-fn/Makefile libcruft/slatec-err/Makefile libcruft/villad/Makefile - libcruft/blas-xtra/Makefile libcruft/lapack-xtra/Makefile - src/graphics/Makefile src/graphics/Makerules - src/graphics/opengl/Makefile src/graphics/fltk_backend/Makefile]) + libcruft/blas-xtra/Makefile libcruft/lapack-xtra/Makefile]) AC_OUTPUT AC_CONFIG_COMMANDS([default-1],[[chmod +x install-octave]],[[]])
--- a/src/ChangeLog Thu Jun 05 20:42:14 2008 +0200 +++ b/src/ChangeLog Thu Jun 05 18:00:37 2008 -0400 @@ -1,5 +1,21 @@ 2008-06-05 John W. Eaton <jwe@octave.org> + * gl-render.cc (opengl_renderer::draw): Correctly avoid shadow + warnings from gcc for xmin, xmax, ymin, ymax, zmin, and zmax. + + * graphics/ChangeLog, graphics/Makefile.in, graphics/Makerules.in, + graphics/fltk_backend/Makefile.in, graphics/opengl/Makefile.in: + Delete. + + * gl-render.cc, gl-render.h: Move here from src/graphics/opengl. + * Makefile.in: Add them to the appropriate lists. + (octave$(EXEEXT)): Also link with $(OPENGL_LIBS) + + * fltk_backend.cc: Move here from src/graphics/fltk_backend. + * Makefile.in (DLD_XSRC): Add it to the list + (fltk_backend.oct): Include special rules for linking with + $(GRAPHICS_LIBS) and $(FT2_LIBS). + * dynamic-ld.cc (octave_dynamic_loader::mex_mangler, octave_dynamic_loader::mex_uscore_mangler, octave_dynamic_loader::mex_f77_mangler): New functions. @@ -12,6 +28,192 @@ * graphics.cc (properties::update_normals): Style fixes. * graphics.h.in: Style fixes. + ChangeLog entries for gl-render.h, gl-render.cc, and + fltk_backend.cc before the move: + + 2008-06-05 John W. Eaton <jwe@octave.org> + + * opengl/gl-render.cc (xmin): New static function. + + * opengl/gl-render.h (opengl_renderer): Style fixes. + * fltk_backend/fltk_backend.cc: Style fixes. + + 2008-04-26 Michael Goffioul <michael.goffioul@gmail.com> + + * opengl/gl-render.h (opengl_renderer::draw(hggroup)): New method. + * opengl/gl-render.cc (opengl_renderer::draw(hggroup)): Likewise. + (opengl_renderer::draw(graphics_object)): Call it. + + 2008-03-17 Shai Ayal <shaiay@users.sourceforge.net> + + * fltk_backend/fltk_backend.cc (plot_window::resize, + plot_window::draw): make canvas the size of figure.position + + 2008-03-09 Shai Ayal <shaiay@users.sourceforge.net> + + * fltk_backend/fltk_backend.cc (plot_window::handle): add zoom + stack + + 2008-03-06 Shai Ayal <shaiay@users.sourceforge.net> + + * fltk_backend/fltk_backend.cc (plot_window::handle): Add handling + of the 'a' and 'g' keys + (plot_window: toggle_grid): New helper function + (plot_window): Add new togglegrid button + + 2008-03-01 Shai Ayal <shaiay@users.sourceforge.net> + + * fltk_backend/fltk_backend.cc (OpenGL_fltk::draw_overlay, + OpenGL_fltk::zoom, OpenGL_fltk::set_zoom_box): Added to support + zoom box + (plot_window::handle): Added zoom box code, B-3 now does autoscale + (plot_window::axis_auto): New utility function to call axis("auto") + (plot_window::button_press): "A" button now does autoscale + + * opengl/gl-render.cc (make_marker_list): Add the "+x*.^v><" + markers + + 2008-02-27 Michael Goffioul <michael.goffioul@gmail.com> + + * opengl/gl-render.cc (opengl_renderer::draw(patch), + opengl_renderer::draw(surface)): Adapt to type change of facealpha and + edgealpha, using double_radio_property class. + + 2008-02-26 Michael Goffioul <michael.goffioul@gmail.com> + + * opengl/gl-render.h: Make sure windows.h is included before OpenGL + headers. + * fltk_backend/Makefile.in (FLTK_EXTRA_CXXFLAGS): Use $(srcdir) for + includesion of OpenGL renderer headers. + (Makeconf): Move inclusion of Makeconf later on, to avoid freezing + MinGW make. + + * fltk_backend/Makefile.in (GRAPHICS_CFLAGS): New substituted + variable. + + 2008-02-25 Shai Ayal <shaiay@users.sourceforge.net> + + * fltk_backend/fltk_backend.cc (class plot_window): Many changes + to use figure::properties instead of figure handle to reference + the figure + (class figure_manager): ditto + (__fltk_redraw__): moved most of functionality into the + figure_manager class + (plot_window::pixel2pos): Modified to use axes::pixel2coord + (plot_window::pixel2staus): Modified to use pixel2pos + (plot_window::handle): Added zoom with mouse + + 2008-02-24 Shai Ayal <shaiay@users.sourceforge.net> + + * fltk_backend/fltk_backend.cc (OpenGL_fltk::Draw): removed double + buffer switch + (OpenGL_fltk::setup_viewport): removed call to glOrtho -- + gl-render takes care of all the transformations + + 2008-02-23 Shai Ayal <shaiay@users.sourceforge.net> + + * fltk_backend/fltk_backend.cc (plot_window::mark_modifed): mark + the whole window as damaged (otherwise changing figure.postion + does not have immediate effect) + (plot_window::draw): New function, checks for window size + (__fltk_maxtime__): New DEFUN to allow tweaking of fltk timeout + (__fltk_redraw__): Use fltk_maxtime as timeout + + 2008-02-21 Michael Goffioul <michael.goffioul@gmail.com> + + * opengl/gl-render.cc (opengl_renderer::patch_tesselator::combine): + Protect against NULL vertex data. + + * opengl/gl-render.cc (opengl_renderer::draw(patch)): Add marker + rendering of patch objects. + + 2008-02-21 Shai Ayal <shaiay@users.sourceforge.net> + + * opengl/gl-render.cc: remove OpenGL includes + * opengl/gl-render.h: add OpenGL includes + * fltk_backend/fltk_backend.cc: remove OpenGL includes + (__fltk_redraw__): put figure handle into the figure's + __plot_stream__ property for later + (fltk_backend::close_figure): use argument as figure handle to + close + + 2008-02-20 Shai Ayal <shaiay@users.sourceforge.net> + + * fltk_backend/Makefile.in: initial import + + * fltk_backend/fltk_backend.cc: initial import + + + 2008-02-20 Michael Goffioul <michael.goffioul@gmail.com> + + * opengl/gl-render.h (opengl_renderer::draw(patch)): New method to + render patch objects. + (class opengl_renderer::patch_tesselator): Forward declaration. + * opengl/gl-render.cc (opengl_texture::create): Use RGB data format + instead of RGBA. + (class opengl_tesselator): New classes to abstract GLU tessellation + process. + (class opengl_renderer::patch_tesselator): New class to render opaque + patch objects. + (class vertex_data): New class to hold vertex data during tessellation + of patch objects. + (opengl_renderer::draw(patch)): New method to render patch objects (no + transparency, no border, no marker yet). + (opengl_renderer::draw(graphics_object)): Dispatch to it. + + * opengl/gl-render.cc (opengl_renderer::draw(patch)): Use patch color + data and support face/vertex single color specification. + + * opengl/gl-render.cc (opengl_tesselator::begin_polygon): Set + tessellation property also for non-filled polygons. + (opengl_renderer::patch_tesselator::vertex): Protect against empty + color matrices. + (opengl_renderer::draw(patch)): Render patch border (no transparency + yet). + + 2008-02-19 Michael Goffioul <michael.goffioul@gmail.com> + + * opengl/gl-render.cc (opengl_texture::texture_rep::tex_coord, + opengl_texture::tex_coord): New wrapper around glTexCoord2d. + (opengl_renderer::draw(surface)): Use it for texturemap + implementation. + (opengl_renderer::draw(surface)): Fix indexing bug when creating clip + matrix. + (opengl_texture::operator=): Add assignment operator. + (opengl_texture::create): New static opengl_texture creator. + (opengl_texture::is_valid): New accessor. + + 2008-02-18 Michael Goffioul <michael.goffioul@gmail.com> + + * opengl/gl-render.cc (class opengl_texture): New class to wrap + texture operations in OpenGL. + + 2008-02-17 Michael Goffioul <michael.goffioul@gmail.com> + + * opengl/gl-render.cc (opengl_renderer::draw(surface)): Set material + color when rendering surface facets. + + * opengl/gl-render.cc (opengl_renderer::draw(surface)): Add rendering + of mesh and markers. + + 2008-02-16 Michael Goffioul <michael.goffioul@gmail.com> + + * opengl/gl-render.cc (opengl_renderer::draw(figure)): Initialize the + OpenGL context correctly. + (opengl_renderer::draw(surface)): Add missing glEnd call. + + 2008-02-14 Michael Goffioul <michael.goffioul@gmail.com> + + * opengl/gl-render.h opengl/gl-render.cc: Add rendering + interface for surface objects (actual implement still + missing). + + 2008-02-14 Michael Goffioul <michael.goffioul@gmail.com> + + * Makefile.in Makerules.in: Initial import + * opengl/Makefile.in: Likewise. + * opengl/gl-render.h opengl/gl-render.cc: Likewise. + 2008-06-04 Shai Ayal <shaiay@users.sourceforge.net> * graphics.cc (axes::properties::set_defaults): Preserve position
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/DLD-FUNCTIONS/fltk_backend.cc Thu Jun 05 18:00:37 2008 -0400 @@ -0,0 +1,811 @@ +/* + +Copyright (C) 2007, 2008 Shai Ayal + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +<http://www.gnu.org/licenses/>. + +*/ + +/* + +To initialize: + + input_event_hook ("__fltk_redraw__"); + __init_fltk__ (); + set (gcf (), "__backend__", "fltk"); + plot (randn (1e3, 1)); + +*/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <map> +#include <set> +#include <sstream> +#include <iostream> + +#include "gl-render.h" + +#include <FL/Fl.H> +#include <FL/Fl_Window.H> +#include <FL/Fl_Output.H> +#include <FL/Fl_Button.H> +#include <FL/Fl_Gl_Window.H> +#include <FL/fl_ask.H> +#include <FL/fl_draw.H> +#include <FL/gl.h> + +#include "oct.h" +#include "parse.h" +#include "graphics.h" + +#define FLTK_BACKEND_NAME "fltk" + +const char* help_text = "\ +Keyboard Shortcuts\n\ +a - autoscale\n\ +g - toggle grid\n\ +\n\ +Mouse\n\ +left drag - zoom\n\ +right click - unzoom\n\ +double click - copy coordinates to clipboard\ +"; + +class OpenGL_fltk : public Fl_Gl_Window +{ +public: + OpenGL_fltk (int xx, int yy, int ww, int hh, double num) + : Fl_Gl_Window (xx, yy, ww, hh, 0), number (num), in_zoom (false) + { + // ask for double buffering and a depth buffer + mode (FL_DEPTH | FL_DOUBLE); + } + + ~OpenGL_fltk (void) { } + + void zoom (bool z) { in_zoom = z; } + bool zoom (void) { return in_zoom; } + void set_zoom_box (const Matrix& zb) { zoom_box = zb; } + +private: + double number; + opengl_renderer renderer; + bool in_zoom; + + // (x1,y1,x2,y2) + Matrix zoom_box; + + void setup_viewport (int _w, int _h) + { + glMatrixMode (GL_PROJECTION); + glLoadIdentity (); + glViewport (0, 0, _w, _h); + } + + void draw (void) + { + if (!valid ()) + { + valid (1); + setup_viewport (w (), h ()); + } + + renderer.draw (gh_manager::lookup (number)); + } + + void resize (int _x,int _y,int _w,int _h) + { + Fl_Gl_Window::resize (_x, _y, _w, _h); + setup_viewport (_w, _h); + redraw (); + } + + void draw_overlay (void) + { + if (!in_zoom) + return; + + if (!valid()) + { + valid(1); + setup_viewport (w (), h ()); + } + + glPushMatrix (); + + glMatrixMode (GL_MODELVIEW); + glLoadIdentity (); + + glMatrixMode (GL_PROJECTION); + glLoadIdentity (); + gluOrtho2D (0.0, w (), 0.0, h ()); + + glPushAttrib (GL_DEPTH_BUFFER_BIT | GL_CURRENT_BIT); + glDisable (GL_DEPTH_TEST); + + glLineWidth (1); + glBegin (GL_LINE_STRIP); + gl_color(0); + glVertex2d (zoom_box(0), h () - zoom_box(1)); + glVertex2d (zoom_box(0), h () - zoom_box(3)); + glVertex2d (zoom_box(2), h () - zoom_box(3)); + glVertex2d (zoom_box(2), h () - zoom_box(1)); + glVertex2d (zoom_box(0), h () - zoom_box(1)); + glEnd (); + + glPopAttrib (); + glPopMatrix (); + } + + int handle (int event) + { + int retval = Fl_Gl_Window::handle (event); + + switch (event) + { + case FL_ENTER: + window ()->cursor (FL_CURSOR_CROSS); + return 1; + + case FL_LEAVE: + window ()->cursor (FL_CURSOR_DEFAULT); + return 1; + } + + return retval; + } +}; + +class plot_window : public Fl_Window +{ +public: + plot_window (int _x, int _y, int _w, int _h, figure::properties& _fp) + : Fl_Window (_x, _y, _w, _h, "octave"), fp (_fp) + { + callback (window_close, static_cast<void*> (this)); + + begin (); + { + canvas = new + OpenGL_fltk (0, 0, _w , _h - status_h, number ()); + + autoscale = new + Fl_Button (0, + _h - status_h, + status_h, + status_h, + "A"); + autoscale->callback (button_callback, static_cast<void*> (this)); + + togglegrid = new + Fl_Button (status_h, + _h - status_h, + status_h, + status_h, + "G"); + togglegrid->callback (button_callback, static_cast<void*> (this)); + + help = new + Fl_Button (2*status_h, + _h - status_h, + status_h, + status_h, + "H"); + help->callback (button_callback, static_cast<void*> (this)); + + status = new + Fl_Output (3*status_h, + _h - status_h, + _w > 2*status_h ? _w - status_h : 0, + status_h, ""); + + status->textcolor (FL_BLACK); + status->color (FL_GRAY); + status->textfont (FL_COURIER); + status->textsize (10); + status->box (FL_ENGRAVED_BOX); + + // This allows us to have a valid OpenGL context right away + canvas->mode (FL_DEPTH | FL_DOUBLE ); + show (); + canvas->show (); + canvas->make_current (); + } + end (); + + status->show (); + autoscale->show (); + togglegrid->show (); + + resizable (canvas); + size_range (4*status_h, 2*status_h); + + std::stringstream name; + name << "octave: figure " << number (); + label (name.str ().c_str ()); + } + + ~plot_window (void) + { + canvas->hide (); + status->hide (); + this->hide (); + delete canvas; + delete status; + } + + // FIXME -- this could change + double number (void) { return fp.get___myhandle__ ().value (); } + + void mark_modified (void) + { + damage (FL_DAMAGE_ALL); + canvas->damage (FL_DAMAGE_ALL); + } + +private: + // figure properties + figure::properties& fp; + + // status area height + static const int status_h = 20; + + // window callback + static void window_close (Fl_Widget*, void* data) + { + octave_value_list args; + args(0) = static_cast<plot_window*> (data)->number (); + feval ("close", args); + } + + // button callbacks + static void button_callback (Fl_Widget* ww, void* data) + { + static_cast<plot_window*> (data)->button_press (ww); + } + + void button_press (Fl_Widget* widg) + { + if (widg == autoscale) + axis_auto (); + + if (widg == togglegrid) + toggle_grid (); + + if (widg == help) + fl_message (help_text); + } + + OpenGL_fltk* canvas; + Fl_Button* autoscale; + Fl_Button* togglegrid; + Fl_Button* help; + Fl_Output* status; + + void axis_auto (void) + { + octave_value_list args; + args(0) = "auto"; + feval ("axis",args); + mark_modified (); + } + + void toggle_grid (void) + { + feval ("grid"); + mark_modified (); + } + + void pixel2pos (int px, int py, double& xx, double& yy) const + { + graphics_object ax = gh_manager::get_object (fp.get_currentaxes ()); + + if (ax && ax.isa ("axes")) + { + axes::properties& ap = + dynamic_cast<axes::properties&> (ax.get_properties ()); + ColumnVector pp = ap.pixel2coord (px, py); + xx = pp(0); + yy = pp(1); + } + } + + graphics_handle pixel2axes (int /* px */, int /* py */) + { + Matrix kids = fp.get_children (); + + for (octave_idx_type n = 0; n < kids.numel (); n++) + { + graphics_object ax = gh_manager::get_object (kids (n)); + if (ax && ax.isa ("axes")) + { +#if 0 + axes::properties& ap = + dynamic_cast<axes::properties&> (ax.get_properties ()); + + // std::cout << "\npixpos="<<pixpos<<"(px,py)=("<<px<<","<<py<<")\n"; + if (px >= pixpos(0) && px <= pixpos(2) + && py >= pixpos(1) && py <= pixpos(3)) + return ap.get___myhandle__ (); +#endif + } + } + + return graphics_handle (); + } + + void pixel2status (int px0, int py0, int px1 = -1, int py1 = -1) + { + double x0, y0, x1, y1; + std::stringstream cbuf; + + pixel2pos (px0, py0, x0, y0); + cbuf << "[" << x0 << ", " << y0 << "]"; + if (px1 >= 0) + { + pixel2pos (px1, py1, x1, y1); + cbuf << " -> ["<< x1 << ", " << y1 << "]"; + } + + status->value (cbuf.str ().c_str ()); + status->redraw (); + } + + void resize (int _x,int _y,int _w,int _h) + { + Fl_Window::resize (_x, _y, _w, _h); + + Matrix pos (1,4,0); + pos(0) = _x; + pos(1) = _y; + pos(2) = _w; + pos(3) = _h - status_h; + + fp.set_position (pos); + } + + void draw (void) + { + Matrix pos = fp.get_position ().matrix_value (); + Fl_Window::resize (pos(0), pos(1) , pos(2), pos(3) + status_h); + + return Fl_Window::draw (); + } + + int handle (int event) + { + static int px0,py0; + static graphics_handle h0 = graphics_handle (); + + int retval = Fl_Window::handle (event); + + // we only handle events which are in the canvas area + if (Fl::event_y () >= h() - status_h) + return retval; + + switch (event) + { + case FL_KEYDOWN: + switch(Fl::event_key ()) + { + case 'a': + case 'A': + axis_auto (); + break; + + case 'g': + case 'G': + toggle_grid (); + break; + } + break; + + case FL_MOVE: + pixel2status (Fl::event_x (), Fl::event_y ()); + break; + + case FL_PUSH: + if (Fl::event_button () == 1) + { + px0 = Fl::event_x (); + py0 = Fl::event_y (); + h0 = pixel2axes (Fl::event_x (), Fl::event_y ()); + return 1; + } + break; + + case FL_DRAG: + pixel2status (px0, py0, Fl::event_x (), Fl::event_y ()); + if (Fl::event_button () == 1) + { + canvas->zoom (true); + Matrix zoom_box (1,4,0); + zoom_box (0) = px0; + zoom_box (1) = py0; + zoom_box (2) = Fl::event_x (); + zoom_box (3) = Fl::event_y (); + canvas->set_zoom_box (zoom_box); + canvas->redraw_overlay (); + return 1; + } + break; + + case FL_RELEASE: + if (Fl::event_button () == 1) + { + // end of drag -- zoom + if (canvas->zoom ()) + { + canvas->zoom (false); + double x0,y0,x1,y1; + graphics_object ax = + gh_manager::get_object (fp.get_currentaxes ()); + if (ax && ax.isa ("axes")) + { + axes::properties& ap = + dynamic_cast<axes::properties&> (ax.get_properties ()); + pixel2pos (px0, py0, x0, y0); + pixel2pos (Fl::event_x (), Fl::event_y (), x1, y1); + Matrix xl (1,2,0); + Matrix yl (1,2,0); + if (x0 < x1) + { + xl(0) = x0; + xl(1) = x1; + } + else + { + xl(0) = x1; + xl(1) = x0; + } + + if (y0 < y1) + { + yl(0) = y0; + yl(1) = y1; + } + else + { + yl(0) = y1; + yl(1) = y0; + } + ap.zoom (xl, yl); + mark_modified (); + } + } + // one click -- select axes + else if ( Fl::event_clicks () == 0) + { + std::cout << "ca="<< h0.value ()<<"\n"; + if (h0.ok ()) + fp.set_currentaxes (h0.value()); + return 1; + } + } + else if (Fl::event_button () == 3) + { + graphics_object ax = + gh_manager::get_object (fp.get_currentaxes ()); + if (ax && ax.isa ("axes")) + { + axes::properties& ap = + dynamic_cast<axes::properties&> (ax.get_properties ()); + ap.unzoom (); + mark_modified (); + } + } + break; + } + + return retval; + } +}; + +class figure_manager +{ +public: + + static figure_manager& Instance (void) + { + static figure_manager fm; + return fm; + } + + ~figure_manager (void) + { + close_all (); + } + + void close_all (void) + { + wm_iterator win; + for (win = windows.begin (); win != windows.end (); win++) + delete (*win).second; + windows.clear (); + } + + void new_window (figure::properties& fp) + { + int x, y, w, h; + + int idx = figprops2idx (fp); + if (idx >= 0 && windows.find (idx) == windows.end ()) + { + default_size(x,y,w,h); + idx2figprops (curr_index , fp); + windows[curr_index++] = new plot_window (x, y, w, h, fp); + } + } + + void delete_window (int idx) + { + wm_iterator win; + if ((win = windows.find (idx)) != windows.end ()) + { + delete (*win).second; + windows.erase (win); + } + } + + void delete_window (std::string idx_str) + { + delete_window (str2idx (idx_str)); + } + + void mark_modified (int idx) + { + wm_iterator win; + if ((win=windows.find (idx)) != windows.end ()) + { + (*win).second->mark_modified (); + } + } + + void mark_modified (const graphics_handle& gh) + { + mark_modified (hnd2idx (gh)); + } + + Matrix get_size (int idx) + { + Matrix sz (1, 2, 0.0); + + wm_iterator win; + if ((win = windows.find (idx)) != windows.end ()) + { + sz(0) = (*win).second->w (); + sz(1) = (*win).second->h (); + } + + return sz; + } + + Matrix get_size (const graphics_handle& gh) + { + return get_size (hnd2idx (gh)); + } + +private: + figure_manager (void) { } + figure_manager (const figure_manager&) { } + figure_manager& operator = (const figure_manager&) { return *this; } + // singelton -- hide all of the above + + static int curr_index; + typedef std::map<int, plot_window*> window_map; + typedef window_map::iterator wm_iterator;; + window_map windows; + + static std::string fltk_idx_header; + + void default_size (int& x, int& y, int& w, int& h) + { + x = 10; + y = 10; + w = 400; + h = 300; + } + + int str2idx (const caseless_str clstr) + { + int ind; + if (clstr.find (fltk_idx_header,0) == 0) + { + std::istringstream istr (clstr.substr (fltk_idx_header.size ())); + if (istr >> ind) + return ind; + } + error ("fltk_backend: could not recognize fltk index"); + return -1; + } + + void idx2figprops (int idx, figure::properties& fp) + { + std::ostringstream ind_str; + ind_str << fltk_idx_header << idx; + fp.set___plot_stream__ (ind_str.str ()); + } + + int figprops2idx (const figure::properties& fp) + { + if (fp.get___backend__ () == FLTK_BACKEND_NAME) + { + octave_value ps = fp.get___plot_stream__ (); + if (ps.is_string ()) + return str2idx (ps.string_value ()); + else + return 0; + } + error ("fltk_backend:: figure is not fltk"); + return -1; + } + + int hnd2idx (const graphics_handle& fh) + { + return hnd2idx (fh.value ()); + } + + int hnd2idx (const double h) + { + graphics_object fobj = gh_manager::get_object (h); + if (fobj && fobj.isa ("figure")) + { + figure::properties& fp = + dynamic_cast<figure::properties&> (fobj.get_properties ()); + return figprops2idx (fp); + } + error ("fltk_backend:: not a figure"); + return -1; + } +}; + +std::string figure_manager::fltk_idx_header="fltk index="; +int figure_manager::curr_index = 1; + +class fltk_backend : public base_graphics_backend +{ +public: + fltk_backend (void) + : base_graphics_backend (FLTK_BACKEND_NAME) { } + + ~fltk_backend (void) { } + + bool is_valid (void) const { return true; } + + void close_figure (const octave_value& ov) const + { + if (ov.is_string ()) + figure_manager::Instance ().delete_window (ov.string_value ()); + } + + void redraw_figure (const graphics_handle& fh) const + { + figure_manager::Instance ().mark_modified (fh); + } + + void print_figure (const graphics_handle& /*fh*/, + const std::string& /*term*/, + const std::string& /*file*/, bool /*mono*/, + const std::string& /*debug_file*/) const { } + + Matrix get_canvas_size (const graphics_handle& fh) const + { + return figure_manager::Instance ().get_size (fh); + } + + double get_screen_resolution (void) const + { + // FLTK doesn't give this info + return 72.0; + } + + Matrix get_screen_size (void) const + { + Matrix sz (1, 2, 0.0); + sz(0) = Fl::w (); + sz(1) = Fl::h (); + return sz; + } +}; + +static bool backend_registered = false; +// call this to init the fltk backend +DEFUN_DLD (__init_fltk__, , , "") +{ + graphics_backend::register_backend (new fltk_backend); + backend_registered = true; + + octave_value retval; + return retval; +} + + +// call this to delete the fltk backend +DEFUN_DLD (__remove_fltk__, , , "") +{ + figure_manager::Instance ().close_all (); + graphics_backend::unregister_backend (FLTK_BACKEND_NAME); + backend_registered = false; + + // FIXME ??? + // give FLTK 10 seconds to wrap it up + Fl::wait(10); + octave_value retval; + return retval; +} + +// give FLTK no more than 0.01 sec to do it's stuff +static double fltk_maxtime = 1e-2; + +// call this to delete the fltk backend +DEFUN_DLD (__fltk_maxtime__, args, ,"") +{ + octave_value retval = fltk_maxtime; + + if (args.length () == 1) + { + if (args(0).is_real_scalar ()) + fltk_maxtime = args(0).double_value (); + else + error ("argument must be a real scalar"); + } + + return retval; +} + +// call this from the idle_callback to refresh windows +DEFUN_DLD (__fltk_redraw__, , , + "internal function for the fltk backend") +{ + octave_value retval; + + if (!backend_registered) + return retval; + + // we scan all figures and add those which use FLTK as a backend + graphics_object obj = gh_manager::get_object (0); + if (obj && obj.isa ("root_figure")) + { + base_properties& props = obj.get_properties (); + Matrix children = props.get_children (); + + for (octave_idx_type n = 0; n < children.numel (); n++) + { + graphics_object fobj = gh_manager::get_object (children (n)); + if (fobj && fobj.isa ("figure")) + { + figure::properties& fp = + dynamic_cast<figure::properties&> (fobj.get_properties ()); + if (fp.get___backend__ () == FLTK_BACKEND_NAME) + figure_manager::Instance ().new_window (fp); + } + } + } + + Fl::wait (fltk_maxtime); + + return retval; +} + +/* +;;; Local Variables: *** +;;; mode: C++ *** +;;; End: *** +*/
--- a/src/Makefile.in Thu Jun 05 20:42:14 2008 +0200 +++ b/src/Makefile.in Thu Jun 05 18:00:37 2008 -0400 @@ -65,7 +65,8 @@ DLD_XSRC := amd.cc balance.cc besselj.cc betainc.cc bsxfun.cc cellfun.cc \ chol.cc ccolamd.cc colamd.cc colloc.cc conv2.cc convhulln.cc daspk.cc \ dasrt.cc dassl.cc det.cc dispatch.cc dlmread.cc dmperm.cc eig.cc \ - expm.cc fft.cc fft2.cc fftn.cc fftw.cc filter.cc find.cc fsolve.cc \ + expm.cc fft.cc fft2.cc fftn.cc fftw.cc filter.cc find.cc \ + fltk_backend.cc fsolve.cc \ gammainc.cc gcd.cc getgrent.cc getpwent.cc getrusage.cc \ givens.cc hess.cc hex2num.cc inv.cc kron.cc lookup.cc lsode.cc \ lu.cc luinc.cc matrix_type.cc max.cc md5sum.cc pinv.cc qr.cc \ @@ -117,8 +118,8 @@ INCLUDES := Cell.h base-list.h builtins.h c-file-ptr-stream.h \ comment-list.h debug.h defun-dld.h defun-int.h defun.h \ - dirfns.h dynamic-ld.h error.h file-io.h gripes.h help.h \ - input.h lex.h load-path.h load-save.h ls-hdf5.h \ + dirfns.h dynamic-ld.h error.h file-io.h gl-render.h \ + gripes.h help.h input.h lex.h load-path.h load-save.h ls-hdf5.h \ ls-mat-ascii.h ls-mat4.h ls-mat5.h ls-oct-ascii.h \ ls-oct-binary.h ls-utils.h mex.h mexproto.h oct-errno.h \ oct-fstrm.h oct-hist.h oct-iostrm.h oct-map.h oct-obj.h \ @@ -196,9 +197,9 @@ DIST_SRC := Cell.cc bitfcns.cc c-file-ptr-stream.cc comment-list.cc \ cutils.c data.cc debug.cc defaults.cc defun.cc dirfns.cc \ - dynamic-ld.cc error.cc file-io.cc graphics.cc gripes.cc \ - help.cc input.cc lex.l load-path.cc load-save.cc ls-hdf5.cc \ - ls-mat-ascii.cc ls-mat4.cc ls-mat5.cc ls-oct-ascii.cc \ + dynamic-ld.cc error.cc file-io.cc gl-render.cc graphics.cc \ + gripes.cc help.cc input.cc lex.l load-path.cc load-save.cc \ + ls-hdf5.cc ls-mat-ascii.cc ls-mat4.cc ls-mat5.cc ls-oct-ascii.cc \ ls-oct-binary.cc ls-utils.cc main.c mappers.cc matherr.c \ mex.cc oct-fstrm.cc oct-hist.cc oct-iostrm.cc oct-map.cc \ oct-obj.cc oct-prcstrm.cc oct-procbuf.cc oct-stream.cc \ @@ -348,7 +349,7 @@ $(OCTAVE_LIBS) \ $(LEXLIB) $(UMFPACK_LIBS) $(AMD_LIBS) $(CAMD_LIBS) $(COLAMD_LIBS) \ $(CHOLMOD_LIBS) $(CCOLAMD_LIBS) $(CXSPARSE_LIBS) $(BLAS_LIBS) \ - $(FFTW_LIBS) $(LIBS) $(FLIBS) + $(FFTW_LIBS) $(OPENGL_LIBS) $(LIBS) $(FLIBS) stmp-pic: pic @if [ -f stmp-pic ]; then \ @@ -633,6 +634,8 @@ $(DL_LD) $(DL_LDFLAGS) -o $@ $< $(OCT_LINK_DEPS) $(CURL_LIBS) __glpk__.oct : pic/__glpk__.o octave$(EXEEXT) $(DL_LD) $(DL_LDFLAGS) -o $@ $< $(OCT_LINK_DEPS) $(GLPK_LIBS) + fltk_backend.oct : pic/fltk_backend.o octave$(EXEEXT) + $(DL_LD) $(DL_LDFLAGS) -o $@ $< $(OCT_LINK_DEPS) $(GRAPHICS_LIBS) $(FT2_LIBS) else convhulln.oct : convhulln.o octave$(EXEEXT) $(DL_LD) $(DL_LDFLAGS) -o $@ $< $(OCT_LINK_DEPS) $(QHULL_LIBS) @@ -646,6 +649,8 @@ $(DL_LD) $(DL_LDFLAGS) -o $@ $< $(OCT_LINK_DEPS) $(CURL_LIBS) __glpk__.oct : __glpk__.o octave$(EXEEXT) $(DL_LD) $(DL_LDFLAGS) -o $@ $< $(OCT_LINK_DEPS) $(GLPK_LIBS) + fltk_backend.oct : fltk_backend.o octave$(EXEEXT) + $(DL_LD) $(DL_LDFLAGS) -o $@ $< $(OCT_LINK_DEPS) $(GRAPHICS_LIBS) $(FT2_LIBS) endif endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/gl-render.cc Thu Jun 05 18:00:37 2008 -0400 @@ -0,0 +1,2783 @@ +/* + +Copyright (C) 2008 Michael Goffioul + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +<http://www.gnu.org/licenses/>. + +*/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <lo-mappers.h> +#include "gl-render.h" + +#define LIGHT_MODE GL_FRONT_AND_BACK + +// Win32 API requires the CALLBACK attributes for +// GLU callback functions. Define it to empty on +// other platforms. +#ifndef CALLBACK +#define CALLBACK +#endif + +enum { + AXE_ANY_DIR = 0, + AXE_DEPTH_DIR = 1, + AXE_HORZ_DIR = 2, + AXE_VERT_DIR = 3 +}; + +static octave_idx_type +xmin (octave_idx_type x, octave_idx_type y) +{ + return x < y ? x : y; +} + +class +opengl_texture +{ +protected: + class texture_rep + { + public: + texture_rep (void) : valid (false), count (1) { } + + texture_rep (GLuint _id, int _w, int _h, int _tw, int _th) + : id (_id), w (_w), h (_h), tw (_tw), th (_th), + tx (double(w)/tw), ty (double(h)/th), valid (true), + count (1) { } + + ~texture_rep (void) + { + if (valid) + glDeleteTextures (1, &id); + } + + void bind (int mode) const + { if (valid) glBindTexture (mode, id); } + + void tex_coord (double q, double r) const + { if (valid) glTexCoord2d (q*tx, r*ty); } + + GLuint id; + int w, h; + int tw, th; + double tx, ty; + bool valid; + int count; + }; + + texture_rep *rep; + +private: + opengl_texture (texture_rep *_rep) : rep (_rep) { } + +public: + opengl_texture (void) : rep (new texture_rep ()) { } + + opengl_texture (const opengl_texture& tx) + : rep (tx.rep) + { + rep->count++; + } + + ~opengl_texture (void) + { + if (--rep->count == 0) + delete rep; + } + + opengl_texture& operator = (const opengl_texture& tx) + { + if (--rep->count == 0) + delete rep; + + rep = tx.rep; + rep->count++; + + return *this; + } + + static opengl_texture create (const octave_value& data); + + void bind (int mode = GL_TEXTURE_2D) const + { rep->bind (mode); } + + void tex_coord (double q, double r) const + { rep->tex_coord (q, r); } + + bool is_valid (void) const + { return rep->valid; } +}; + +static int +next_power_of_2 (int n) +{ + int m = 1; + + while (m < n && m < INT_MAX) + m <<= 1; + + return m; +} + +opengl_texture +opengl_texture::create (const octave_value& data) +{ + opengl_texture retval; + + dim_vector dv (data.dims ()); + + // Expect RGB data + if (dv.length () == 3 && dv(2) == 3) + { + int h = dv(0), w = dv(1), tw, th; + GLuint id; + bool ok = true; + + tw = next_power_of_2 (w); + th = next_power_of_2 (w); + + glGenTextures (1, &id); + glBindTexture (GL_TEXTURE_2D, id); + + if (data.is_double_type ()) + { + NDArray _a = data.array_value (); + + OCTAVE_LOCAL_BUFFER (float, a, (3*tw*th)); + + for (int i = 0; i < h; i++) + for (int j = 0, idx = i*tw*3; j < w; j++, idx += 3) + { + a[idx] = _a(i,j,0); + a[idx+1] = _a(i,j,1); + a[idx+2] = _a(i,j,2); + } + + glTexImage2D (GL_TEXTURE_2D, 0, 3, tw, th, 0, + GL_RGB, GL_FLOAT, a); + } + else if (data.is_uint8_type ()) + { + uint8NDArray _a = data.uint8_array_value (); + + OCTAVE_LOCAL_BUFFER (octave_uint8, a, (3*tw*th)); + + for (int i = 0; i < h; i++) + for (int j = 0, idx = i*tw*3; j < w; j++, idx += 3) + { + a[idx] = _a(i,j,0); + a[idx+1] = _a(i,j,1); + a[idx+2] = _a(i,j,2); + } + + glTexImage2D (GL_TEXTURE_2D, 0, 3, tw, th, 0, + GL_RGB, GL_UNSIGNED_BYTE, a); + } + else + { + ok = false; + warning ("opengl_texture::create: invalid texture data type (expected double or uint8)"); + } + + if (ok) + { + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + if (glGetError () != GL_NO_ERROR) + warning ("opengl_texture::create: OpenGL error while generating texture data"); + else + retval = opengl_texture (new texture_rep (id, w, h, tw, th)); + } + } + else + warning ("opengl_texture::create: invalid texture data size"); + + return retval; +} + +class +opengl_tesselator +{ +public: + typedef void (CALLBACK *fcn) (void); + +public: + + opengl_tesselator (void) : glu_tess (0) { init (); } + + virtual ~opengl_tesselator (void) + { if (glu_tess) gluDeleteTess (glu_tess); } + + void begin_polygon (bool filled = true) + { + gluTessProperty (glu_tess, GLU_TESS_BOUNDARY_ONLY, + (filled ? GL_FALSE : GL_TRUE)); + fill = filled; + gluTessBeginPolygon (glu_tess, this); + } + + void end_polygon (void) const + { gluTessEndPolygon (glu_tess); } + + void begin_contour (void) const + { gluTessBeginContour (glu_tess); } + + void end_contour (void) const + { gluTessEndContour (glu_tess); } + + void add_vertex (double *loc, void *data) const + { gluTessVertex (glu_tess, loc, data); } + +protected: + virtual void begin (GLenum /*type*/) { } + + virtual void end (void) { } + + virtual void vertex (void */*data*/) { } + + virtual void combine (GLdouble /*c*/[3], void */*data*/[4], + GLfloat /*w*/[4], void **/*out_data*/) { } + + virtual void edge_flag (GLboolean /*flag*/) { } + + virtual void error (GLenum err) + { ::error ("OpenGL tesselation error (%d)", err); } + + virtual void init (void) + { + glu_tess = gluNewTess (); + + gluTessCallback (glu_tess, GLU_TESS_BEGIN_DATA, + reinterpret_cast<fcn> (tess_begin)); + gluTessCallback (glu_tess, GLU_TESS_END_DATA, + reinterpret_cast<fcn> (tess_end)); + gluTessCallback (glu_tess, GLU_TESS_VERTEX_DATA, + reinterpret_cast<fcn> (tess_vertex)); + gluTessCallback (glu_tess, GLU_TESS_COMBINE_DATA, + reinterpret_cast<fcn> (tess_combine)); + gluTessCallback (glu_tess, GLU_TESS_EDGE_FLAG_DATA, + reinterpret_cast<fcn> (tess_edge_flag)); + gluTessCallback (glu_tess, GLU_TESS_ERROR_DATA, + reinterpret_cast<fcn> (tess_error)); + } + + bool is_filled (void) const { return fill; } + +private: + static void CALLBACK tess_begin (GLenum type, void *t) + { reinterpret_cast<opengl_tesselator *> (t)->begin (type); } + + static void CALLBACK tess_end (void *t) + { reinterpret_cast<opengl_tesselator *> (t)->end (); } + + static void CALLBACK tess_vertex (void *v, void *t) + { reinterpret_cast<opengl_tesselator *> (t)->vertex (v); } + + static void CALLBACK tess_combine (GLdouble c[3], void *v[4], GLfloat w[4], + void **out, void *t) + { reinterpret_cast<opengl_tesselator *> (t)->combine (c, v, w, out); } + + static void CALLBACK tess_edge_flag (GLboolean flag, void *t) + { reinterpret_cast<opengl_tesselator *> (t)->edge_flag (flag); } + + static void CALLBACK tess_error (GLenum err, void *t) + { reinterpret_cast<opengl_tesselator *> (t)->error (err); } + +private: + GLUtesselator *glu_tess; + bool fill; +}; + +class +vertex_data +{ +public: + class vertex_data_rep + { + public: + Matrix coords; + Matrix color; + Matrix normal; + double alpha; + float ambient; + float diffuse; + float specular; + float specular_exp; + + // reference counter + int count; + + vertex_data_rep (void) { } + + vertex_data_rep (const Matrix& c, const Matrix& col, const Matrix& n, + double a, float as, float ds, float ss, float se) + : coords (c), color (col), normal (n), alpha (a), + ambient (as), diffuse (ds), specular (ss), specular_exp (se), + count (1) { } + }; + +private: + vertex_data_rep *rep; + + vertex_data_rep *nil_rep (void) const + { + static vertex_data_rep *nr = new vertex_data_rep (); + + return nr; + } + +public: + vertex_data (void) : rep (nil_rep ()) { } + + vertex_data (const vertex_data& v) : rep (v.rep) + { rep->count++; } + + vertex_data (const Matrix& c, const Matrix& col, const Matrix& n, + double a, float as, float ds, float ss, float se) + : rep (new vertex_data_rep (c, col, n, a, as, ds, ss, se)) + { + rep->count++; + } + + vertex_data (vertex_data_rep *new_rep) + : rep (new_rep) { } + + ~vertex_data (void) + { + if (--rep->count == 0) + delete rep; + } + + vertex_data& operator = (const vertex_data& v) + { + if (--rep->count == 0) + delete rep; + + rep = v.rep; + rep->count++; + + return *this; + } + + vertex_data_rep *get_rep (void) const { return rep; } +}; + +#include <Array.cc> + +class +opengl_renderer::patch_tesselator : public opengl_tesselator +{ +public: + patch_tesselator (opengl_renderer *r, int cmode, int lmode, int idx = 0) + : opengl_tesselator (), renderer (r), + color_mode (cmode), light_mode (lmode), index (idx), + first (true) { } + +protected: + void begin (GLenum type) + { + //printf("patch_tesselator::begin (%d)\n", type); + first = true; + + if (color_mode == 2 || light_mode == 2) + glShadeModel (GL_SMOOTH); + else + glShadeModel (GL_FLAT); + + if (is_filled ()) + renderer->set_polygon_offset (true, 1+index); + + glBegin (type); + } + + void end (void) + { + //printf("patch_tesselator::end\n"); + glEnd (); + renderer->set_polygon_offset (false); + } + + void vertex (void *data) + { + vertex_data::vertex_data_rep *v + = reinterpret_cast<vertex_data::vertex_data_rep *> (data); + //printf("patch_tesselator::vertex (%g, %g, %g)\n", v->coords(0), v->coords(1), v->coords(2)); + + // FIXME: why did I need to keep the first vertex of the face + // in JHandles? I think it's related to the fact that the + // tessellation process might re-order the vertices, such that + // the first one you get here might not be the first one of the face; + // but I can't figure out the actual reason. + if (color_mode > 0 && (first || color_mode == 2)) + { + Matrix col = v->color; + + if (col.numel () == 3) + { + glColor3dv (col.data ()); + if (light_mode > 0) + { + float buf[4] = { 0, 0, 0, 1 }; + + for (int k = 0; k < 3; k++) + buf[k] = (v->ambient * col(k)); + glMaterialfv (LIGHT_MODE, GL_AMBIENT, buf); + + for (int k = 0; k < 3; k++) + buf[k] = (v->diffuse * col(k)); + glMaterialfv (LIGHT_MODE, GL_AMBIENT, buf); + } + } + } + + if (light_mode > 0 && (first || light_mode == 2)) + glNormal3dv (v->normal.data ()); + + glVertex3dv (v->coords.data ()); + + first = false; + } + + void combine (GLdouble xyz[3], void *data[4], GLfloat w[4], + void **out_data) + { + //printf("patch_tesselator::combine\n"); + + vertex_data::vertex_data_rep *v[4]; + int vmax = 4; + + for (int i = 0; i < 4; i++) + { + v[i] = reinterpret_cast<vertex_data::vertex_data_rep *> (data[i]); + + if (vmax == 4 && ! v[i]) + vmax = i; + } + + Matrix vv (1, 3, 0.0); + Matrix cc; + Matrix nn (1, 3, 0.0); + double aa = 0.0; + + vv(0) = xyz[0]; + vv(1) = xyz[1]; + vv(2) = xyz[2]; + + if (v[0]->color.numel ()) + { + cc.resize (1, 3, 0.0); + for (int ic = 0; ic < 3; ic++) + for (int iv = 0; iv < vmax; iv++) + cc(ic) += (w[iv] * v[iv]->color(ic)); + } + + if (v[0]->normal.numel () > 0) + { + for (int in = 0; in < 3; in++) + for (int iv = 0; iv < vmax; iv++) + nn(in) += (w[iv] * v[iv]->normal(in)); + } + + for (int iv = 0; iv < vmax; iv++) + aa += (w[iv] * v[iv]->alpha); + + vertex_data new_v (vv, cc, nn, aa, v[0]->ambient, v[0]->diffuse, + v[0]->specular, v[0]->specular_exp); + tmp_vdata.push_back (new_v); + + *out_data = new_v.get_rep (); + } + +private: + opengl_renderer *renderer; + int color_mode; // 0: uni, 1: flat, 2: interp + int light_mode; // 0: none, 1: flat, 2: gouraud + int index; + bool first; + std::list<vertex_data> tmp_vdata; +}; + +void +opengl_renderer::draw (const graphics_object& go) +{ + if (! go.valid_object ()) + return; + + const base_properties& props = go.get_properties (); + + if (go.isa ("figure")) + draw (dynamic_cast<const figure::properties&> (props)); + else if (go.isa ("axes")) + draw (dynamic_cast<const axes::properties&> (props)); + else if (go.isa ("line")) + draw (dynamic_cast<const line::properties&> (props)); + else if (go.isa ("surface")) + draw (dynamic_cast<const surface::properties&> (props)); + else if (go.isa ("patch")) + draw (dynamic_cast<const patch::properties&> (props)); + else if (go.isa ("hggroup")) + draw (dynamic_cast<const hggroup::properties&> (props)); + else + warning ("opengl_renderer: cannot render object of type `%s'", + props.graphics_object_name ().c_str ()); +} + +void +opengl_renderer::draw (const figure::properties& props) +{ + backend = props.get_backend (); + + // Initialize OpenGL context + + glEnable (GL_DEPTH_TEST); + glDepthFunc (GL_LEQUAL); + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable (GL_NORMALIZE); + + // Clear background + + Matrix c = props.get_color_rgb (); + + if (c.length() >= 3) + { + glClearColor (c(0), c(1), c(2), 1); + glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + } + + // Draw children + + draw (props.get_children ()); +} + +void +opengl_renderer::draw (const axes::properties& props) +{ + // setup OpenGL transformation + + Matrix x_zlim = props.get_transform_zlim (); + Matrix x_mat1 = props.get_opengl_matrix_1 (); + Matrix x_mat2 = props.get_opengl_matrix_2 (); + + xZ1 = x_zlim(0)-(x_zlim(1)-x_zlim(0))/2; + xZ2 = x_zlim(1)+(x_zlim(1)-x_zlim(0))/2; + + int vw[4]; + glGetIntegerv (GL_VIEWPORT, vw); + + glMatrixMode (GL_MODELVIEW); + glLoadIdentity (); + glScaled(1, 1, -1); + glMultMatrixd (x_mat1.data ()); + glMatrixMode (GL_PROJECTION); + glLoadIdentity (); + glOrtho (0, vw[2], vw[3], 0, xZ1, xZ2); + glMultMatrixd (x_mat2.data ()); + glMatrixMode (GL_MODELVIEW); + + glClear (GL_DEPTH_BUFFER_BIT); + + // store axes transformation data + + xform = props.get_transform (); + + // draw axes object + + Matrix xlim = xform.xscale (props.get_xlim ().matrix_value ()); + Matrix ylim = xform.yscale (props.get_ylim ().matrix_value ()); + Matrix zlim = xform.zscale (props.get_zlim ().matrix_value ()); + double x_min = xlim(0), x_max = xlim(1); + double y_min = ylim(0), y_max = ylim(1); + double z_min = zlim(0), z_max = zlim(1); + + double xd = (props.xdir_is ("normal") ? 1 : -1); + double yd = (props.ydir_is ("normal") ? 1 : -1); + double zd = (props.zdir_is ("normal") ? 1 : -1); + + ColumnVector p1, p2, xv (3), yv (3), zv (3); + int xstate, ystate, zstate; + + xstate = ystate = zstate = AXE_ANY_DIR; + + p1 = xform.transform (x_min, (y_min+y_max)/2, (z_min+z_max)/2, false); + p2 = xform.transform (x_max, (y_min+y_max)/2, (z_min+z_max)/2, false); + xv(0) = xround (p2(0)-p1(0)); + xv(1) = xround (p2(1)-p1(1)); + xv(2) = (p2(2)-p1(2)); + if (xv(0) == 0 && xv(1) == 0) + xstate = AXE_DEPTH_DIR; + else if (xv(2) == 0) + { + if (xv(0) == 0) + xstate = AXE_VERT_DIR; + else if (xv(1) == 0) + xstate = AXE_HORZ_DIR; + } + double xPlane; + if (xv(2) == 0) + if (xv(1) == 0) + xPlane = (xv(0) > 0 ? x_max : x_min); + else + xPlane = (xv(1) < 0 ? x_max : x_min); + else + xPlane = (xv(2) < 0 ? x_min : x_max); + double xPlaneN = (xPlane == x_min ? x_max : x_min); + double fx = (x_max-x_min)/sqrt(xv(0)*xv(0)+xv(1)*xv(1)); + + p1 = xform.transform ((x_min+x_max)/2, y_min, (z_min+z_max)/2, false); + p2 = xform.transform ((x_min+x_max)/2, y_max, (z_min+z_max)/2, false); + yv(0) = xround (p2(0)-p1(0)); + yv(1) = xround (p2(1)-p1(1)); + yv(2) = (p2(2)-p1(2)); + if (yv(0) == 0 && yv(1) == 0) + ystate = AXE_DEPTH_DIR; + else if (yv(2) == 0) + { + if (yv(0) == 0) + ystate = AXE_VERT_DIR; + else if (yv(1) == 0) + ystate = AXE_HORZ_DIR; + } + double yPlane; + if (yv(2) == 0) + if (yv(1) == 0) + yPlane = (yv(0) > 0 ? y_max : y_min); + else + yPlane = (yv(1) < 0 ? y_max : y_min); + else + yPlane = (yv(2) < 0 ? y_min : y_max); + double yPlaneN = (yPlane == y_min ? y_max : y_min); + double fy = (y_max-y_min)/sqrt(yv(0)*yv(0)+yv(1)*yv(1)); + + p1 = xform.transform((x_min+x_max)/2, (y_min+y_max)/2, z_min, false); + p2 = xform.transform((x_min+x_max)/2, (y_min+y_max)/2, z_max, false); + zv(0) = xround(p2(0)-p1(0)); + zv(1) = xround (p2(1)-p1(1)); + zv(2) = (p2(2)-p1(2)); + if (zv(0) == 0 && zv(1) == 0) + zstate = AXE_DEPTH_DIR; + else if (zv(2) == 0) + { + if (zv(0) == 0) + zstate = AXE_VERT_DIR; + else if (zv(1) == 0) + zstate = AXE_HORZ_DIR; + } + double zPlane; + if (zv(2) == 0) + if (zv(1) == 0) + zPlane = (zv(0) > 0 ? z_min : z_max); + else + zPlane = (zv(1) < 0 ? z_min : z_max); + else + zPlane = (zv(2) < 0 ? z_min : z_max); + double zPlaneN = (zPlane == z_min ? z_max : z_min); + double fz = (z_max-z_min)/sqrt(zv(0)*zv(0)+zv(1)*zv(1)); + + bool mode2d = (((xstate > AXE_DEPTH_DIR ? 1 : 0) + + (ystate > AXE_DEPTH_DIR ? 1 : 0) + + (zstate > AXE_DEPTH_DIR ? 1 : 0)) == 2); + if (props.tickdirmode_is ("auto")) + { + // FIXME: tickdir should be updated (code below comes + // from JHandles) + //autoMode++; + //TickDir.set(mode2d ? "in" : "out", true); + //autoMode--; + } + + // FIXME: use ticklength property + double xticklen = 7, yticklen = 7, zticklen = 7; + + //double tickdir = (props.tickdir_is ("in") ? -1 : 1); + double tickdir = (props.tickdirmode_is ("auto") ? + (mode2d ? -1 : 1) : + (props.tickdir_is ("in") ? -1 : 1)); + double xtickoffset = (mode2d && tickdir < 0 ? 0 : xticklen) + 5; + double ytickoffset = (mode2d && tickdir < 0 ? 0 : yticklen) + 5; + double ztickoffset = (mode2d && tickdir < 0 ? 0 : zticklen) + 5; + + bool xySym = (xd*yd*(xPlane-xPlaneN)*(yPlane-yPlaneN) > 0); + bool x2Dtop = false; + bool y2Dright = false; + double zpTick = zPlane; + + /* 2D mode */ + if (xstate == AXE_HORZ_DIR && ystate == AXE_VERT_DIR) + { + if (props.xaxislocation_is ("top")) + { + double tmp = yPlane; + yPlane = yPlaneN; + yPlaneN = tmp; + x2Dtop = true; + } + if (props.yaxislocation_is ("right")) + { + double tmp = xPlane; + xPlane = xPlaneN; + xPlaneN = tmp; + y2Dright = true; + } + if (props.layer_is ("top")) + zpTick = zPlaneN; + } + + Matrix axe_color = props.get_color_rgb (); + bool visible = props.is_visible (); + bool box = props.is_box (); + + // Axes planes + + if (axe_color.numel () > 0 && visible) + { + set_color (axe_color); + set_polygon_offset (true, 2.5); + + glBegin (GL_QUADS); + + // X plane + glVertex3d (xPlane, y_min, z_min); + glVertex3d (xPlane, y_max, z_min); + glVertex3d (xPlane, y_max, z_max); + glVertex3d (xPlane, y_min, z_max); + + // Y plane + glVertex3d (x_min, yPlane, z_min); + glVertex3d (x_max, yPlane, z_min); + glVertex3d (x_max, yPlane, z_max); + glVertex3d (x_min, yPlane, z_max); + + // Z plane + glVertex3d (x_min, y_min, zPlane); + glVertex3d (x_max, y_min, zPlane); + glVertex3d (x_max, y_max, zPlane); + glVertex3d (x_min, y_max, zPlane); + + glEnd (); + + set_polygon_offset (false); + } + + // Axes box + + set_linestyle ("-", true); + set_linewidth (props.get_linewidth ()); + + if (visible) + { + glBegin (GL_LINES); + + // X box + set_color (props.get_xcolor_rgb ()); + glVertex3d (xPlaneN, yPlaneN, zPlane); + glVertex3d (xPlane, yPlaneN, zPlane); + if (box) + { + glVertex3d (xPlaneN, yPlane, zPlane); + glVertex3d (xPlane, yPlane, zPlane); + glVertex3d (xPlaneN, yPlane, zPlaneN); + glVertex3d (xPlane, yPlane, zPlaneN); + glVertex3d (xPlaneN, yPlaneN, zPlaneN); + glVertex3d (xPlane, yPlaneN, zPlaneN); + } + + // Y box + set_color (props.get_ycolor_rgb ()); + glVertex3d (xPlaneN, yPlaneN, zPlane); + glVertex3d (xPlaneN, yPlane, zPlane); + if (box) + { + glVertex3d (xPlane, yPlaneN, zPlane); + glVertex3d (xPlane, yPlane, zPlane); + glVertex3d (xPlane, yPlaneN, zPlaneN); + glVertex3d (xPlane, yPlane, zPlaneN); + glVertex3d (xPlaneN, yPlaneN, zPlaneN); + glVertex3d (xPlaneN, yPlane, zPlaneN); + } + + // Z box + set_color (props.get_zcolor_rgb ()); + if (xySym) + { + glVertex3d (xPlaneN, yPlane, zPlaneN); + glVertex3d (xPlaneN, yPlane, zPlane); + } + else + { + glVertex3d (xPlane, yPlaneN, zPlaneN); + glVertex3d (xPlane, yPlaneN, zPlane); + } + if (box) + { + glVertex3d (xPlane, yPlane, zPlaneN); + glVertex3d (xPlane, yPlane, zPlane); + if (xySym) + { + glVertex3d (xPlane, yPlaneN, zPlaneN); + glVertex3d (xPlane, yPlaneN, zPlane); + } + else + { + glVertex3d (xPlaneN, yPlane, zPlaneN); + glVertex3d (xPlaneN, yPlane, zPlane); + } + glVertex3d (xPlaneN, yPlaneN, zPlaneN); + glVertex3d (xPlaneN, yPlaneN, zPlane); + } + + glEnd (); + } + + std::string gridstyle = props.get_gridlinestyle (); + std::string minorgridstyle = props.get_minorgridlinestyle (); + + // X grid + + if (visible && xstate != AXE_DEPTH_DIR) + { + bool do_xgrid = (props.is_xgrid () && (gridstyle != "none")); + bool do_xminorgrid = (props.is_xminorgrid () && (minorgridstyle != "none")); + bool do_xminortick = props.is_xminortick (); + Matrix xticks = xform.xscale (props.get_xtick ().matrix_value ()); + // FIXME: use pre-computed minor ticks + Matrix xmticks; + // FIXME: use xticklabels property + string_vector xticklabels; + int wmax = 0, hmax = 0; + bool tick_along_z = xisinf (fy); + Matrix tickpos (xticks.numel (), 3); + + set_color (props.get_xcolor_rgb ()); + + // grid lines + if (do_xgrid) + { + set_linestyle (gridstyle, true); + glBegin (GL_LINES); + for (int i = 0; i < xticks.numel (); i++) + { + double xval = xticks(i); + + glVertex3d (xval, yPlaneN, zpTick); + glVertex3d (xval, yPlane, zpTick); + if (zstate != AXE_DEPTH_DIR) + { + glVertex3d (xval, yPlane, zPlaneN); + glVertex3d (xval, yPlane, zPlane); + } + } + glEnd (); + set_linestyle ("-", true); + } + + // tick marks + if (tick_along_z) + { + glBegin (GL_LINES); + for (int i = 0; i < xticks.numel (); i++) + { + double xval = xticks(i); + + glVertex3d (xval, yPlaneN, zPlane); + glVertex3d (xval, yPlaneN, zPlane+signum(zPlane-zPlaneN)*fz*xticklen*tickdir); + if (box && xstate != AXE_ANY_DIR) + { + glVertex3d (xval, yPlaneN, zPlaneN); + glVertex3d (xval, yPlaneN, + zPlaneN+signum(zPlaneN-zPlane)*fz*xticklen*tickdir); + } + tickpos(i,0) = xval; + tickpos(i,1) = yPlaneN; + tickpos(i,2) = zPlane+signum(zPlane-zPlaneN)*fz*xtickoffset; + } + glEnd (); + } + else + { + glBegin (GL_LINES); + for (int i = 0; i < xticks.numel (); i++) + { + double xval = xticks(i); + + glVertex3d (xval, yPlaneN, zpTick); + glVertex3d (xval, yPlaneN+signum(yPlaneN-yPlane)*fy*xticklen*tickdir, zpTick); + if (box && xstate != AXE_ANY_DIR) + { + glVertex3d (xval, yPlane, zpTick); + glVertex3d (xval, + yPlane+signum(yPlane-yPlaneN)*fy*xticklen*tickdir, zpTick); + } + tickpos(i,0) = xval; + tickpos(i,1) = yPlaneN+signum(yPlaneN-yPlane)*fy*xtickoffset; + tickpos(i,2) = zPlane; + } + glEnd (); + } + + // FIXME: tick texts + + // minor grid lines + if (do_xminorgrid) + { + set_linestyle (minorgridstyle, true); + glBegin (GL_LINES); + for (int i = 0; i < xmticks.numel (); i++) + { + double xval = xmticks(i); + + glVertex3d (xval, yPlaneN, zpTick); + glVertex3d (xval, yPlane, zpTick); + if (zstate != AXE_DEPTH_DIR) + { + glVertex3d (xval, yPlane, zPlaneN); + glVertex3d (xval, yPlane, zPlane); + } + } + glEnd (); + set_linestyle ("-", true); + } + + // minor tick marks + if (do_xminortick) + { + if (tick_along_z) + { + glBegin (GL_LINES); + for (int i = 0; i < xmticks.numel (); i++) + { + double xval = xmticks(i); + + glVertex3d (xval, yPlaneN, zPlane); + glVertex3d (xval, yPlaneN, + zPlane+signum(zPlane-zPlaneN)*fz*xticklen/2*tickdir); + if (box && xstate != AXE_ANY_DIR) + { + glVertex3d (xval, yPlaneN, zPlaneN); + glVertex3d (xval, yPlaneN, + zPlaneN+signum(zPlaneN-zPlane)*fz*xticklen/2*tickdir); + } + } + glEnd (); + } + else + { + glBegin (GL_LINES); + for (int i = 0; i < xmticks.numel (); i++) + { + double xval = xmticks(i); + + glVertex3d (xval, yPlaneN, zpTick); + glVertex3d (xval, + yPlaneN+signum(yPlaneN-yPlane)*fy*xticklen/2*tickdir, zpTick); + if (box && xstate != AXE_ANY_DIR) + { + glVertex3d (xval, yPlane, zpTick); + glVertex3d (xval, + yPlane+signum(yPlane-yPlaneN)*fy*xticklen/2*tickdir, zpTick); + } + } + glEnd (); + } + } + + text::properties& xlabel_props = + reinterpret_cast<text::properties&> (gh_manager::get_object (props.get_xlabel ()).get_properties ()); + + // FIXME: auto-positioning should be disabled if the + // label has been positioned manually + if (! xlabel_props.get_string ().empty ()) + { + xlabel_props.set_horizontalalignment (xstate > AXE_DEPTH_DIR ? "center" : (xySym ? "left" : "right")); + xlabel_props.set_verticalalignment (xstate == AXE_VERT_DIR ? "bottom" : (zd*zv(2) <= 0 ? "top" : "bottom")); + + double angle = 0; + ColumnVector p = graphics_xform::xform_vector ((x_min+x_max)/2, yPlaneN, zPlane); + + if (tick_along_z) + p(2) += (signum(zPlane-zPlaneN)*fz*xtickoffset); + else + p(1) += (signum(yPlaneN-yPlane)*fy*xtickoffset); + p = xform.transform (p(0), p(1), p(2), false); + switch (xstate) + { + case AXE_ANY_DIR: + p(0) += (xySym ? wmax : -wmax); + p(1) += (zd*zv(2) <= 0 ? hmax : -hmax); + break; + case AXE_VERT_DIR: + p(0) -= wmax; + angle = 90; + break; + case AXE_HORZ_DIR: + p(1) += hmax; + break; + } + p = xform.untransform (p(0), p(1), p(2), true); + xlabel_props.set_position (p.extract_n (0, 3).transpose ()); + xlabel_props.set_rotation (angle); + } + } + + // Y grid + + if (ystate != AXE_DEPTH_DIR && visible) + { + bool do_ygrid = (props.is_ygrid () && (gridstyle != "none")); + bool do_yminorgrid = (props.is_yminorgrid () && (minorgridstyle != "none")); + bool do_yminortick = props.is_yminortick (); + Matrix yticks = xform.yscale (props.get_ytick ().matrix_value ()); + // FIXME: use pre-computed minor ticks + Matrix ymticks; + // FIXME: use yticklabels property + string_vector yticklabels; + int wmax = 0, hmax = 0; + bool tick_along_z = xisinf (fx); + Matrix tickpos (yticks.numel (), 3); + + set_color (props.get_ycolor_rgb ()); + + // grid lines + if (do_ygrid) + { + set_linestyle (gridstyle, true); + glBegin (GL_LINES); + for (int i = 0; i < yticks.numel (); i++) + { + double yval = yticks(i); + + glVertex3d (xPlaneN, yval, zpTick); + glVertex3d (xPlane, yval, zpTick); + if (zstate != AXE_DEPTH_DIR) + { + glVertex3d (xPlane, yval, zPlaneN); + glVertex3d (xPlane, yval, zPlane); + } + } + glEnd (); + set_linestyle ("-", true); + } + + // tick marks + if (tick_along_z) + { + glBegin (GL_LINES); + for (int i = 0; i < yticks.numel (); i++) + { + double yval = yticks(i); + + glVertex3d (xPlaneN, yval, zPlane); + glVertex3d (xPlaneN, yval, zPlane+signum(zPlane-zPlaneN)*fz*yticklen*tickdir); + if (box && ystate != AXE_ANY_DIR) + { + glVertex3d (xPlaneN, yval, zPlaneN); + glVertex3d (xPlaneN, yval, + zPlaneN+signum(zPlaneN-zPlane)*fz*yticklen*tickdir); + } + tickpos(i,0) = xPlaneN; + tickpos(i,1) = yval; + tickpos(i,2) = zPlane+signum(zPlane-zPlaneN)*fz*ytickoffset; + } + glEnd (); + } + else + { + glBegin (GL_LINES); + for (int i = 0; i < yticks.numel (); i++) + { + double yval = yticks(i); + + glVertex3d (xPlaneN, yval, zpTick); + glVertex3d (xPlaneN+signum(xPlaneN-xPlane)*fx*yticklen*tickdir, yval, zpTick); + if (box && ystate != AXE_ANY_DIR) + { + glVertex3d (xPlane, yval, zpTick); + glVertex3d (xPlane+signum(xPlane-xPlaneN)*fx*yticklen*tickdir, + yval, zpTick); + } + tickpos(i,0) = xPlaneN+signum(xPlaneN-xPlane)*fx*ytickoffset; + tickpos(i,1) = yval; + tickpos(i,2) = zPlane; + } + glEnd (); + } + + // FIXME: tick texts + + // minor grid lines + if (do_yminorgrid) + { + set_linestyle (minorgridstyle, true); + glBegin (GL_LINES); + for (int i = 0; i < ymticks.numel (); i++) + { + double yval = ymticks(i); + + glVertex3d (xPlaneN, yval, zpTick); + glVertex3d (xPlane, yval, zpTick); + if (zstate != AXE_DEPTH_DIR) + { + glVertex3d (xPlane, yval, zPlaneN); + glVertex3d (xPlane, yval, zPlane); + } + } + glEnd (); + set_linestyle ("-", true); + } + + // minor tick marks + if (do_yminortick) + { + if (tick_along_z) + { + glBegin (GL_LINES); + for (int i = 0; i < ymticks.numel (); i++) + { + double yval = ymticks(i); + + glVertex3d (xPlaneN, yval, zPlane); + glVertex3d (xPlaneN, yval, + zPlane+signum(zPlane-zPlaneN)*fz*yticklen/2*tickdir); + if (box && ystate != AXE_ANY_DIR) + { + glVertex3d (xPlaneN, yval, zPlaneN); + glVertex3d (xPlaneN, yval, + zPlaneN+signum(zPlaneN-zPlane)*fz*yticklen/2*tickdir); + } + } + glEnd (); + } + else + { + glBegin (GL_LINES); + for (int i = 0; i < ymticks.numel (); i++) + { + double yval = ymticks(i); + + glVertex3d (xPlaneN, yval, zpTick); + glVertex3d (xPlaneN+signum(xPlaneN-xPlane)*fx*yticklen/2*tickdir, + yval, zpTick); + if (box && ystate != AXE_ANY_DIR) + { + glVertex3d (xPlane, yval, zpTick); + glVertex3d (xPlane+signum(xPlane-xPlaneN)*fx*yticklen/2*tickdir, + yval, zpTick); + } + } + glEnd (); + } + } + + text::properties& ylabel_props = + reinterpret_cast<text::properties&> (gh_manager::get_object (props.get_ylabel ()).get_properties ()); + + // FIXME: auto-positioning should be disabled if the + // label has been positioned manually + if (! ylabel_props.get_string ().empty ()) + { + ylabel_props.set_horizontalalignment (ystate > AXE_DEPTH_DIR ? "center" : (!xySym ? "left" : "right")); + ylabel_props.set_verticalalignment (ystate == AXE_VERT_DIR ? "bottom" : (zd*zv(2) <= 0 ? "top" : "bottom")); + + double angle = 0; + ColumnVector p = graphics_xform::xform_vector (xPlaneN, (y_min+y_max)/2, zPlane); + + if (tick_along_z) + p(2) += (signum(zPlane-zPlaneN)*fz*ytickoffset); + else + p(0) += (signum(xPlaneN-xPlane)*fx*ytickoffset); + p = xform.transform (p(0), p(1), p(2), false); + switch (ystate) + { + case AXE_ANY_DIR: + p(0) += (!xySym ? wmax : -wmax); + p(1) += (zd*zv(2) <= 0 ? hmax : -hmax); + break; + case AXE_VERT_DIR: + p(0) -= wmax; + angle = 90; + break; + case AXE_HORZ_DIR: + p(1) += hmax; + break; + } + p = xform.untransform(p(0), p(1), p(2), true); + ylabel_props.set_position (p.extract_n (0, 3).transpose ()); + ylabel_props.set_rotation (angle); + } + } + + // Z Grid + + if (zstate != AXE_DEPTH_DIR && visible) + { + bool do_zgrid = (props.is_zgrid () && (gridstyle != "none")); + bool do_zminorgrid = (props.is_zminorgrid () && (minorgridstyle != "none")); + bool do_zminortick = props.is_zminortick (); + Matrix zticks = xform.zscale (props.get_ztick ().matrix_value ()); + // FIXME: use pre-computed minor ticks + Matrix zmticks; + // FIXME: use zticklabels property + string_vector zticklabels; + int wmax = 0, hmax = 0; + Matrix tickpos (zticks.numel (), 3); + + set_color (props.get_zcolor_rgb ()); + + // grid lines + if (do_zgrid) + { + set_linestyle (gridstyle, true); + glBegin (GL_LINES); + for (int i = 0; i < zticks.numel (); i++) + { + double zval = zticks(i); + + glVertex3d (xPlaneN, yPlane, zval); + glVertex3d (xPlane, yPlane, zval); + glVertex3d (xPlane, yPlaneN, zval); + glVertex3d (xPlane, yPlane, zval); + } + glEnd (); + set_linestyle ("-", true); + } + + // tick marks + if (xySym) + { + if (xisinf (fy)) + { + glBegin (GL_LINES); + for (int i = 0; i < zticks.numel (); i++) + { + double zval = zticks(i); + + glVertex3d (xPlaneN, yPlane, zval); + glVertex3d (xPlaneN+signum(xPlaneN-xPlane)*fx*zticklen*tickdir, + yPlane, zval); + if (box && zstate != AXE_ANY_DIR) + { + glVertex3d (xPlane, yPlane, zval); + glVertex3d (xPlane+signum(xPlane-xPlaneN)*fx*zticklen*tickdir, + yPlane, zval); + } + tickpos(i,0) = xPlaneN+signum(xPlaneN-xPlane)*fx*ztickoffset; + tickpos(i,1) = yPlane; + tickpos(i,2) = zval; + } + glEnd (); + } + else + { + glBegin (GL_LINES); + for (int i = 0; i < zticks.numel (); i++) + { + double zval = zticks(i); + + glVertex3d (xPlaneN, yPlane, zval); + glVertex3d (xPlaneN, yPlane+signum(yPlane-yPlaneN)*fy*zticklen*tickdir, zval); + tickpos(i,0) = xPlaneN; + tickpos(i,1) = yPlane+signum(yPlane-yPlaneN)*fy*ztickoffset; + tickpos(i,2) = zval; + } + glEnd (); + } + } + else + { + if (xisinf (fx)) + { + glBegin (GL_LINES); + for (int i = 0; i < zticks.numel (); i++) + { + double zval = zticks(i); + + glVertex3d (xPlane, yPlaneN, zval); + glVertex3d (xPlane, yPlaneN+signum(yPlaneN-yPlane)*fy*zticklen*tickdir, zval); + if (box && zstate != AXE_ANY_DIR) + { + glVertex3d (xPlane, yPlane, zval); + glVertex3d (xPlane, yPlane+signum(yPlane-yPlaneN)*fy*zticklen*tickdir, zval); + } + tickpos(i,0) = xPlane; + tickpos(i,1) = yPlaneN+signum(yPlaneN-yPlane)*fy*ztickoffset; + tickpos(i,2) = zval; + } + glEnd (); + } + else + { + glBegin (GL_LINES); + for (int i = 0; i < zticks.numel (); i++) + { + double zval = zticks(i); + + glVertex3d (xPlane, yPlaneN, zval); + glVertex3d (xPlane+signum(xPlane-xPlaneN)*fx*zticklen*tickdir, yPlaneN, zval); + tickpos(i,0) = xPlane+signum(xPlane-xPlaneN)*fx*ztickoffset; + tickpos(i,1) = yPlaneN; + tickpos(i,2) = zval; + } + glEnd (); + } + } + + // FIXME: tick texts + + // minor grid lines + if (do_zminorgrid) + { + set_linestyle (minorgridstyle, true); + glBegin (GL_LINES); + for (int i = 0; i < zmticks.numel (); i++) + { + double zval = zmticks(i); + + glVertex3d (xPlaneN, yPlane, zval); + glVertex3d (xPlane, yPlane, zval); + glVertex3d (xPlane, yPlaneN, zval); + glVertex3d (xPlane, yPlane, zval); + } + glEnd (); + set_linestyle ("-", true); + } + + // minor tick marks + if (do_zminortick) + { + if (xySym) + { + if (xisinf (fy)) + { + glBegin (GL_LINES); + for (int i = 0; i < zmticks.numel (); i++) + { + double zval = zmticks(i); + + glVertex3d (xPlaneN, yPlane, zval); + glVertex3d (xPlaneN+signum(xPlaneN-xPlane)*fx*zticklen/2*tickdir, + yPlane, zval); + if (box && zstate != AXE_ANY_DIR) + { + glVertex3d (xPlane, yPlane, zval); + glVertex3d (xPlane+signum(xPlane-xPlaneN)*fx*zticklen/2*tickdir, + yPlane, zval); + } + } + glEnd (); + } + else + { + glBegin (GL_LINES); + for (int i = 0; i < zmticks.numel (); i++) + { + double zval = zmticks(i); + + glVertex3d (xPlaneN, yPlane, zval); + glVertex3d (xPlaneN, yPlane+signum(yPlane-yPlaneN)*fy*zticklen/2*tickdir, zval); + } + glEnd (); + } + } + else + { + if (xisinf (fx)) + { + glBegin (GL_LINES); + for (int i = 0; i < zmticks.numel (); i++) + { + double zval = zmticks(i); + + glVertex3d (xPlane, yPlaneN, zval); + glVertex3d (xPlane, yPlaneN+signum(yPlaneN-yPlane)*fy*zticklen/2*tickdir, zval); + if (box && zstate != AXE_ANY_DIR) + { + glVertex3d (xPlane, yPlane, zval); + glVertex3d (xPlane, yPlane+signum(yPlane-yPlaneN)*fy*zticklen/2*tickdir, zval); + } + } + glEnd (); + } + else + { + glBegin (GL_LINES); + for (int i = 0; i < zmticks.numel (); i++) + { + double zval = zmticks(i); + + glVertex3d (xPlane, yPlaneN, zval); + glVertex3d (xPlane+signum(xPlane-xPlaneN)*fx*zticklen/2*tickdir, yPlaneN, zval); + } + glEnd (); + } + } + } + + text::properties& zlabel_props = + reinterpret_cast<text::properties&> (gh_manager::get_object (props.get_zlabel ()).get_properties ()); + + // FIXME: auto-positioning should be disabled if the + // label has been positioned manually + if (! zlabel_props.get_string ().empty ()) + { + bool camAuto = props.cameraupvectormode_is ("auto"); + + zlabel_props.set_horizontalalignment ((zstate > AXE_DEPTH_DIR || camAuto) ? "center" : "right"); + zlabel_props.set_verticalalignment(zstate == AXE_VERT_DIR ? "bottom" : ((zd*zv(2) < 0 || camAuto) ? "bottom" : "top")); + + double angle = 0; + ColumnVector p; + + if (xySym) + { + p = graphics_xform::xform_vector (xPlaneN, yPlane, (z_min+z_max)/2); + if (xisinf (fy)) + p(0) += (signum(xPlaneN-xPlane)*fx*ztickoffset); + else + p(1) += (signum(yPlane-yPlaneN)*fy*ztickoffset); + } + else + { + p = graphics_xform::xform_vector (xPlane, yPlaneN, (z_min+z_max)/2); + if (xisinf (fx)) + p(1) += (signum(yPlaneN-yPlane)*fy*ztickoffset); + else + p(0) += (signum(xPlane-xPlaneN)*fx*ztickoffset); + } + p = xform.transform (p(0), p(1), p(2), false); + switch (zstate) + { + case AXE_ANY_DIR: + if (camAuto) + { + p(0) -= wmax; + angle = 90; + } + /* FIXME: what's the correct offset? + p[0] += (!xySym ? wmax : -wmax); + p[1] += (zd*zv[2] <= 0 ? hmax : -hmax); + */ + break; + case AXE_VERT_DIR: + p(0) -= wmax; + angle = 90; + break; + case AXE_HORZ_DIR: + p(1) += hmax; + break; + } + p = xform.untransform (p(0), p(1), p(2), true); + zlabel_props.set_position (p.extract_n (0, 3).transpose ()); + zlabel_props.set_rotation (angle); + } + } + + set_linestyle ("-"); + + // Title + + text::properties& title_props = + reinterpret_cast<text::properties&> (gh_manager::get_object (props.get_title ()).get_properties ()); + + // FIXME: auto-positioning should be disabled if the + // title has been positioned manually + if (! title_props.get_string ().empty ()) + { + Matrix bb = props.get_boundingbox (true); + ColumnVector p = xform.untransform (bb(0)+bb(2)/2, (bb(1)-10), + (x_zlim(0)+x_zlim(1))/2, true); + title_props.set_position (p.extract_n(0, 3).transpose ()); + } + + set_clipbox (x_min, x_max, y_min, y_max, z_min, z_max); + + // Children + + Matrix children = props.get_children (); + std::list<graphics_object> obj_list; + std::list<graphics_object>::iterator it; + + // 1st pass: draw light objects + + for (int i = 0; i < children.numel (); i++) + { + graphics_object go = gh_manager::get_object (children (i)); + + if (go.get_properties ().is_visible ()) + { + if (go.isa ("light")) + draw (go); + else + obj_list.push_back (go); + } + } + + // 2nd pass: draw other objects (with units set to "data") + + it = obj_list.begin (); + while (it != obj_list.end ()) + { + graphics_object go = (*it); + + // FIXME: check whether object has "units" property and it is set to "data" + if (! go.isa ("text") || go.get ("units").string_value () == "data") + { + set_clipping (go.get_properties ().is_clipping ()); + draw (go); + + it = obj_list.erase (it); + } + else + it++; + } + + // 3rd pass: draw remaining objects + + for (it = obj_list.begin (); it != obj_list.end (); it++) + { + graphics_object go = (*it); + + set_clipping (go.get_properties ().is_clipping ()); + draw (go); + } + + set_clipping (false); + // FIXME: finalize rendering (transparency processing) + // FIXME: draw zoom box, if needed +} + +void +opengl_renderer::draw (const line::properties& props) +{ + Matrix x = xform.xscale (props.get_xdata ().matrix_value ()); + Matrix y = xform.yscale (props.get_ydata ().matrix_value ()); + Matrix z = xform.zscale (props.get_zdata ().matrix_value ()); + + bool has_z = (z.numel () > 0); + int n = static_cast<int> (::xmin (::xmin (x.numel (), y.numel ()), (has_z ? z.numel () : INT_MAX))); + octave_uint8 clip_mask = (props.is_clipping () ? 0x7F : 0x40), clip_ok (0x40); + + std::vector<octave_uint8> clip (n); + + if (has_z) + for (int i = 0; i < n; i++) + clip[i] = (clip_code (x(i), y(i), z(i)) & clip_mask); + else + { + double z_mid = (zmin+zmax)/2; + + for (int i = 0; i < n; i++) + clip[i] = (clip_code (x(i), y(i), z_mid) & clip_mask); + } + + if (! props.linestyle_is ("none")) + { + set_color (props.get_color_rgb ()); + set_linestyle (props.get_linestyle (), false); + set_linewidth (props.get_linewidth ()); + + if (has_z) + { + bool flag = false; + + for (int i = 1; i < n; i++) + { + if ((clip[i-1] & clip[i]) == clip_ok) + { + if (! flag) + { + flag = true; + glBegin (GL_LINE_STRIP); + glVertex3d (x(i-1), y(i-1), z(i-1)); + } + glVertex3d (x(i), y(i), z(i)); + } + else if (flag) + { + flag = false; + glEnd (); + } + } + + if (flag) + glEnd (); + } + else + { + bool flag = false; + + for (int i = 1; i < n; i++) + { + if ((clip[i-1] & clip[i]) == clip_ok) + { + if (! flag) + { + flag = true; + glBegin (GL_LINE_STRIP); + glVertex2d (x(i-1), y(i-1)); + } + glVertex2d (x(i), y(i)); + } + else if (flag) + { + flag = false; + glEnd (); + } + } + + if (flag) + glEnd (); + } + + set_linewidth (0.5); + set_linestyle ("-"); + } + + set_clipping (false); + + if (! props.marker_is ("none") && + ! (props.markeredgecolor_is ("none") + && props.markerfacecolor_is ("none"))) + { + Matrix lc, fc; + + if (props.markeredgecolor_is ("auto")) + lc = props.get_color_rgb (); + else if (! props.markeredgecolor_is ("none")) + lc = props.get_markeredgecolor_rgb (); + + if (props.markerfacecolor_is ("auto")) + fc = props.get_color_rgb (); + else if (! props.markerfacecolor_is ("none")) + fc = props.get_markerfacecolor_rgb (); + + init_marker (props.get_marker (), props.get_markersize (), + props.get_linewidth ()); + + for (int i = 0; i < n; i++) + { + if (clip[i] == clip_ok) + draw_marker (x(i), y(i), (has_z ? z(i) : 0), lc, fc); + } + + end_marker (); + } + + set_clipping (props.is_clipping ()); +} + +void +opengl_renderer::draw (const surface::properties& props) +{ + Matrix x = xform.xscale (props.get_xdata ().matrix_value ()); + Matrix y = xform.yscale (props.get_ydata ().matrix_value ()); + Matrix z = xform.zscale (props.get_zdata ().matrix_value ()); + + int zr = z.rows (), zc = z.columns (); + + NDArray c; + NDArray n = props.get_vertexnormals ().array_value (); + + // FIXME: handle transparency + Matrix a; + + if (props.facelighting_is ("phong") || props.edgelighting_is ("phong")) + warning ("opengl_renderer::draw: phong light model not supported"); + + int fc_mode = (props.facecolor_is_rgb () ? 0 : + (props.facecolor_is ("flat") ? 1 : + (props.facecolor_is ("interp") ? 2 : + (props.facecolor_is ("texturemap") ? 3 : -1)))); + int fl_mode = (props.facelighting_is ("none") ? 0 : + (props.facelighting_is ("flat") ? 1 : 2)); + int fa_mode = (props.facealpha_is_double () ? 0 : + (props.facealpha_is ("flat") ? 1 : 2)); + int ec_mode = (props.edgecolor_is_rgb () ? 0 : + (props.edgecolor_is ("flat") ? 1 : + (props.edgecolor_is ("interp") ? 2 : -1))); + int el_mode = (props.edgelighting_is ("none") ? 0 : + (props.edgelighting_is ("flat") ? 1 : 2)); + int ea_mode = (props.edgealpha_is_double () ? 0 : + (props.edgealpha_is ("flat") ? 1 : 2)); + + Matrix fcolor = (fc_mode == 3 ? Matrix (1, 3, 1.0) : props.get_facecolor_rgb ()); + Matrix ecolor = props.get_edgecolor_rgb (); + + float as = props.get_ambientstrength (); + float ds = props.get_diffusestrength (); + float ss = props.get_specularstrength (); + float se = props.get_specularexponent (); + float cb[4] = { 0, 0, 0, 1 }; + + opengl_texture tex; + + int i1, i2, j1, j2; + bool x_mat = (x.rows () == z.rows ()); + bool y_mat = (y.columns () == z.columns ()); + + i1 = i2 = j1 = j2 = 0; + + boolMatrix clip (z.dims (), false); + + for (int i = 0; i < zr; i++) + { + if (x_mat) + i1 = i; + + for (int j = 0; j < zc; j++) + { + if (y_mat) + j1 = j; + + clip(i,j) = is_nan_or_inf (x(i1,j), y(i,j1), z(i,j)); + } + } + + if ((fc_mode > 0 && fc_mode < 3) || ec_mode > 0) + c = props.get_color_data ().array_value (); + + if (fa_mode > 0 || ea_mode > 0) + { + // FIXME: implement alphadata conversion + //a = props.get_alpha_data (); + } + + if (fl_mode > 0 || el_mode > 0) + { + float buf[4] = { ss, ss, ss, 1 }; + + glMaterialfv (LIGHT_MODE, GL_SPECULAR, buf); + glMaterialf (LIGHT_MODE, GL_SHININESS, se); + } + + // FIXME: good candidate for caching, transfering pixel + // data to OpenGL is time consuming. + if (fc_mode == 3) + tex = opengl_texture::create (props.get_color_data ()); + + if (! props.facecolor_is ("none")) + { + if (props.get_facealpha_double () == 1) + { + if (fc_mode == 0 || fc_mode == 3) + { + glColor3dv (fcolor.data ()); + if (fl_mode > 0) + { + for (int i = 0; i < 3; i++) + cb[i] = (as * fcolor(i)); + glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb); + + for (int i = 0; i < 3; i++) + cb[i] *= (ds / as); + glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb); + } + } + + if (fl_mode > 0) + glEnable (GL_LIGHTING); + glShadeModel ((fc_mode == 2 || fl_mode == 2) ? GL_SMOOTH : GL_FLAT); + set_polygon_offset (true, 1); + if (fc_mode == 3) + glEnable (GL_TEXTURE_2D); + + for (int i = 1; i < zc; i++) + { + if (y_mat) + { + i1 = i-1; + i2 = i; + } + + for (int j = 1; j < zr; j++) + { + if (clip(j-1, i-1) || clip (j, i-1) + || clip (j-1, i) || clip (j, i)) + continue; + + if (x_mat) + { + j1 = j-1; + j2 = j; + } + + glBegin (GL_QUADS); + + // Vertex 1 + if (fc_mode == 3) + tex.tex_coord (double (i-1) / (zc-1), double (j-1) / (zr-1)); + else if (fc_mode > 0) + { + // FIXME: is there a smarter way to do this? + for (int k = 0; k < 3; k++) + cb[k] = c(j-1, i-1, k); + glColor3fv (cb); + + if (fl_mode > 0) + { + for (int k = 0; k < 3; k++) + cb[k] *= as; + glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb); + + for (int k = 0; k < 3; k++) + cb[k] *= (ds / as); + glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb); + } + } + if (fl_mode > 0) + glNormal3d (n(j-1,i-1,0), n(j-1,i-1,1), n(j-1,i-1,2)); + glVertex3d (x(j1,i-1), y(j-1,i1), z(j-1,i-1)); + + // Vertex 2 + if (fc_mode == 3) + tex.tex_coord (double (i) / (zc-1), double (j-1) / (zr-1)); + else if (fc_mode == 2) + { + for (int k = 0; k < 3; k++) + cb[k] = c(j-1, i, k); + glColor3fv (cb); + + if (fl_mode > 0) + { + for (int k = 0; k < 3; k++) + cb[k] *= as; + glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb); + + for (int k = 0; k < 3; k++) + cb[k] *= (ds / as); + glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb); + } + } + if (fl_mode == 2) + glNormal3d (n(j-1,i,0), n(j-1,i,1), n(j-1,i,2)); + glVertex3d (x(j1,i), y(j-1,i2), z(j-1,i)); + + // Vertex 3 + if (fc_mode == 3) + tex.tex_coord (double (i) / (zc-1), double (j) / (zr-1)); + else if (fc_mode == 2) + { + for (int k = 0; k < 3; k++) + cb[k] = c(j, i, k); + glColor3fv (cb); + + if (fl_mode > 0) + { + for (int k = 0; k < 3; k++) + cb[k] *= as; + glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb); + + for (int k = 0; k < 3; k++) + cb[k] *= (ds / as); + glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb); + } + } + if (fl_mode == 2) + glNormal3d (n(j,i,0), n(j,i,1), n(j,i,2)); + glVertex3d (x(j2,i), y(j,i2), z(j,i)); + + // Vertex 4 + if (fc_mode == 3) + tex.tex_coord (double (i-1) / (zc-1), double (j) / (zr-1)); + else if (fc_mode == 2) + { + for (int k = 0; k < 3; k++) + cb[k] = c(j, i-1, k); + glColor3fv (cb); + + if (fl_mode > 0) + { + for (int k = 0; k < 3; k++) + cb[k] *= as; + glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb); + + for (int k = 0; k < 3; k++) + cb[k] *= (ds / as); + glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb); + } + } + if (fl_mode == 2) + glNormal3d (n(j,i-1,0), n(j,i-1,1), n(j,i-1,2)); + glVertex3d (x(j2,i-1), y(j,i1), z(j,i-1)); + + glEnd (); + } + } + + set_polygon_offset (false); + if (fc_mode == 3) + glDisable (GL_TEXTURE_2D); + + if (fl_mode > 0) + glDisable (GL_LIGHTING); + } + else + { + // FIXME: implement transparency + } + } + + if (! props.edgecolor_is ("none")) + { + if (props.get_edgealpha_double () == 1) + { + if (ec_mode == 0) + { + glColor3dv (ecolor.data ()); + if (fl_mode > 0) + { + for (int i = 0; i < 3; i++) + cb[i] = (as * ecolor(i)); + glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb); + + for (int i = 0; i < 3; i++) + cb[i] *= (ds / as); + glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb); + } + } + + if (el_mode > 0) + glEnable (GL_LIGHTING); + glShadeModel ((ec_mode == 2 || el_mode == 2) ? GL_SMOOTH : GL_FLAT); + + set_linestyle (props.get_linestyle (), false); + set_linewidth (props.get_linewidth ()); + + // Mesh along Y-axis + + if (props.meshstyle_is ("both") || props.meshstyle_is ("column")) + { + for (int i = 0; i < zc; i++) + { + if (y_mat) + { + i1 = i-1; + i2 = i; + } + + for (int j = 1; j < zr; j++) + { + if (clip(j-1,i) || clip(j,i)) + continue; + + if (x_mat) + { + j1 = j-1; + j2 = j; + } + + glBegin (GL_LINES); + + // Vertex 1 + if (ec_mode > 0) + { + for (int k = 0; k < 3; k++) + cb[k] = c(j-1, i, k); + glColor3fv (cb); + + if (fl_mode > 0) + { + for (int k = 0; k < 3; k++) + cb[k] *= as; + glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb); + + for (int k = 0; k < 3; k++) + cb[k] *= (ds / as); + glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb); + } + } + if (el_mode > 0) + glNormal3d (n(j-1,i,0), n(j-1,i,1), n(j-1,i,2)); + glVertex3d (x(j1,i), y(j-1,i2), z(j-1,i)); + + // Vertex 2 + if (ec_mode == 2) + { + for (int k = 0; k < 3; k++) + cb[k] = c(j, i, k); + glColor3fv (cb); + + if (fl_mode > 0) + { + for (int k = 0; k < 3; k++) + cb[k] *= as; + glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb); + + for (int k = 0; k < 3; k++) + cb[k] *= (ds / as); + glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb); + } + } + if (el_mode == 2) + glNormal3d (n(j,i,0), n(j,i,1), n(j,i,2)); + glVertex3d (x(j2,i), y(j,i2), z(j,i)); + + glEnd (); + } + } + } + + // Mesh along X-axis + + if (props.meshstyle_is ("both") || props.meshstyle_is ("row")) + { + for (int j = 0; j < zr; j++) + { + if (x_mat) + { + j1 = j-1; + j2 = j; + } + + for (int i = 1; i < zc; i++) + { + if (clip(j,i-1) || clip(j,i)) + continue; + + if (y_mat) + { + i1 = i-1; + i2 = i; + } + + glBegin (GL_LINES); + + // Vertex 1 + if (ec_mode > 0) + { + for (int k = 0; k < 3; k++) + cb[k] = c(j, i-1, k); + glColor3fv (cb); + + if (fl_mode > 0) + { + for (int k = 0; k < 3; k++) + cb[k] *= as; + glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb); + + for (int k = 0; k < 3; k++) + cb[k] *= (ds / as); + glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb); + } + } + if (el_mode > 0) + glNormal3d (n(j,i-1,0), n(j,i-1,1), n(j,i-1,2)); + glVertex3d (x(j2,i-1), y(j,i1), z(j,i-1)); + + // Vertex 2 + if (ec_mode == 2) + { + for (int k = 0; k < 3; k++) + cb[k] = c(j, i, k); + glColor3fv (cb); + + if (fl_mode > 0) + { + for (int k = 0; k < 3; k++) + cb[k] *= as; + glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb); + + for (int k = 0; k < 3; k++) + cb[k] *= (ds / as); + glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb); + } + } + if (el_mode == 2) + glNormal3d (n(j,i,0), n(j,i,1), n(j,i,2)); + glVertex3d (x(j2,i), y(j,i2), z(j,i)); + + glEnd (); + } + } + } + + set_linestyle ("-"); + set_linewidth (0.5); + + if (el_mode > 0) + glDisable (GL_LIGHTING); + } + else + { + // FIXME: implement transparency + } + } + + if (! props.marker_is ("none") && + ! (props.markeredgecolor_is ("none") + && props.markerfacecolor_is ("none"))) + { + // FIXME: check how transparency should be handled in markers + // FIXME: check what to do with marker facecolor set to auto + // and facecolor set to none. + + bool do_edge = ! props.markeredgecolor_is ("none"); + bool do_face = ! props.markerfacecolor_is ("none"); + + Matrix mecolor = props.get_markeredgecolor_rgb (); + Matrix mfcolor = props.get_markerfacecolor_rgb (); + Matrix cc (1, 3, 0.0); + + if (mecolor.numel () == 0 && props.markeredgecolor_is ("auto")) + { + mecolor = props.get_edgecolor_rgb (); + do_edge = ! props.edgecolor_is ("none"); + } + + if (mfcolor.numel () == 0 && props.markerfacecolor_is ("auto")) + { + mfcolor = props.get_facecolor_rgb (); + do_face = ! props.facecolor_is ("none"); + } + + if ((mecolor.numel () == 0 || mfcolor.numel () == 0) + && c.numel () == 0) + c = props.get_color_data ().array_value (); + + init_marker (props.get_marker (), props.get_markersize (), + props.get_linewidth ()); + + for (int i = 0; i < zc; i++) + { + if (y_mat) + i1 = i; + + for (int j = 0; j < zr; j++) + { + if (clip(j,i)) + continue; + + if (x_mat) + j1 = j; + + if ((do_edge && mecolor.numel () == 0) + || (do_face && mfcolor.numel () == 0)) + { + for (int k = 0; k < 3; k++) + cc(k) = c(j,i,k); + } + + Matrix lc = (do_edge ? (mecolor.numel () == 0 ? cc : mecolor) : Matrix ()); + Matrix fc = (do_face ? (mfcolor.numel () == 0 ? cc : mfcolor) : Matrix ()); + + draw_marker (x(j1,i), y(j,i1), z(j,i), lc, fc); + } + } + + end_marker (); + } +} + +// FIXME: global optimization (rendering, data structures...), there +// is probably a smarter/faster/less-memory-consuming way to do this. +void +opengl_renderer::draw (const patch::properties &props) +{ + Matrix f = props.get_faces ().matrix_value (); + Matrix v = xform.scale (props.get_vertices ().matrix_value ()); + Matrix c; + Matrix n = props.get_vertexnormals ().matrix_value (); + Matrix a; + + int nv = v.rows (); + // int vmax = v.columns (); + int nf = f.rows (); + int fcmax = f.columns (); + + bool has_z = (v.columns () > 2); + bool has_facecolor = false; + bool has_facealpha = false; + + int fc_mode = (props.facecolor_is_rgb () ? 0 : + (props.facecolor_is("flat") ? 1 : 2)); + int fl_mode = (props.facelighting_is ("none") ? 0 : + (props.facelighting_is ("flat") ? 1 : 2)); + int fa_mode = (props.facealpha_is_double () ? 0 : + (props.facealpha_is ("flat") ? 1 : 2)); + int ec_mode = (props.edgecolor_is_rgb () ? 0 : + (props.edgecolor_is("flat") ? 1 : 2)); + int el_mode = (props.edgelighting_is ("none") ? 0 : + (props.edgelighting_is ("flat") ? 1 : 2)); + int ea_mode = (props.edgealpha_is_double () ? 0 : + (props.edgealpha_is ("flat") ? 1 : 2)); + + Matrix fcolor = props.get_facecolor_rgb (); + Matrix ecolor = props.get_edgecolor_rgb (); + + float as = props.get_ambientstrength (); + float ds = props.get_diffusestrength (); + float ss = props.get_specularstrength (); + float se = props.get_specularexponent (); + + boolMatrix clip (1, nv, false); + + if (has_z) + for (int i = 0; i < nv; i++) + clip(i) = is_nan_or_inf (v(i,0), v(i,1), v(i,2)); + else + for (int i = 0; i < nv; i++) + clip(i) = is_nan_or_inf (v(i,0), v(i,1), 0); + + boolMatrix clip_f (1, nf, false); + Array<int> count_f (nf, 0); + + for (int i = 0; i < nf; i++) + { + bool fclip = false; + int count = 0; + + for (int j = 0; j < fcmax && ! xisnan (f(i,j)); j++, count++) + fclip = (fclip || clip(int (f(i,j) - 1))); + + clip_f(i) = fclip; + count_f(i) = count; + } + + if (fc_mode > 0 || ec_mode > 0) + { + c = props.get_color_data ().matrix_value (); + + if (c.rows () == 1) + { + // Single color specifications, we can simplify a little bit + + if (fc_mode > 0) + { + fcolor = c; + fc_mode = 0; + } + + if (ec_mode > 0) + { + ecolor = c; + ec_mode = 0; + } + + c = Matrix (); + } + else + has_facecolor = ((c.numel () > 0) && (c.rows () == f.rows ())); + } + + if (fa_mode > 0 || ea_mode > 0) + { + // FIXME: retrieve alpha data from patch object + //a = props.get_alpha_data (); + has_facealpha = ((a.numel () > 0) && (a.rows () == f.rows ())); + } + + Array2<vertex_data> vdata (f.dims ()); + + for (int i = 0; i < nf; i++) + for (int j = 0; j < count_f(i); j++) + { + int idx = int (f(i,j) - 1); + + Matrix vv (1, 3, 0.0); + Matrix cc; + Matrix nn(1, 3, 0.0); + double aa = 1.0; + + vv(0) = v(idx,0); vv(1) = v(idx,1); + if (has_z) + vv(2) = v(idx,2); + // FIXME: uncomment when patch object has normal computation + //nn(0) = n(idx,0); nn(1) = n(idx,1); nn(2) = n(idx,2); + if (c.numel () > 0) + { + cc.resize (1, 3); + if (has_facecolor) + cc(0) = c(i,0), cc(1) = c(i,1), cc(2) = c(i,2); + else + cc(0) = c(idx,0), cc(1) = c(idx,1), cc(2) = c(idx,2); + } + if (a.numel () > 0) + { + if (has_facealpha) + aa = a(i); + else + aa = a(idx); + } + + vdata(i,j) = + vertex_data (vv, cc, nn, aa, as, ds, ss, se); + } + + if (fl_mode > 0 || el_mode > 0) + { + float buf[4] = { ss, ss, ss, 1 }; + + glMaterialfv (LIGHT_MODE, GL_SPECULAR, buf); + glMaterialf (LIGHT_MODE, GL_SHININESS, se); + } + + if (! props.facecolor_is ("none")) + { + // FIXME: adapt to double-radio property + if (props.get_facealpha_double () == 1) + { + if (fc_mode == 0) + { + glColor3dv (fcolor.data ()); + if (fl_mode > 0) + { + float cb[4] = { 0, 0, 0, 1 }; + + for (int i = 0; i < 3; i++) + cb[i] = (as * fcolor(i)); + glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb); + + for (int i = 0; i < 3; i++) + cb[i] *= (ds / as); + glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb); + } + } + + if (fl_mode > 0) + glEnable (GL_LIGHTING); + + // FIXME: use __index__ property from patch object + patch_tesselator tess (this, fc_mode, fl_mode, 0); + + for (int i = 0; i < nf; i++) + { + if (clip_f(i)) + continue; + + tess.begin_polygon (true); + tess.begin_contour (); + + for (int j = 0; j < count_f(i); j++) + { + vertex_data::vertex_data_rep *vv = vdata(i,j).get_rep (); + + tess.add_vertex (vv->coords.fortran_vec (), vv); + } + + tess.end_contour (); + tess.end_polygon (); + } + + if (fl_mode > 0) + glDisable (GL_LIGHTING); + } + else + { + // FIXME: implement transparency + } + } + + if (! props.edgecolor_is ("none")) + { + // FIXME: adapt to double-radio property + if (props.get_edgealpha_double () == 1) + { + if (ec_mode == 0) + { + glColor3dv (ecolor.data ()); + if (el_mode > 0) + { + float cb[4] = { 0, 0, 0, 1 }; + + for (int i = 0; i < 3; i++) + cb[i] = (as * ecolor(i)); + glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb); + + for (int i = 0; i < 3; i++) + cb[i] *= (ds / as); + glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb); + } + } + + if (el_mode > 0) + glEnable (GL_LIGHTING); + + set_linestyle (props.get_linestyle (), false); + set_linewidth (props.get_linewidth ()); + + // FIXME: use __index__ property from patch object; should we + // offset patch contour as well? + patch_tesselator tess (this, ec_mode, el_mode); + + for (int i = 0; i < nf; i++) + { + if (clip_f(i)) + continue; + + tess.begin_polygon (false); + tess.begin_contour (); + + for (int j = 0; j < count_f(i); j++) + { + vertex_data::vertex_data_rep *vv = vdata(i,j).get_rep (); + + tess.add_vertex (vv->coords.fortran_vec (), vv); + } + + tess.end_contour (); + tess.end_polygon (); + } + + set_linestyle ("-"); + set_linewidth (0.5); + + if (el_mode > 0) + glDisable (GL_LIGHTING); + } + else + { + // FIXME: implement transparency + } + } + + if (! props.marker_is ("none") && + ! (props.markeredgecolor_is ("none") && props.markerfacecolor_is ("none"))) + { + bool do_edge = ! props.markeredgecolor_is ("none"); + bool do_face = ! props.markerfacecolor_is ("none"); + + Matrix mecolor = props.get_markeredgecolor_rgb (); + Matrix mfcolor = props.get_markerfacecolor_rgb (); + Matrix cc (1, 3, 0.0); + + if (mecolor.numel () == 0 && props.markeredgecolor_is ("auto")) + { + mecolor = props.get_edgecolor_rgb (); + do_edge = ! props.edgecolor_is ("none"); + } + + if (mfcolor.numel () == 0 && props.markerfacecolor_is ("auto")) + { + mfcolor = props.get_facecolor_rgb (); + do_face = ! props.facecolor_is ("none"); + } + + init_marker (props.get_marker (), props.get_markersize (), + props.get_linewidth ()); + + for (int i = 0; i < nf; i++) + for (int j = 0; j < count_f(i); j++) + { + int idx = int (f(i,j) - 1); + + if (clip(idx)) + continue; + + Matrix lc = (do_edge ? (mecolor.numel () == 0 ? + vdata(i,j).get_rep ()->color : mecolor) + : Matrix ()); + Matrix fc = (do_face ? (mfcolor.numel () == 0 ? + vdata(i,j).get_rep ()->color : mfcolor) + : Matrix ()); + + draw_marker (v(idx,0), v(idx,1), (has_z ? v(idx,2) : 0), lc, fc); + } + + end_marker (); + } +} + +void +opengl_renderer::draw (const hggroup::properties &props) +{ + draw (props.get_children ()); +} + +void +opengl_renderer::set_viewport (int w, int h) +{ + glViewport (0, 0, w, h); +} + +void +opengl_renderer::set_color (const Matrix& c) +{ + glColor3dv (c.data ()); +} + +void +opengl_renderer::set_polygon_offset (bool on, double offset) +{ + if (on) + { + glPolygonOffset (offset, offset); + glEnable (GL_POLYGON_OFFSET_FILL); + } + else + glDisable (GL_POLYGON_OFFSET_FILL); +} + +void +opengl_renderer::set_linewidth (float w) +{ + glLineWidth (w); +} + +void +opengl_renderer::set_linestyle (const std::string& s, bool use_stipple) +{ + bool solid = false; + + if (s == "-") + { + glLineStipple (1, static_cast<unsigned short> (0xFFFF)); + solid = true; + } + else if (s == ":") + glLineStipple (1, static_cast<unsigned short> (0x8888)); + else if (s == "--") + glLineStipple (1, static_cast<unsigned short> (0x0FFF)); + else if (s == "-.") + glLineStipple (1, static_cast<unsigned short> (0x020F)); + else + glLineStipple (1, static_cast<unsigned short> (0x0000)); + + if (solid && ! use_stipple) + glDisable (GL_LINE_STIPPLE); + else + glEnable (GL_LINE_STIPPLE); +} + +void +opengl_renderer::set_clipbox (double x1, double x2, double y1, double y2, + double z1, double z2) +{ + double dx = (x2-x1); + double dy = (y2-y1); + double dz = (z2-z1); + + x1 -= 0.001*dx; x2 += 0.001*dx; + y1 -= 0.001*dy; y2 += 0.001*dy; + z1 -= 0.001*dz; z2 += 0.001*dz; + + ColumnVector p (4, 0.0); + + p(0) = -1; p(3) = x2; + glClipPlane (GL_CLIP_PLANE0, p.data ()); + p(0) = 1; p(3) = -x1; + glClipPlane (GL_CLIP_PLANE1, p.data ()); + p(0) = 0; p(1) = -1; p(3) = y2; + glClipPlane (GL_CLIP_PLANE2, p.data ()); + p(1) = 1; p(3) = -y1; + glClipPlane (GL_CLIP_PLANE3, p.data ()); + p(1) = 0; p(2) = -1; p(3) = z2; + glClipPlane (GL_CLIP_PLANE4, p.data ()); + p(2) = 1; p(3) = -z1; + glClipPlane (GL_CLIP_PLANE5, p.data ()); + + xmin = x1; xmax = x2; + ymin = y1; ymax = y2; + zmin = z1; zmax = z2; +} + +void +opengl_renderer::set_clipping (bool enable) +{ + bool has_clipping = (glIsEnabled (GL_CLIP_PLANE0) == GL_TRUE); + + if (enable != has_clipping) + { + if (enable) + for (int i = 0; i < 6; i++) + glEnable (GL_CLIP_PLANE0+i); + else + for (int i = 0; i < 6; i++) + glDisable (GL_CLIP_PLANE0+i); + } +} + +void +opengl_renderer::init_marker (const std::string& m, double size, float width) +{ + int vw[4]; + + glGetIntegerv (GL_VIEWPORT, vw); + + glMatrixMode (GL_PROJECTION); + glPushMatrix (); + glLoadIdentity (); + glOrtho (0, vw[2], vw[3], 0, xZ1, xZ2); + glMatrixMode (GL_MODELVIEW); + glPushMatrix (); + + set_clipping (false); + set_linewidth (width); + + marker_id = make_marker_list (m, size, false); + filled_marker_id = make_marker_list (m, size, true); +} + +void +opengl_renderer::end_marker (void) +{ + glDeleteLists (marker_id, 1); + glDeleteLists (filled_marker_id, 1); + + glMatrixMode (GL_MODELVIEW); + glPopMatrix (); + glMatrixMode (GL_PROJECTION); + glPopMatrix (); + set_linewidth (0.5f); +} + +void +opengl_renderer::draw_marker (double x, double y, double z, + const Matrix& lc, const Matrix& fc) +{ + ColumnVector tmp = xform.transform (x, y, z, false); + + glLoadIdentity (); + glTranslated (tmp(0), tmp(1), -tmp(2)); + + if (fc.numel () > 0) + { + glColor3dv (fc.data ()); + set_polygon_offset (true, 1.0); + glCallList (filled_marker_id); + set_polygon_offset (false); + } + + if (lc.numel () > 0) + { + glColor3dv (lc.data ()); + glCallList (marker_id); + } +} + +unsigned int +opengl_renderer::make_marker_list (const std::string& marker, double size, + bool filled) const +{ + unsigned int ID = glGenLists (1); + double sz = size * backend.get_screen_resolution () / 72.0; + + // constants for the * marker + const double sqrt2d4 = 0.35355339059327; + double tt = sz*sqrt2d4; + + glNewList (ID, GL_COMPILE); + + switch (marker[0]) + { + case '+': + glBegin (GL_LINES); + glVertex2f (-sz/2 ,0 ); + glVertex2f (sz/2 ,0 ); + glVertex2f (0 ,-sz/2 ); + glVertex2f (0 ,sz/2 ); + glEnd (); + break; + case 'x': + glBegin(GL_LINES); + glVertex2f (-sz/2 ,-sz/2); + glVertex2f (sz/2 ,sz/2 ); + glVertex2f (-sz/2 ,sz/2 ); + glVertex2f (sz/2 ,-sz/2 ); + glEnd (); + break; + case '*': + glBegin (GL_LINES); + glVertex2f (-sz/2 ,0 ); + glVertex2f (sz/2 ,0 ); + glVertex2f (0 ,-sz/2 ); + glVertex2f (0 ,sz/2 ); + glVertex2f (-tt ,-tt ); + glVertex2f (+tt ,+tt ); + glVertex2f (-tt ,+tt ); + glVertex2f (+tt ,-tt ); + glEnd (); + break; + case '.': + glBegin (GL_POLYGON); + glVertex2f (-sz/10, -sz/10); + glVertex2f (-sz/10, sz/10 ); + glVertex2f (sz/10 , sz/10 ); + glVertex2f (sz/10 , -sz/10); + glEnd (); + break; + case 's': + glBegin ((filled ? GL_POLYGON : GL_LINE_LOOP)); + glVertex2d (-sz/2, -sz/2); + glVertex2d (-sz/2, sz/2); + glVertex2d ( sz/2, sz/2); + glVertex2d ( sz/2, -sz/2); + glEnd(); + break; + case 'o': + { + double ang_step = M_PI / 5; + + glBegin ((filled ? GL_POLYGON : GL_LINE_LOOP)); + for (double ang = 0; ang < (2*M_PI); ang += ang_step) + glVertex2d (sz*cos(ang)/2, sz*sin(ang)/2); + glEnd (); + } + break; + case 'd': + glBegin ((filled ? GL_POLYGON : GL_LINE_LOOP)); + glVertex2d ( 0, -sz/2); + glVertex2d ( sz/2, 0); + glVertex2d ( 0, sz/2); + glVertex2d (-sz/2, 0); + glEnd(); + break; + case '^': + glBegin ((filled ? GL_POLYGON : GL_LINE_LOOP)); + glVertex2f (0 , sz/2); + glVertex2f (sz/2 , -sz/2); + glVertex2f (-sz/2 , -sz/2); + glEnd (); + break; + case 'v': + glBegin ((filled ? GL_POLYGON : GL_LINE_LOOP)); + glVertex2f (0 ,-sz/2); + glVertex2f (-sz/2 ,sz/2 ); + glVertex2f (sz/2 ,sz/2 ); + glEnd (); + break; + case '>': + glBegin ((filled ? GL_POLYGON : GL_LINE_LOOP)); + glVertex2f (sz/2 ,0 ); + glVertex2f (-sz/2 ,sz/2 ); + glVertex2f (-sz/2 ,-sz/2); + glEnd (); + break; + case '<': + glBegin ((filled ? GL_POLYGON : GL_LINE_LOOP)); + glVertex2f (-sz/2 ,0 ); + glVertex2f (sz/2 ,-sz/2); + glVertex2f (sz/2 ,sz/2 ); + glEnd (); + default: + warning ("opengl_renderer: unsupported marker `%s'", + marker.c_str ()); + break; + } + + glEndList (); + + return ID; +} + +/* +;;; Local Variables: *** +;;; mode: C++ *** +;;; End: *** +*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/gl-render.h Thu Jun 05 18:00:37 2008 -0400 @@ -0,0 +1,138 @@ +/* + +Copyright (C) 2008 Michael Goffioul + +This file is part of Octave. + +Octave is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3 of the License, or (at your +option) any later version. + +Octave is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +<http://www.gnu.org/licenses/>. + +*/ + +#if !defined (gl_render_h) +#define gl_render_h 1 + +#include "config.h" + +#ifdef HAVE_WINDOWS_H +#include <windows.h> +#endif + +#include <GL/gl.h> +#include <GL/glu.h> + +#include "graphics.h" + +class +OCTGRAPHICS_API +opengl_renderer +{ +public: + opengl_renderer (void) { } + + virtual ~opengl_renderer (void) { } + + virtual void draw (const graphics_handle& h) + { draw (gh_manager::get_object (h)); } + + virtual void draw (const graphics_object& go); + + virtual void draw (const Matrix& hlist) + { + int len = hlist.length (); + + for (int i = 0; i < len; i++) + { + graphics_handle h = gh_manager::lookup (hlist(i)); + + if (h.ok ()) + draw (h); + } + } + + virtual void set_viewport (int w, int h); + +protected: + virtual void draw (const figure::properties& props); + virtual void draw (const axes::properties& props); + virtual void draw (const line::properties& props); + virtual void draw (const surface::properties& props); + virtual void draw (const patch::properties& props); + virtual void draw (const hggroup::properties& props); + + virtual void set_color (const Matrix& c); + virtual void set_polygon_offset (bool on, double offset = 0.0); + virtual void set_linewidth (float w); + virtual void set_linestyle (const std::string& s, bool stipple = false); + virtual void set_clipbox (double x1, double x2, double y1, double y2, + double z1, double z2); + virtual void set_clipping (bool on); + + virtual void init_marker (const std::string& m, double size, float width); + virtual void end_marker (void); + virtual void draw_marker (double x, double y, double z, + const Matrix& lc, const Matrix& fc); + +private: + opengl_renderer (const opengl_renderer&) { } + + opengl_renderer& operator = (const opengl_renderer&) + { return *this; } + + bool is_nan_or_inf (double x, double y, double z) const + { + return (xisnan (x) || xisnan (y) || xisnan (z) + || xisinf (x) || xisinf (y) || xisinf (z)); + } + + octave_uint8 clip_code (double x, double y, double z) const + { + return ((x < xmin ? 1 : 0) + | (x > xmax ? 1 : 0) << 1 + | (y < ymin ? 1 : 0) << 2 + | (y > ymax ? 1 : 0) << 3 + | (z < zmin ? 1 : 0) << 4 + | (z > zmax ? 1 : 0) << 5 + | (is_nan_or_inf (x, y, z) ? 0 : 1) << 6); + } + + unsigned int make_marker_list (const std::string& m, double size, + bool filled) const; + +private: + // the backend associated with the figure being rendered + graphics_backend backend; + + // axes transformation data + graphics_xform xform; + + // axis limits in model scaled coordinate + double xmin, xmax; + double ymin, ymax; + double zmin, zmax; + + // Z projection limits in windows coordinate + double xZ1, xZ2; + + // call lists identifiers for markers + unsigned int marker_id, filled_marker_id; + + // camera information for primitive sorting + ColumnVector camera_pos, camera_dir; + +private: + class patch_tesselator; +}; + +#endif
--- a/src/graphics/ChangeLog Thu Jun 05 20:42:14 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,182 +0,0 @@ -2008-06-05 John W. Eaton <jwe@octave.org> - - * opengl/gl-render.cc (xmin): New static function. - - * opengl/gl-render.h (opengl_renderer): Style fixes. - * fltk_backend/fltk_backend.cc: Style fixes. - -2008-04-26 Michael Goffioul <michael.goffioul@gmail.com> - - * opengl/gl-render.h (opengl_renderer::draw(hggroup)): New method. - * opengl/gl-render.cc (opengl_renderer::draw(hggroup)): Likewise. - (opengl_renderer::draw(graphics_object)): Call it. - -2008-03-17 Shai Ayal <shaiay@users.sourceforge.net> - - * fltk_backend/fltk_backend.cc (plot_window::resize, - plot_window::draw): make canvas the size of figure.position - -2008-03-09 Shai Ayal <shaiay@users.sourceforge.net> - - * fltk_backend/fltk_backend.cc (plot_window::handle): add zoom - stack - -2008-03-06 Shai Ayal <shaiay@users.sourceforge.net> - - * fltk_backend/fltk_backend.cc (plot_window::handle): Add handling - of the 'a' and 'g' keys - (plot_window: toggle_grid): New helper function - (plot_window): Add new togglegrid button - -2008-03-01 Shai Ayal <shaiay@users.sourceforge.net> - - * fltk_backend/fltk_backend.cc (OpenGL_fltk::draw_overlay, - OpenGL_fltk::zoom, OpenGL_fltk::set_zoom_box): Added to support - zoom box - (plot_window::handle): Added zoom box code, B-3 now does autoscale - (plot_window::axis_auto): New utility function to call axis("auto") - (plot_window::button_press): "A" button now does autoscale - - * opengl/gl-render.cc (make_marker_list): Add the "+x*.^v><" - markers - -2008-02-27 Michael Goffioul <michael.goffioul@gmail.com> - - * opengl/gl-render.cc (opengl_renderer::draw(patch), - opengl_renderer::draw(surface)): Adapt to type change of facealpha and - edgealpha, using double_radio_property class. - -2008-02-26 Michael Goffioul <michael.goffioul@gmail.com> - - * opengl/gl-render.h: Make sure windows.h is included before OpenGL - headers. - * fltk_backend/Makefile.in (FLTK_EXTRA_CXXFLAGS): Use $(srcdir) for - includesion of OpenGL renderer headers. - (Makeconf): Move inclusion of Makeconf later on, to avoid freezing - MinGW make. - - * fltk_backend/Makefile.in (GRAPHICS_CFLAGS): New substituted - variable. - -2008-02-25 Shai Ayal <shaiay@users.sourceforge.net> - - * fltk_backend/fltk_backend.cc (class plot_window): Many changes - to use figure::properties instead of figure handle to reference - the figure - (class figure_manager): ditto - (__fltk_redraw__): moved most of functionality into the - figure_manager class - (plot_window::pixel2pos): Modified to use axes::pixel2coord - (plot_window::pixel2staus): Modified to use pixel2pos - (plot_window::handle): Added zoom with mouse - -2008-02-24 Shai Ayal <shaiay@users.sourceforge.net> - - * fltk_backend/fltk_backend.cc (OpenGL_fltk::Draw): removed double - buffer switch - (OpenGL_fltk::setup_viewport): removed call to glOrtho -- - gl-render takes care of all the transformations - -2008-02-23 Shai Ayal <shaiay@users.sourceforge.net> - - * fltk_backend/fltk_backend.cc (plot_window::mark_modifed): mark - the whole window as damaged (otherwise changing figure.postion - does not have immediate effect) - (plot_window::draw): New function, checks for window size - (__fltk_maxtime__): New DEFUN to allow tweaking of fltk timeout - (__fltk_redraw__): Use fltk_maxtime as timeout - -2008-02-21 Michael Goffioul <michael.goffioul@gmail.com> - - * opengl/gl-render.cc (opengl_renderer::patch_tesselator::combine): - Protect against NULL vertex data. - - * opengl/gl-render.cc (opengl_renderer::draw(patch)): Add marker - rendering of patch objects. - -2008-02-21 Shai Ayal <shaiay@users.sourceforge.net> - - * opengl/gl-render.cc: remove OpenGL includes - * opengl/gl-render.h: add OpenGL includes - * fltk_backend/fltk_backend.cc: remove OpenGL includes - (__fltk_redraw__): put figure handle into the figure's - __plot_stream__ property for later - (fltk_backend::close_figure): use argument as figure handle to - close - -2008-02-20 Shai Ayal <shaiay@users.sourceforge.net> - - * fltk_backend/Makefile.in: initial import - - * fltk_backend/fltk_backend.cc: initial import - - -2008-02-20 Michael Goffioul <michael.goffioul@gmail.com> - - * opengl/gl-render.h (opengl_renderer::draw(patch)): New method to - render patch objects. - (class opengl_renderer::patch_tesselator): Forward declaration. - * opengl/gl-render.cc (opengl_texture::create): Use RGB data format - instead of RGBA. - (class opengl_tesselator): New classes to abstract GLU tessellation - process. - (class opengl_renderer::patch_tesselator): New class to render opaque - patch objects. - (class vertex_data): New class to hold vertex data during tessellation - of patch objects. - (opengl_renderer::draw(patch)): New method to render patch objects (no - transparency, no border, no marker yet). - (opengl_renderer::draw(graphics_object)): Dispatch to it. - - * opengl/gl-render.cc (opengl_renderer::draw(patch)): Use patch color - data and support face/vertex single color specification. - - * opengl/gl-render.cc (opengl_tesselator::begin_polygon): Set - tessellation property also for non-filled polygons. - (opengl_renderer::patch_tesselator::vertex): Protect against empty - color matrices. - (opengl_renderer::draw(patch)): Render patch border (no transparency - yet). - -2008-02-19 Michael Goffioul <michael.goffioul@gmail.com> - - * opengl/gl-render.cc (opengl_texture::texture_rep::tex_coord, - opengl_texture::tex_coord): New wrapper around glTexCoord2d. - (opengl_renderer::draw(surface)): Use it for texturemap - implementation. - (opengl_renderer::draw(surface)): Fix indexing bug when creating clip - matrix. - (opengl_texture::operator=): Add assignment operator. - (opengl_texture::create): New static opengl_texture creator. - (opengl_texture::is_valid): New accessor. - -2008-02-18 Michael Goffioul <michael.goffioul@gmail.com> - - * opengl/gl-render.cc (class opengl_texture): New class to wrap - texture operations in OpenGL. - -2008-02-17 Michael Goffioul <michael.goffioul@gmail.com> - - * opengl/gl-render.cc (opengl_renderer::draw(surface)): Set material - color when rendering surface facets. - - * opengl/gl-render.cc (opengl_renderer::draw(surface)): Add rendering - of mesh and markers. - -2008-02-16 Michael Goffioul <michael.goffioul@gmail.com> - - * opengl/gl-render.cc (opengl_renderer::draw(figure)): Initialize the - OpenGL context correctly. - (opengl_renderer::draw(surface)): Add missing glEnd call. - -2008-02-14 Michael Goffioul <michael.goffioul@gmail.com> - - * opengl/gl-render.h opengl/gl-render.cc: Add rendering - interface for surface objects (actual implement still - missing). - -2008-06-04 Michael Goffioul <michael.goffioul@gmail.com> - - * Makefile.in Makerules.in: Initial import - * opengl/Makefile.in: Likewise. - * opengl/gl-render.h opengl/gl-render.cc: Likewise.
--- a/src/graphics/Makefile.in Thu Jun 05 20:42:14 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,70 +0,0 @@ -# Makefile for octave's src/graphics directory -# -# Copyright (C) 2008 John W. Eaton -# -# This file is part of Octave. -# -# Octave is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by the -# Free Software Foundation; either version 3 of the License, or (at -# your option) any later version. -# -# Octave is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# for more details. -# -# You should have received a copy of the GNU General Public License -# along with Octave; see the file COPYING. If not, see -# <http://www.gnu.org/licenses/>. - -TOPDIR = ../.. - -srcdir = @srcdir@ -top_srcdir = @top_srcdir@ -VPATH = @srcdir@ - -include $(TOPDIR)/Makeconf - -INSTALL = @INSTALL@ -INSTALL_PROGRAM = @INSTALL_PROGRAM@ -INSTALL_DATA = @INSTALL_DATA@ - -GRAPHICS_DIRS = @GRAPHICS_OPENGL@ - -SUBDIRS = $(GRAPHICS_DIRS) - -DISTSUBDIRS = $(GRAPHICS_DIRS) - -CLEAN_SUBDIRS = $(DISTSUBDIRS) - -DISTFILES = Makefile.in Makerules.in - -all: $(SUBDIRS) -.PHONY: all - -$(SUBDIRS): - $(MAKE) -C $@ all -.PHONY: $(SUBDIRS) - -check: all -.PHONY: check - -install install-strip uninstall:: - @$(subdir-for-command) - -clean mostlyclean distclean maintainer-clean:: - @$(foreach d, $(CLEAN_SUBDIRS), $(do-subdir-for-command)) - -install-strip:: - $(MAKE) INSTALL_PROGRAM="$(INSTALL_PROGRAM) -s" install - -tags TAGS:: $(SOURCES) - $(SUBDIR_FOR_COMMAND) - -dist: - for dir in $(DISTSUBDIRS); do mkdir $(TOPDIR)/`cat $(TOPDIR)/.fname`/src/graphics/$$dir; $(MAKE) -C $$dir $@; done - ln $(addprefix $(srcdir)/, $(DISTFILES)) $(TOPDIR)/`cat $(TOPDIR)/.fname`/src/graphics -.PHONY: dist - -.NOTPARALLEL:
--- a/src/graphics/Makerules.in Thu Jun 05 20:42:14 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,221 +0,0 @@ -# Makefile for octave's src/graphics directory -# -# Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, -# 2002, 2003, 2004, 2005, 2006, 2007 John W. Eaton -# -# This file is part of Octave. -# -# Octave is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by the -# Free Software Foundation; either version 3 of the License, or (at -# your option) any later version. -# -# Octave is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# for more details. -# -# You should have received a copy of the GNU General Public License -# along with Octave; see the file COPYING. If not, see -# <http://www.gnu.org/licenses/>. - -include $(TOPDIR)/Makeconf - -DLL_CDEFS = @OCTGRAPHICS_DLL_DEFS@ -DLL_CXXDEFS = @OCTGRAPHICS_DLL_DEFS@ - -INSTALL = @INSTALL@ -INSTALL_PROGRAM = @INSTALL_PROGRAM@ -INSTALL_DATA = @INSTALL_DATA@ - -PT_FLAGS = -fexternal-templates -fno-implicit-templates -CXXFLAGS_NO_PT_FLAGS = $(filter-out $(PT_FLAGS), $(ALL_CXXFLAGS)) - -OCTGRAPHICS_INCS = $(GRAPHICS_INCS) - -OCTGRAPHICS_SRC = $(GRAPHICS_SRC) - -OCTGRAPHICS_BASE = $(basename $(notdir $(OCTGRAPHICS_SRC))) - -OCTGRAPHICS_OBJ = $(addsuffix .o, $(OCTGRAPHICS_BASE)) - -ifeq ($(SHARED_LIBS), true) - ifdef CXXPICFLAG - OCTGRAPHICS_PICOBJ := $(addprefix pic/, $(OCTGRAPHICS_OBJ)) - else - OCTGRAPHICS_PICOBJ := $(OCTGRAPHICS_OBJ) - endif -endif - -SOURCES := $(OCTGRAPHICS_SRC) - -# Ugh. - -DEP_1 := $(OCTGRAPHICS_SRC) -MAKEDEPS := $(patsubst %.cc, %.d, $(DEP_1)) - -OCTGRAPHICS_LINK_DEPS = \ - -L$(TOPDIR)/src $(LIBOCTINTERP) -L$(TOPDIR)/liboctave $(LIBOCTAVE) \ - -L$(TOPDIR)/libcruft $(LIBCRUFT) $(GRAPHICS_EXTRA_LIBS) $(LIBS) $(FLIBS) - -DISTFILES = $(OCTGRAPHICS_SRC) $(OCTGRAPHICS_INCS) \ - $(addprefix $(srcdir)/, Makefile.in $(SPECIAL)) - -CWD = $(shell pwd) -THISDIR = $(notdir $(CWD)) - -ifeq ($(SHARED_LIBS), true) - ifeq ($(STATIC_LIBS), true) - LIBRARIES = $(LIBPRE)$(GRAPHICS_NAME).$(LIBEXT) $(LIBPRE)$(GRAPHICS_NAME).$(SHLEXT_VER) - else - LIBRARIES = $(LIBPRE)$(GRAPHICS_NAME).$(SHLEXT_VER) - endif -else - ifeq ($(STATIC_LIBS), true) - LIBRARIES = $(LIBPRE)$(GRAPHICS_NAME).$(LIBEXT) - else - ## This is not going to work, but hey, you asked for it... - LIBRARIES = - endif -endif - -all: $(LIBRARIES) -.PHONY: all - -objects: $(OCTGRAPHICS_OBJ) - -libraries: $(LIBRARIES) -.PHONY: libraries - -$(LIBPRE)$(GRAPHICS_NAME).$(LIBEXT): $(OCTGRAPHICS_OBJ) - rm -f $@ - $(TEMPLATE_AR) $(TEMPLATE_ARFLAGS) $@ $^ - $(RANLIB) $@ - -$(LIBPRE)$(GRAPHICS_NAME).$(SHLEXT_VER): $(LIBPRE)$(GRAPHICS_NAME).$(SHLEXT) - rm -f $@ - $(LN_S) $< $@ - -$(LIBPRE)$(GRAPHICS_NAME).$(SHLEXT): $(OCTGRAPHICS_PICOBJ) - rm -f $@ - $(SH_LD) $(SH_LDFLAGS) $(SONAME_FLAGS) -o $@ $^ $(OCTGRAPHICS_LINK_DEPS) - -stmp-pic: pic - @if [ -f stmp-pic ]; then \ - true; \ - else \ - echo "touch stmp-pic"; \ - touch stmp-pic; \ - fi - -pic: - @if [ -d pic ]; then \ - true; \ - else \ - echo "mkdir pic"; \ - mkdir pic; \ - fi - -$(OCTGRAPHICS_PICOBJ): stmp-pic - -PREREQ := $(GRAPHICS_PREREQ) - -$(MAKEDEPS): $(PREREQ) - -check: all -.PHONY: check - -install: install-bin install-lib install-inc -.PHONY: install - -install-strip: - $(MAKE) INSTALL_PROGRAM="$(INSTALL_PROGRAM) -s" install -.PHONY: install-strip - -install-bin: -.PHONY: install-bin - -install-lib: - $(top_srcdir)/mkinstalldirs $(DESTDIR)$(octlibdir) - if $(STATIC_LIBS); then \ - rm -f $(DESTDIR)$(octlibdir)/$(LIBPRE)$(GRAPHICS_NAME).$(LIBEXT); \ - $(INSTALL_DATA) $(LIBPRE)$(GRAPHICS_NAME).$(LIBEXT) \ - $(DESTDIR)$(octlibdir)/$(LIBPRE)$(GRAPHICS_NAME).$(LIBEXT); \ - $(RANLIB) $(DESTDIR)$(octlibdir)/$(LIBPRE)$(GRAPHICS_NAME).$(LIBEXT); \ - fi - if $(SHARED_LIBS); then \ - rm -f $(DESTDIR)$(octlibdir)/$(LIBPRE)$(GRAPHICS_NAME).$(SHLEXT_VER); \ - $(INSTALL) $(LIBPRE)$(GRAPHICS_NAME).$(SHLLIB) \ - $(DESTDIR)$(octlibdir)/$(LIBPRE)$(GRAPHICS_NAME).$(SHLLIB_VER); \ - rm -f $(DESTDIR)$(octlibdir)/$(LIBPRE)$(GRAPHICS_NAME).$(SHLLIB); \ - (cd $(DESTDIR)$(octlibdir) ; $(LN_S) $(LIBPRE)$(GRAPHICS_NAME).$(SHLLIB_VER) $(DESTDIR)$(octlibdir)/$(LIBPRE)$(GRAPHICS_NAME).$(SHLLIB)); \ - if test x$(SHLBIN) != x ; then \ - rm -f $(DESTDIR)$(bindir)/$(LIBPRE)$(GRAPHICS_NAME).$(SHLBIN); \ - $(INSTALL_PROGRAM) \ - $(LIBPRE)$(GRAPHICS_NAME).$(SHLBIN) $(DESTDIR)$(bindir)/$(LIBPRE)$(GRAPHICS_NAME).$(SHLBIN); \ - fi; \ - fi -.PHONY: install-lib - -install-inc: - $(top_srcdir)/mkinstalldirs $(DESTDIR)$(octincludedir)/octave - for f in $(OCTGRAPHICS_INCS); do \ - rm -f $(DESTDIR)$(octincludedir)/octave/$$f; \ - if [ -f $$f ]; then \ - $(INSTALL_DATA) $$f $(DESTDIR)$(octincludedir)/octave/$$f; \ - else \ - $(INSTALL_DATA) $(srcdir)/$$f $(DESTDIR)$(octincludedir)/octave/$$f; \ - fi ; \ - done -.PHONY: install-inc - -uninstall: - rm -f $(DESTDIR)$(octlibdir)/$(LIBPRE)$(GRAPHICS_NAME).$(LIBEXT) - rm -f $(DESTDIR)$(octlibdir)/$(LIBPRE)$(GRAPHICS_NAME).$(SHLLIB) - rm -f $(DESTDIR)$(octlibdir)/$(LIBPRE)$(GRAPHICS_NAME).$(SHLLIB_VER) - if test x$(SHLBIN) != x ; then \ - rm -f $(DESTDIR)$(bindir)/$(LIBPRE)$(GRAPHICS_NAME).$(SHLBIN); \ - rm -f $(DESTDIR)$(bindir)/$(LIBPRE)$(GRAPHICS_NAME).$(SHLBIN_VER); \ - fi - for f in $(OCTGRAPHICS_INCS); do \ - rm -f $(DESTDIR)$(octincludedir)/octave/$$f; \ - done - -rmdir $(DESTDIR)$(octincludedir)/octave - -rmdir $(DESTDIR)$(octincludedir) - -rmdir $(DESTDIR)$(octlibdir) - -rmdir $(DESTDIR)$(octfiledir) -.PHONY: uninstall - -tags: $(SOURCES) $(DLD_SRC) - ctags $(SOURCES) $(DLD_SRC) - -TAGS: $(SOURCES) $(DLD_SRC) - etags $(SOURCES) $(DLD_SRC) - -clean mostlyclean distclean maintainer-clean:: - rm -f $(MAKEDEPS) $(OCTGRAPHICS_OBJ) $(OCTGRAPHICS_PICOBJ) - -rmdir pic - rm -f stmp-pic -.PHONY: clean mostlyclean - -clean:: - rm -f $(LIBPRE)$(GRAPHICS_NAME).$(LIBEXT) - rm -f $(LIBPRE)$(GRAPHICS_NAME).$(SHLEXT_VER) $(LIBPRE)$(GRAPHICS_NAME).$(SHLEXT) - -distclean maintainer-clean:: - rm -f Makefile -.PHONY: distclean - -maintainer-clean:: - rm -f tags TAGS -.PHONY: maintainer-clean - -dist: - ln $(EXTERNAL_DISTFILES) $(TOPDIR)/`cat $(TOPDIR)/.fname`/src/graphics/$(THISDIR) -.PHONY: dist - -ifdef omit_deps -.PHONY: $(MAKEDEPS) -endif - --include $(MAKEDEPS)
--- a/src/graphics/fltk_backend/Makefile.in Thu Jun 05 20:42:14 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,77 +0,0 @@ -# Makefile for octave's src/graphics/opengl directory -# -# Copyright (C) 1998, 2007 John W. Eaton -# -# This file is part of Octave. -# -# Octave is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by the -# Free Software Foundation; either version 3 of the License, or (at -# your option) any later version. -# -# Octave is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# for more details. -# -# You should have received a copy of the GNU General Public License -# along with Octave; see the file COPYING. If not, see -# <http://www.gnu.org/licenses/>. - -TOPDIR = ../../.. - -srcdir = @srcdir@ -top_srcdir = @top_srcdir@ -VPATH = @srcdir@ - -GRAPHICS_LIBS = @GRAPHICS_LIBS@ -GRAPHICS_CFLAGS = @GRAPHICS_CFLAGS@ - -include $(TOPDIR)/Makeconf - -FLTK_EXTRA_LIBS = $(OPENGL_LIBS) $(GRAPHICS_LIBS) -FLTK_EXTRA_CXXFLAGS = $(GRAPHICS_CFLAGS) -I$(srcdir)/../opengl - -FLTK_NAME = fltk_backend - -FLTK_SRC := fltk_backend.cc -FLTK_OBJ := $(patsubst %.cc, %.o, $(FLTK_SRC)) - -%.o : %.cc - $(CXX) -c $(CPPFLAGS) $(ALL_CXXFLAGS) $(FLTK_EXTRA_CXXFLAGS) $< -o $@ - -# Some stupid egreps don't like empty elements in alternation patterns, -# so we have to repeat ourselves because some stupid egreps don't like -# empty elements in alternation patterns. - -DEFUN_PATTERN = "^[ \t]*DEF(CONSTFUN|CMD|UN|UN_DLD|UNX_DLD|UN_TEXT|UN_MAPPER)[ \t]*\\(" - -DLD_DEF_FILES := $(patsubst %.cc, %.df, $(FLTK_SRC)) - -OCTAVE_LFLAGS = -L$(TOPDIR)/liboctave -L$(TOPDIR)/libcruft \ - -L$(TOPDIR)/src $(RLD_FLAG) - -ifeq ($(ENABLE_DYNAMIC_LINKING), true) - OCTAVE_LIBS = $(LIBOCTINTERP) $(LIBOCTAVE) \ - $(SPECIAL_MATH_LIB) $(LIBCRUFT) \ - $(LIBPLPLOT) $(LIBGLOB) -else - OCTAVE_LIBS = $(LIBOCTINTERP) $(LIBOCTAVE) $(QHULL_LIBS) \ - $(GLPK_LIBS) $(REGEX_LIBS) $(SPECIAL_MATH_LIB) $(LIBCRUFT) \ - $(LIBPLPLOT) $(LIBGLOB) -endif - -OCT_LINK_DEPS = \ - -L../../../libcruft $(LIBCRUFT) -L../../../liboctave $(LIBOCTAVE) \ - -L../../ $(LIBOCTINTERP) -L../opengl -loctgraphics_gl $(CHOLMOD_LIBS) $(UMFPACK_LIBS) $(AMD_LIBS) \ - $(CAMD_LIBS) $(COLAMD_LIBS) $(CCOLAMD_LIBS) $(CXSPARSE_LIBS) $(BLAS_LIBS) \ - $(FFTW_LIBS) $(LIBS) $(FLIBS) $(FLTK_EXTRA_LIBS) $(GRAPHICS_LIBS) - - -fltk_backend.oct : fltk_backend.o - $(DL_LD) $(DL_LDFLAGS) -o $@ $< $(OCT_LINK_DEPS) - -test_stuff.oct : test_stuff.o - $(DL_LD) $(DL_LDFLAGS) -o $@ $< $(OCT_LINK_DEPS) - -all : fltk_backend.oct
--- a/src/graphics/fltk_backend/fltk_backend.cc Thu Jun 05 20:42:14 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,807 +0,0 @@ -/* - -Copyright (C) 2007 Shai Ayal - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -<http://www.gnu.org/licenses/>. - -*/ - -#include <map> -#include <set> -#include <sstream> -#include <iostream> - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include "gl-render.h" - -#include <FL/Fl.H> -#include <FL/Fl_Window.H> -#include <FL/Fl_Output.H> -#include <FL/Fl_Button.H> -#include <FL/Fl_Gl_Window.H> -#include <FL/fl_ask.H> -#include <FL/fl_draw.H> -#include <FL/gl.h> - -#include "oct.h" -#include "parse.h" -#include "graphics.h" - -#define FLTK_BACKEND_NAME "fltk" - -const char* help_text = "\ -Keyboard Shortcuts\n\ -a - autoscale\n\ -g - toggle grid\n\ -\n\ -Mouse\n\ -left drag - zoom\n\ -right click - unzoom\n\ -double click - copy coordinates to clipboard\ -"; - -class OpenGL_fltk : public Fl_Gl_Window -{ -public: - OpenGL_fltk (int xx, int yy, int ww, int hh, double num) - : Fl_Gl_Window (xx, yy, ww, hh, 0), number (num), in_zoom (false) - { - // ask for double buffering and a depth buffer - mode (FL_DEPTH | FL_DOUBLE); - } - - ~OpenGL_fltk (void) { } - - void zoom (bool z) { in_zoom = z; } - bool zoom (void) { return in_zoom; } - void set_zoom_box (const Matrix& zb) { zoom_box = zb; } - -private: - double number; - opengl_renderer renderer; - bool in_zoom; - - // (x1,y1,x2,y2) - Matrix zoom_box; - - void setup_viewport (int _w, int _h) - { - glMatrixMode (GL_PROJECTION); - glLoadIdentity (); - glViewport (0, 0, _w, _h); - } - - void draw (void) - { - if (!valid ()) - { - valid (1); - setup_viewport (w (), h ()); - } - - renderer.draw (gh_manager::lookup (number)); - } - - void resize (int _x,int _y,int _w,int _h) - { - Fl_Gl_Window::resize (_x, _y, _w, _h); - setup_viewport (_w, _h); - redraw (); - } - - void draw_overlay (void) - { - if (!in_zoom) - return; - - if (!valid()) - { - valid(1); - setup_viewport (w (), h ()); - } - - glPushMatrix (); - - glMatrixMode (GL_MODELVIEW); - glLoadIdentity (); - - glMatrixMode (GL_PROJECTION); - glLoadIdentity (); - gluOrtho2D (0.0, w (), 0.0, h ()); - - glPushAttrib (GL_DEPTH_BUFFER_BIT | GL_CURRENT_BIT); - glDisable (GL_DEPTH_TEST); - - glLineWidth (1); - glBegin (GL_LINE_STRIP); - gl_color(0); - glVertex2d (zoom_box(0), h () - zoom_box(1)); - glVertex2d (zoom_box(0), h () - zoom_box(3)); - glVertex2d (zoom_box(2), h () - zoom_box(3)); - glVertex2d (zoom_box(2), h () - zoom_box(1)); - glVertex2d (zoom_box(0), h () - zoom_box(1)); - glEnd (); - - glPopAttrib (); - glPopMatrix (); - } - - int handle (int event) - { - int retval = Fl_Gl_Window::handle (event); - - switch (event) - { - case FL_ENTER: - window ()->cursor (FL_CURSOR_CROSS); - return 1; - - case FL_LEAVE: - window ()->cursor (FL_CURSOR_DEFAULT); - return 1; - } - - return retval; - } -}; - -class plot_window : public Fl_Window -{ -public: - plot_window (int _x, int _y, int _w, int _h, figure::properties& _fp) - : Fl_Window (_x, _y, _w, _h, "octave"), fp (_fp) - { - callback (window_close, static_cast<void*> (this)); - - begin (); - { - canvas = new - OpenGL_fltk (0, 0, _w , _h - status_h, number ()); - - autoscale = new - Fl_Button (0, - _h - status_h, - status_h, - status_h, - "A"); - autoscale->callback (button_callback, static_cast<void*> (this)); - - togglegrid = new - Fl_Button (status_h, - _h - status_h, - status_h, - status_h, - "G"); - togglegrid->callback (button_callback, static_cast<void*> (this)); - - help = new - Fl_Button (2*status_h, - _h - status_h, - status_h, - status_h, - "H"); - help->callback (button_callback, static_cast<void*> (this)); - - status = new - Fl_Output (3*status_h, - _h - status_h, - _w > 2*status_h ? _w - status_h : 0, - status_h, ""); - - status->textcolor (FL_BLACK); - status->color (FL_GRAY); - status->textfont (FL_COURIER); - status->textsize (10); - status->box (FL_ENGRAVED_BOX); - - // This allows us to have a valid OpenGL context right away - canvas->mode (FL_DEPTH | FL_DOUBLE ); - show (); - canvas->show (); - canvas->make_current (); - } - end (); - - status->show (); - autoscale->show (); - togglegrid->show (); - - resizable (canvas); - size_range (4*status_h, 2*status_h); - - std::stringstream name; - name << "octave: figure " << number (); - label (name.str ().c_str ()); - } - - ~plot_window (void) - { - canvas->hide (); - status->hide (); - this->hide (); - delete canvas; - delete status; - } - - // FIXME -- this could change - double number (void) { return fp.get___myhandle__ ().value (); } - - void mark_modified (void) - { - damage (FL_DAMAGE_ALL); - canvas->damage (FL_DAMAGE_ALL); - } - -private: - // figure properties - figure::properties& fp; - - // status area height - static const int status_h = 20; - - // window callback - static void window_close (Fl_Widget*, void* data) - { - octave_value_list args; - args(0) = static_cast<plot_window*> (data)->number (); - feval ("close", args); - } - - // button callbacks - static void button_callback (Fl_Widget* ww, void* data) - { - static_cast<plot_window*> (data)->button_press (ww); - } - - void button_press (Fl_Widget* widg) - { - if (widg == autoscale) - axis_auto (); - - if (widg == togglegrid) - toggle_grid (); - - if (widg == help) - fl_message (help_text); - } - - OpenGL_fltk* canvas; - Fl_Button* autoscale; - Fl_Button* togglegrid; - Fl_Button* help; - Fl_Output* status; - - void axis_auto (void) - { - octave_value_list args; - args(0) = "auto"; - feval ("axis",args); - mark_modified (); - } - - void toggle_grid (void) - { - feval ("grid"); - mark_modified (); - } - - void pixel2pos (int px, int py, double& xx, double& yy) const - { - graphics_object ax = gh_manager::get_object (fp.get_currentaxes ()); - - if (ax && ax.isa ("axes")) - { - axes::properties& ap = - dynamic_cast<axes::properties&> (ax.get_properties ()); - ColumnVector pp = ap.pixel2coord (px, py); - xx = pp(0); - yy = pp(1); - } - } - - graphics_handle pixel2axes (int /* px */, int /* py */) - { - Matrix kids = fp.get_children (); - - for (octave_idx_type n = 0; n < kids.numel (); n++) - { - graphics_object ax = gh_manager::get_object (kids (n)); - if (ax && ax.isa ("axes")) - { -#if 0 - axes::properties& ap = - dynamic_cast<axes::properties&> (ax.get_properties ()); - - // std::cout << "\npixpos="<<pixpos<<"(px,py)=("<<px<<","<<py<<")\n"; - if (px >= pixpos(0) && px <= pixpos(2) - && py >= pixpos(1) && py <= pixpos(3)) - return ap.get___myhandle__ (); -#endif - } - } - - return graphics_handle (); - } - - void pixel2status (int px0, int py0, int px1 = -1, int py1 = -1) - { - double x0, y0, x1, y1; - std::stringstream cbuf; - - pixel2pos (px0, py0, x0, y0); - cbuf << "[" << x0 << ", " << y0 << "]"; - if (px1 >= 0) - { - pixel2pos (px1, py1, x1, y1); - cbuf << " -> ["<< x1 << ", " << y1 << "]"; - } - - status->value (cbuf.str ().c_str ()); - status->redraw (); - } - - void resize (int _x,int _y,int _w,int _h) - { - Fl_Window::resize (_x, _y, _w, _h); - - Matrix pos (1,4,0); - pos(0) = _x; - pos(1) = _y; - pos(2) = _w; - pos(3) = _h - status_h; - - fp.set_position (pos); - } - - void draw (void) - { - Matrix pos = fp.get_position ().matrix_value (); - Fl_Window::resize (pos(0), pos(1) , pos(2), pos(3) + status_h); - - return Fl_Window::draw (); - } - - int handle (int event) - { - static int px0,py0; - static graphics_handle h0 = graphics_handle (); - - int retval = Fl_Window::handle (event); - - // we only handle events which are in the canvas area - if (Fl::event_y () >= h() - status_h) - return retval; - - switch (event) - { - case FL_KEYDOWN: - switch(Fl::event_key ()) - { - case 'a': - case 'A': - axis_auto (); - break; - - case 'g': - case 'G': - toggle_grid (); - break; - } - break; - - case FL_MOVE: - pixel2status (Fl::event_x (), Fl::event_y ()); - break; - - case FL_PUSH: - if (Fl::event_button () == 1) - { - px0 = Fl::event_x (); - py0 = Fl::event_y (); - h0 = pixel2axes (Fl::event_x (), Fl::event_y ()); - return 1; - } - break; - - case FL_DRAG: - pixel2status (px0, py0, Fl::event_x (), Fl::event_y ()); - if (Fl::event_button () == 1) - { - canvas->zoom (true); - Matrix zoom_box (1,4,0); - zoom_box (0) = px0; - zoom_box (1) = py0; - zoom_box (2) = Fl::event_x (); - zoom_box (3) = Fl::event_y (); - canvas->set_zoom_box (zoom_box); - canvas->redraw_overlay (); - return 1; - } - break; - - case FL_RELEASE: - if (Fl::event_button () == 1) - { - // end of drag -- zoom - if (canvas->zoom ()) - { - canvas->zoom (false); - double x0,y0,x1,y1; - graphics_object ax = - gh_manager::get_object (fp.get_currentaxes ()); - if (ax && ax.isa ("axes")) - { - axes::properties& ap = - dynamic_cast<axes::properties&> (ax.get_properties ()); - pixel2pos (px0, py0, x0, y0); - pixel2pos (Fl::event_x (), Fl::event_y (), x1, y1); - Matrix xl (1,2,0); - Matrix yl (1,2,0); - if (x0 < x1) - { - xl(0) = x0; - xl(1) = x1; - } - else - { - xl(0) = x1; - xl(1) = x0; - } - - if (y0 < y1) - { - yl(0) = y0; - yl(1) = y1; - } - else - { - yl(0) = y1; - yl(1) = y0; - } - ap.zoom (xl, yl); - mark_modified (); - } - } - // one click -- select axes - else if ( Fl::event_clicks () == 0) - { - std::cout << "ca="<< h0.value ()<<"\n"; - if (h0.ok ()) - fp.set_currentaxes (h0.value()); - return 1; - } - } - else if (Fl::event_button () == 3) - { - graphics_object ax = - gh_manager::get_object (fp.get_currentaxes ()); - if (ax && ax.isa ("axes")) - { - axes::properties& ap = - dynamic_cast<axes::properties&> (ax.get_properties ()); - ap.unzoom (); - mark_modified (); - } - } - break; - } - - return retval; - } -}; - -class figure_manager -{ -public: - - static figure_manager& Instance (void) - { - static figure_manager fm; - return fm; - } - - ~figure_manager (void) - { - close_all (); - } - - void close_all (void) - { - wm_iterator win; - for (win = windows.begin (); win != windows.end (); win++) - delete (*win).second; - windows.clear (); - } - - void new_window (figure::properties& fp) - { - int x, y, w, h; - - int idx = figprops2idx (fp); - if (idx >= 0 && windows.find (idx) == windows.end ()) - { - default_size(x,y,w,h); - idx2figprops (curr_index , fp); - windows[curr_index++] = new plot_window (x, y, w, h, fp); - } - } - - void delete_window (int idx) - { - wm_iterator win; - if ((win = windows.find (idx)) != windows.end ()) - { - delete (*win).second; - windows.erase (win); - } - } - - void delete_window (std::string idx_str) - { - delete_window (str2idx (idx_str)); - } - - void mark_modified (int idx) - { - wm_iterator win; - if ((win=windows.find (idx)) != windows.end ()) - { - (*win).second->mark_modified (); - } - } - - void mark_modified (const graphics_handle& gh) - { - mark_modified (hnd2idx (gh)); - } - - Matrix get_size (int idx) - { - Matrix sz (1, 2, 0.0); - - wm_iterator win; - if ((win = windows.find (idx)) != windows.end ()) - { - sz(0) = (*win).second->w (); - sz(1) = (*win).second->h (); - } - - return sz; - } - - Matrix get_size (const graphics_handle& gh) - { - return get_size (hnd2idx (gh)); - } - -private: - figure_manager (void) { } - figure_manager (const figure_manager&) { } - figure_manager& operator = (const figure_manager&) { return *this; } - // singelton -- hide all of the above - - static int curr_index; - typedef std::map<int, plot_window*> window_map; - typedef window_map::iterator wm_iterator;; - window_map windows; - - static std::string fltk_idx_header; - - void default_size (int& x, int& y, int& w, int& h) - { - x = 10; - y = 10; - w = 400; - h = 300; - } - - int str2idx (const caseless_str clstr) - { - int ind; - if (clstr.find (fltk_idx_header,0) == 0) - { - std::istringstream istr (clstr.substr (fltk_idx_header.size ())); - if (istr >> ind) - return ind; - } - error ("fltk_backend: could not recognize fltk index"); - return -1; - } - - void idx2figprops (int idx, figure::properties& fp) - { - std::ostringstream ind_str; - ind_str << fltk_idx_header << idx; - fp.set___plot_stream__ (ind_str.str ()); - } - - int figprops2idx (const figure::properties& fp) - { - if (fp.get___backend__ () == FLTK_BACKEND_NAME) - { - octave_value ps = fp.get___plot_stream__ (); - if (ps.is_string ()) - return str2idx (ps.string_value ()); - else - return 0; - } - error ("fltk_backend:: figure is not fltk"); - return -1; - } - - int hnd2idx (const graphics_handle& fh) - { - return hnd2idx (fh.value ()); - } - - int hnd2idx (const double h) - { - graphics_object fobj = gh_manager::get_object (h); - if (fobj && fobj.isa ("figure")) - { - figure::properties& fp = - dynamic_cast<figure::properties&> (fobj.get_properties ()); - return figprops2idx (fp); - } - error ("fltk_backend:: not a figure"); - return -1; - } -}; - -std::string figure_manager::fltk_idx_header="fltk index="; -int figure_manager::curr_index = 1; - -class fltk_backend : public base_graphics_backend -{ -public: - fltk_backend (void) - : base_graphics_backend (FLTK_BACKEND_NAME) { } - - ~fltk_backend (void) { } - - bool is_valid (void) const { return true; } - - void close_figure (const octave_value& ov) const - { - if (ov.is_string ()) - figure_manager::Instance ().delete_window (ov.string_value ()); - } - - void redraw_figure (const graphics_handle& fh) const - { - figure_manager::Instance ().mark_modified (fh); - } - - void print_figure (const graphics_handle& /*fh*/, - const std::string& /*term*/, - const std::string& /*file*/, bool /*mono*/, - const std::string& /*debug_file*/) const { } - - Matrix get_canvas_size (const graphics_handle& fh) const - { - return figure_manager::Instance ().get_size (fh); - } - - double get_screen_resolution (void) const - { - // FLTK doesn't give this info - return 72.0; - } - - Matrix get_screen_size (void) const - { - Matrix sz (1, 2, 0.0); - sz(0) = Fl::w (); - sz(1) = Fl::h (); - return sz; - } -}; - -static bool backend_registered = false; -// call this to init the fltk backend -DEFUN_DLD (__init_fltk__, , , "") -{ - graphics_backend::register_backend (new fltk_backend); - backend_registered = true; - - octave_value retval; - return retval; -} - - -// call this to delete the fltk backend -DEFUN_DLD (__remove_fltk__, , , "") -{ - figure_manager::Instance ().close_all (); - graphics_backend::unregister_backend (FLTK_BACKEND_NAME); - backend_registered = false; - - // FIXME ??? - // give FLTK 10 seconds to wrap it up - Fl::wait(10); - octave_value retval; - return retval; -} - -// give FLTK no more than 0.01 sec to do it's stuff -static double fltk_maxtime = 1e-2; - -// call this to delete the fltk backend -DEFUN_DLD (__fltk_maxtime__, args, ,"") -{ - octave_value retval = fltk_maxtime; - - if (args.length () == 1) - { - if (args(0).is_real_scalar ()) - fltk_maxtime = args(0).double_value (); - else - error ("argument must be a real scalar"); - } - - return retval; -} - -// call this from the idle_callback to refresh windows -DEFUN_DLD (__fltk_redraw__, , , - "internal function for the fltk backend") -{ - octave_value retval; - - if (!backend_registered) - return retval; - - // we scan all figures and add those which use FLTK as a backend - graphics_object obj = gh_manager::get_object (0); - if (obj && obj.isa ("root_figure")) - { - base_properties& props = obj.get_properties (); - Matrix children = props.get_children (); - - for (octave_idx_type n = 0; n < children.numel (); n++) - { - graphics_object fobj = gh_manager::get_object (children (n)); - if (fobj && fobj.isa ("figure")) - { - figure::properties& fp = - dynamic_cast<figure::properties&> (fobj.get_properties ()); - if (fp.get___backend__ () == FLTK_BACKEND_NAME) - figure_manager::Instance ().new_window (fp); - } - } - } - - Fl::wait (fltk_maxtime); - - return retval; -} - -/* to init -autoload("__init_fltk__",[pwd(),"/fltk_backend.oct"]) -autoload("__remove_fltk__",[pwd(),"/fltk_backend.oct"]) -autoload("__fltk_redraw__",[pwd(),"/fltk_backend.oct"]) -autoload("__fltk_maxtime__",[pwd(),"/fltk_backend.oct"]) -input_event_hook ("__fltk_redraw__"); -__init_fltk__ (); -set(gcf(),"__backend__","fltk") -plot(randn(1e3,1)); - - -*/
--- a/src/graphics/opengl/Makefile.in Thu Jun 05 20:42:14 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,37 +0,0 @@ -# Makefile for octave's src/graphics/opengl directory -# -# Copyright (C) 1998, 2007 John W. Eaton -# -# This file is part of Octave. -# -# Octave is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by the -# Free Software Foundation; either version 3 of the License, or (at -# your option) any later version. -# -# Octave is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -# for more details. -# -# You should have received a copy of the GNU General Public License -# along with Octave; see the file COPYING. If not, see -# <http://www.gnu.org/licenses/>. - -TOPDIR = ../../.. - -srcdir = @srcdir@ -top_srcdir = @top_srcdir@ -VPATH = @srcdir@ - -EXTERNAL_DISTFILES = $(DISTFILES) - -GRAPHICS_NAME = octgraphics_gl - -GRAPHICS_SRC = gl-render.cc - -GRAPHICS_INCS = gl-render.h - -GRAPHICS_EXTRA_LIBS = $(OPENGL_LIBS) - -include ../Makerules
--- a/src/graphics/opengl/gl-render.cc Thu Jun 05 20:42:14 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2777 +0,0 @@ -/* - -Copyright (C) 2008 Michael Goffioul - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -<http://www.gnu.org/licenses/>. - -*/ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include <lo-mappers.h> -#include "gl-render.h" - -#define LIGHT_MODE GL_FRONT_AND_BACK - -// Win32 API requires the CALLBACK attributes for -// GLU callback functions. Define it to empty on -// other platforms. -#ifndef CALLBACK -#define CALLBACK -#endif - -enum { - AXE_ANY_DIR = 0, - AXE_DEPTH_DIR = 1, - AXE_HORZ_DIR = 2, - AXE_VERT_DIR = 3 -}; - -static octave_idx_type -xmin (octave_idx_type x, octave_idx_type y) -{ - return x < y ? x : y; -} - -class -opengl_texture -{ -protected: - class texture_rep - { - public: - texture_rep (void) : valid (false), count (1) { } - - texture_rep (GLuint _id, int _w, int _h, int _tw, int _th) - : id (_id), w (_w), h (_h), tw (_tw), th (_th), - tx (double(w)/tw), ty (double(h)/th), valid (true), - count (1) { } - - ~texture_rep (void) - { - if (valid) - glDeleteTextures (1, &id); - } - - void bind (int mode) const - { if (valid) glBindTexture (mode, id); } - - void tex_coord (double q, double r) const - { if (valid) glTexCoord2d (q*tx, r*ty); } - - GLuint id; - int w, h; - int tw, th; - double tx, ty; - bool valid; - int count; - }; - - texture_rep *rep; - -private: - opengl_texture (texture_rep *_rep) : rep (_rep) { } - -public: - opengl_texture (void) : rep (new texture_rep ()) { } - - opengl_texture (const opengl_texture& tx) - : rep (tx.rep) - { - rep->count++; - } - - ~opengl_texture (void) - { - if (--rep->count == 0) - delete rep; - } - - opengl_texture& operator = (const opengl_texture& tx) - { - if (--rep->count == 0) - delete rep; - - rep = tx.rep; - rep->count++; - - return *this; - } - - static opengl_texture create (const octave_value& data); - - void bind (int mode = GL_TEXTURE_2D) const - { rep->bind (mode); } - - void tex_coord (double q, double r) const - { rep->tex_coord (q, r); } - - bool is_valid (void) const - { return rep->valid; } -}; - -static int -next_power_of_2 (int n) -{ - int m = 1; - - while (m < n && m < INT_MAX) - m <<= 1; - - return m; -} - -opengl_texture -opengl_texture::create (const octave_value& data) -{ - opengl_texture retval; - - dim_vector dv (data.dims ()); - - // Expect RGB data - if (dv.length () == 3 && dv(2) == 3) - { - int h = dv(0), w = dv(1), tw, th; - GLuint id; - bool ok = true; - - tw = next_power_of_2 (w); - th = next_power_of_2 (w); - - glGenTextures (1, &id); - glBindTexture (GL_TEXTURE_2D, id); - - if (data.is_double_type ()) - { - NDArray _a = data.array_value (); - - OCTAVE_LOCAL_BUFFER (float, a, (3*tw*th)); - - for (int i = 0; i < h; i++) - for (int j = 0, idx = i*tw*3; j < w; j++, idx += 3) - { - a[idx] = _a(i,j,0); - a[idx+1] = _a(i,j,1); - a[idx+2] = _a(i,j,2); - } - - glTexImage2D (GL_TEXTURE_2D, 0, 3, tw, th, 0, - GL_RGB, GL_FLOAT, a); - } - else if (data.is_uint8_type ()) - { - uint8NDArray _a = data.uint8_array_value (); - - OCTAVE_LOCAL_BUFFER (octave_uint8, a, (3*tw*th)); - - for (int i = 0; i < h; i++) - for (int j = 0, idx = i*tw*3; j < w; j++, idx += 3) - { - a[idx] = _a(i,j,0); - a[idx+1] = _a(i,j,1); - a[idx+2] = _a(i,j,2); - } - - glTexImage2D (GL_TEXTURE_2D, 0, 3, tw, th, 0, - GL_RGB, GL_UNSIGNED_BYTE, a); - } - else - { - ok = false; - warning ("opengl_texture::create: invalid texture data type (expected double or uint8)"); - } - - if (ok) - { - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - - if (glGetError () != GL_NO_ERROR) - warning ("opengl_texture::create: OpenGL error while generating texture data"); - else - retval = opengl_texture (new texture_rep (id, w, h, tw, th)); - } - } - else - warning ("opengl_texture::create: invalid texture data size"); - - return retval; -} - -class -opengl_tesselator -{ -public: - typedef void (CALLBACK *fcn) (void); - -public: - - opengl_tesselator (void) : glu_tess (0) { init (); } - - virtual ~opengl_tesselator (void) - { if (glu_tess) gluDeleteTess (glu_tess); } - - void begin_polygon (bool filled = true) - { - gluTessProperty (glu_tess, GLU_TESS_BOUNDARY_ONLY, - (filled ? GL_FALSE : GL_TRUE)); - fill = filled; - gluTessBeginPolygon (glu_tess, this); - } - - void end_polygon (void) const - { gluTessEndPolygon (glu_tess); } - - void begin_contour (void) const - { gluTessBeginContour (glu_tess); } - - void end_contour (void) const - { gluTessEndContour (glu_tess); } - - void add_vertex (double *loc, void *data) const - { gluTessVertex (glu_tess, loc, data); } - -protected: - virtual void begin (GLenum /*type*/) { } - - virtual void end (void) { } - - virtual void vertex (void */*data*/) { } - - virtual void combine (GLdouble /*c*/[3], void */*data*/[4], - GLfloat /*w*/[4], void **/*out_data*/) { } - - virtual void edge_flag (GLboolean /*flag*/) { } - - virtual void error (GLenum err) - { ::error ("OpenGL tesselation error (%d)", err); } - - virtual void init (void) - { - glu_tess = gluNewTess (); - - gluTessCallback (glu_tess, GLU_TESS_BEGIN_DATA, - reinterpret_cast<fcn> (tess_begin)); - gluTessCallback (glu_tess, GLU_TESS_END_DATA, - reinterpret_cast<fcn> (tess_end)); - gluTessCallback (glu_tess, GLU_TESS_VERTEX_DATA, - reinterpret_cast<fcn> (tess_vertex)); - gluTessCallback (glu_tess, GLU_TESS_COMBINE_DATA, - reinterpret_cast<fcn> (tess_combine)); - gluTessCallback (glu_tess, GLU_TESS_EDGE_FLAG_DATA, - reinterpret_cast<fcn> (tess_edge_flag)); - gluTessCallback (glu_tess, GLU_TESS_ERROR_DATA, - reinterpret_cast<fcn> (tess_error)); - } - - bool is_filled (void) const { return fill; } - -private: - static void CALLBACK tess_begin (GLenum type, void *t) - { reinterpret_cast<opengl_tesselator *> (t)->begin (type); } - - static void CALLBACK tess_end (void *t) - { reinterpret_cast<opengl_tesselator *> (t)->end (); } - - static void CALLBACK tess_vertex (void *v, void *t) - { reinterpret_cast<opengl_tesselator *> (t)->vertex (v); } - - static void CALLBACK tess_combine (GLdouble c[3], void *v[4], GLfloat w[4], - void **out, void *t) - { reinterpret_cast<opengl_tesselator *> (t)->combine (c, v, w, out); } - - static void CALLBACK tess_edge_flag (GLboolean flag, void *t) - { reinterpret_cast<opengl_tesselator *> (t)->edge_flag (flag); } - - static void CALLBACK tess_error (GLenum err, void *t) - { reinterpret_cast<opengl_tesselator *> (t)->error (err); } - -private: - GLUtesselator *glu_tess; - bool fill; -}; - -class -vertex_data -{ -public: - class vertex_data_rep - { - public: - Matrix coords; - Matrix color; - Matrix normal; - double alpha; - float ambient; - float diffuse; - float specular; - float specular_exp; - - // reference counter - int count; - - vertex_data_rep (void) { } - - vertex_data_rep (const Matrix& c, const Matrix& col, const Matrix& n, - double a, float as, float ds, float ss, float se) - : coords (c), color (col), normal (n), alpha (a), - ambient (as), diffuse (ds), specular (ss), specular_exp (se), - count (1) { } - }; - -private: - vertex_data_rep *rep; - - vertex_data_rep *nil_rep (void) const - { - static vertex_data_rep *nr = new vertex_data_rep (); - - return nr; - } - -public: - vertex_data (void) : rep (nil_rep ()) { } - - vertex_data (const vertex_data& v) : rep (v.rep) - { rep->count++; } - - vertex_data (const Matrix& c, const Matrix& col, const Matrix& n, - double a, float as, float ds, float ss, float se) - : rep (new vertex_data_rep (c, col, n, a, as, ds, ss, se)) - { - rep->count++; - } - - vertex_data (vertex_data_rep *new_rep) - : rep (new_rep) { } - - ~vertex_data (void) - { - if (--rep->count == 0) - delete rep; - } - - vertex_data& operator = (const vertex_data& v) - { - if (--rep->count == 0) - delete rep; - - rep = v.rep; - rep->count++; - - return *this; - } - - vertex_data_rep *get_rep (void) const { return rep; } -}; - -#include <Array.cc> - -class -opengl_renderer::patch_tesselator : public opengl_tesselator -{ -public: - patch_tesselator (opengl_renderer *r, int cmode, int lmode, int idx = 0) - : opengl_tesselator (), renderer (r), - color_mode (cmode), light_mode (lmode), index (idx), - first (true) { } - -protected: - void begin (GLenum type) - { - //printf("patch_tesselator::begin (%d)\n", type); - first = true; - - if (color_mode == 2 || light_mode == 2) - glShadeModel (GL_SMOOTH); - else - glShadeModel (GL_FLAT); - - if (is_filled ()) - renderer->set_polygon_offset (true, 1+index); - - glBegin (type); - } - - void end (void) - { - //printf("patch_tesselator::end\n"); - glEnd (); - renderer->set_polygon_offset (false); - } - - void vertex (void *data) - { - vertex_data::vertex_data_rep *v - = reinterpret_cast<vertex_data::vertex_data_rep *> (data); - //printf("patch_tesselator::vertex (%g, %g, %g)\n", v->coords(0), v->coords(1), v->coords(2)); - - // FIXME: why did I need to keep the first vertex of the face - // in JHandles? I think it's related to the fact that the - // tessellation process might re-order the vertices, such that - // the first one you get here might not be the first one of the face; - // but I can't figure out the actual reason. - if (color_mode > 0 && (first || color_mode == 2)) - { - Matrix col = v->color; - - if (col.numel () == 3) - { - glColor3dv (col.data ()); - if (light_mode > 0) - { - float buf[4] = { 0, 0, 0, 1 }; - - for (int k = 0; k < 3; k++) - buf[k] = (v->ambient * col(k)); - glMaterialfv (LIGHT_MODE, GL_AMBIENT, buf); - - for (int k = 0; k < 3; k++) - buf[k] = (v->diffuse * col(k)); - glMaterialfv (LIGHT_MODE, GL_AMBIENT, buf); - } - } - } - - if (light_mode > 0 && (first || light_mode == 2)) - glNormal3dv (v->normal.data ()); - - glVertex3dv (v->coords.data ()); - - first = false; - } - - void combine (GLdouble xyz[3], void *data[4], GLfloat w[4], - void **out_data) - { - //printf("patch_tesselator::combine\n"); - - vertex_data::vertex_data_rep *v[4]; - int vmax = 4; - - for (int i = 0; i < 4; i++) - { - v[i] = reinterpret_cast<vertex_data::vertex_data_rep *> (data[i]); - - if (vmax == 4 && ! v[i]) - vmax = i; - } - - Matrix vv (1, 3, 0.0); - Matrix cc; - Matrix nn (1, 3, 0.0); - double aa = 0.0; - - vv(0) = xyz[0]; - vv(1) = xyz[1]; - vv(2) = xyz[2]; - - if (v[0]->color.numel ()) - { - cc.resize (1, 3, 0.0); - for (int ic = 0; ic < 3; ic++) - for (int iv = 0; iv < vmax; iv++) - cc(ic) += (w[iv] * v[iv]->color(ic)); - } - - if (v[0]->normal.numel () > 0) - { - for (int in = 0; in < 3; in++) - for (int iv = 0; iv < vmax; iv++) - nn(in) += (w[iv] * v[iv]->normal(in)); - } - - for (int iv = 0; iv < vmax; iv++) - aa += (w[iv] * v[iv]->alpha); - - vertex_data new_v (vv, cc, nn, aa, v[0]->ambient, v[0]->diffuse, - v[0]->specular, v[0]->specular_exp); - tmp_vdata.push_back (new_v); - - *out_data = new_v.get_rep (); - } - -private: - opengl_renderer *renderer; - int color_mode; // 0: uni, 1: flat, 2: interp - int light_mode; // 0: none, 1: flat, 2: gouraud - int index; - bool first; - std::list<vertex_data> tmp_vdata; -}; - -void -opengl_renderer::draw (const graphics_object& go) -{ - if (! go.valid_object ()) - return; - - const base_properties& props = go.get_properties (); - - if (go.isa ("figure")) - draw (dynamic_cast<const figure::properties&> (props)); - else if (go.isa ("axes")) - draw (dynamic_cast<const axes::properties&> (props)); - else if (go.isa ("line")) - draw (dynamic_cast<const line::properties&> (props)); - else if (go.isa ("surface")) - draw (dynamic_cast<const surface::properties&> (props)); - else if (go.isa ("patch")) - draw (dynamic_cast<const patch::properties&> (props)); - else if (go.isa ("hggroup")) - draw (dynamic_cast<const hggroup::properties&> (props)); - else - warning ("opengl_renderer: cannot render object of type `%s'", - props.graphics_object_name ().c_str ()); -} - -void -opengl_renderer::draw (const figure::properties& props) -{ - backend = props.get_backend (); - - // Initialize OpenGL context - - glEnable (GL_DEPTH_TEST); - glDepthFunc (GL_LEQUAL); - glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glEnable (GL_NORMALIZE); - - // Clear background - - Matrix c = props.get_color_rgb (); - - if (c.length() >= 3) - { - glClearColor (c(0), c(1), c(2), 1); - glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - } - - // Draw children - - draw (props.get_children ()); -} - -void -opengl_renderer::draw (const axes::properties& props) -{ - // setup OpenGL transformation - - Matrix x_zlim = props.get_transform_zlim (); - Matrix x_mat1 = props.get_opengl_matrix_1 (); - Matrix x_mat2 = props.get_opengl_matrix_2 (); - - xZ1 = x_zlim(0)-(x_zlim(1)-x_zlim(0))/2; - xZ2 = x_zlim(1)+(x_zlim(1)-x_zlim(0))/2; - - int vw[4]; - glGetIntegerv (GL_VIEWPORT, vw); - - glMatrixMode (GL_MODELVIEW); - glLoadIdentity (); - glScaled(1, 1, -1); - glMultMatrixd (x_mat1.data ()); - glMatrixMode (GL_PROJECTION); - glLoadIdentity (); - glOrtho (0, vw[2], vw[3], 0, xZ1, xZ2); - glMultMatrixd (x_mat2.data ()); - glMatrixMode (GL_MODELVIEW); - - glClear (GL_DEPTH_BUFFER_BIT); - - // store axes transformation data - - xform = props.get_transform (); - - // draw axes object - - Matrix xlim = xform.xscale (props.get_xlim ().matrix_value ()); - Matrix ylim = xform.yscale (props.get_ylim ().matrix_value ()); - Matrix zlim = xform.zscale (props.get_zlim ().matrix_value ()); - double x_min = xlim(0), x_max = xlim(1); - double y_min = ylim(0), y_max = ylim(1); - double z_min = zlim(0), z_max = zlim(1); - - double xd = (props.xdir_is ("normal") ? 1 : -1); - double yd = (props.ydir_is ("normal") ? 1 : -1); - double zd = (props.zdir_is ("normal") ? 1 : -1); - - ColumnVector p1, p2, xv (3), yv (3), zv (3); - int xstate, ystate, zstate; - - xstate = ystate = zstate = AXE_ANY_DIR; - - p1 = xform.transform (x_min, (y_min+y_max)/2, (z_min+z_max)/2, false); - p2 = xform.transform (x_max, (y_min+y_max)/2, (z_min+z_max)/2, false); - xv(0) = xround (p2(0)-p1(0)); - xv(1) = xround (p2(1)-p1(1)); - xv(2) = (p2(2)-p1(2)); - if (xv(0) == 0 && xv(1) == 0) - xstate = AXE_DEPTH_DIR; - else if (xv(2) == 0) - { - if (xv(0) == 0) - xstate = AXE_VERT_DIR; - else if (xv(1) == 0) - xstate = AXE_HORZ_DIR; - } - double xPlane; - if (xv(2) == 0) - if (xv(1) == 0) - xPlane = (xv(0) > 0 ? x_max : x_min); - else - xPlane = (xv(1) < 0 ? x_max : x_min); - else - xPlane = (xv(2) < 0 ? x_min : x_max); - double xPlaneN = (xPlane == x_min ? x_max : x_min); - double fx = (x_max-x_min)/sqrt(xv(0)*xv(0)+xv(1)*xv(1)); - - p1 = xform.transform ((x_min+x_max)/2, y_min, (z_min+z_max)/2, false); - p2 = xform.transform ((x_min+x_max)/2, y_max, (z_min+z_max)/2, false); - yv(0) = xround (p2(0)-p1(0)); - yv(1) = xround (p2(1)-p1(1)); - yv(2) = (p2(2)-p1(2)); - if (yv(0) == 0 && yv(1) == 0) - ystate = AXE_DEPTH_DIR; - else if (yv(2) == 0) - { - if (yv(0) == 0) - ystate = AXE_VERT_DIR; - else if (yv(1) == 0) - ystate = AXE_HORZ_DIR; - } - double yPlane; - if (yv(2) == 0) - if (yv(1) == 0) - yPlane = (yv(0) > 0 ? y_max : y_min); - else - yPlane = (yv(1) < 0 ? y_max : y_min); - else - yPlane = (yv(2) < 0 ? y_min : y_max); - double yPlaneN = (yPlane == y_min ? y_max : y_min); - double fy = (y_max-y_min)/sqrt(yv(0)*yv(0)+yv(1)*yv(1)); - - p1 = xform.transform((x_min+x_max)/2, (y_min+y_max)/2, z_min, false); - p2 = xform.transform((x_min+x_max)/2, (y_min+y_max)/2, z_max, false); - zv(0) = xround(p2(0)-p1(0)); - zv(1) = xround (p2(1)-p1(1)); - zv(2) = (p2(2)-p1(2)); - if (zv(0) == 0 && zv(1) == 0) - zstate = AXE_DEPTH_DIR; - else if (zv(2) == 0) - { - if (zv(0) == 0) - zstate = AXE_VERT_DIR; - else if (zv(1) == 0) - zstate = AXE_HORZ_DIR; - } - double zPlane; - if (zv(2) == 0) - if (zv(1) == 0) - zPlane = (zv(0) > 0 ? z_min : z_max); - else - zPlane = (zv(1) < 0 ? z_min : z_max); - else - zPlane = (zv(2) < 0 ? z_min : z_max); - double zPlaneN = (zPlane == z_min ? z_max : z_min); - double fz = (z_max-z_min)/sqrt(zv(0)*zv(0)+zv(1)*zv(1)); - - bool mode2d = (((xstate > AXE_DEPTH_DIR ? 1 : 0) + - (ystate > AXE_DEPTH_DIR ? 1 : 0) + - (zstate > AXE_DEPTH_DIR ? 1 : 0)) == 2); - if (props.tickdirmode_is ("auto")) - { - // FIXME: tickdir should be updated (code below comes - // from JHandles) - //autoMode++; - //TickDir.set(mode2d ? "in" : "out", true); - //autoMode--; - } - - // FIXME: use ticklength property - double xticklen = 7, yticklen = 7, zticklen = 7; - - //double tickdir = (props.tickdir_is ("in") ? -1 : 1); - double tickdir = (props.tickdirmode_is ("auto") ? - (mode2d ? -1 : 1) : - (props.tickdir_is ("in") ? -1 : 1)); - double xtickoffset = (mode2d && tickdir < 0 ? 0 : xticklen) + 5; - double ytickoffset = (mode2d && tickdir < 0 ? 0 : yticklen) + 5; - double ztickoffset = (mode2d && tickdir < 0 ? 0 : zticklen) + 5; - - bool xySym = (xd*yd*(xPlane-xPlaneN)*(yPlane-yPlaneN) > 0); - bool x2Dtop = false; - bool y2Dright = false; - double zpTick = zPlane; - - /* 2D mode */ - if (xstate == AXE_HORZ_DIR && ystate == AXE_VERT_DIR) - { - if (props.xaxislocation_is ("top")) - { - double tmp = yPlane; - yPlane = yPlaneN; - yPlaneN = tmp; - x2Dtop = true; - } - if (props.yaxislocation_is ("right")) - { - double tmp = xPlane; - xPlane = xPlaneN; - xPlaneN = tmp; - y2Dright = true; - } - if (props.layer_is ("top")) - zpTick = zPlaneN; - } - - Matrix axe_color = props.get_color_rgb (); - bool visible = props.is_visible (); - bool box = props.is_box (); - - // Axes planes - - if (axe_color.numel () > 0 && visible) - { - set_color (axe_color); - set_polygon_offset (true, 2.5); - - glBegin (GL_QUADS); - - // X plane - glVertex3d (xPlane, y_min, z_min); - glVertex3d (xPlane, y_max, z_min); - glVertex3d (xPlane, y_max, z_max); - glVertex3d (xPlane, y_min, z_max); - - // Y plane - glVertex3d (x_min, yPlane, z_min); - glVertex3d (x_max, yPlane, z_min); - glVertex3d (x_max, yPlane, z_max); - glVertex3d (x_min, yPlane, z_max); - - // Z plane - glVertex3d (x_min, y_min, zPlane); - glVertex3d (x_max, y_min, zPlane); - glVertex3d (x_max, y_max, zPlane); - glVertex3d (x_min, y_max, zPlane); - - glEnd (); - - set_polygon_offset (false); - } - - // Axes box - - set_linestyle ("-", true); - set_linewidth (props.get_linewidth ()); - - if (visible) - { - glBegin (GL_LINES); - - // X box - set_color (props.get_xcolor_rgb ()); - glVertex3d (xPlaneN, yPlaneN, zPlane); - glVertex3d (xPlane, yPlaneN, zPlane); - if (box) - { - glVertex3d (xPlaneN, yPlane, zPlane); - glVertex3d (xPlane, yPlane, zPlane); - glVertex3d (xPlaneN, yPlane, zPlaneN); - glVertex3d (xPlane, yPlane, zPlaneN); - glVertex3d (xPlaneN, yPlaneN, zPlaneN); - glVertex3d (xPlane, yPlaneN, zPlaneN); - } - - // Y box - set_color (props.get_ycolor_rgb ()); - glVertex3d (xPlaneN, yPlaneN, zPlane); - glVertex3d (xPlaneN, yPlane, zPlane); - if (box) - { - glVertex3d (xPlane, yPlaneN, zPlane); - glVertex3d (xPlane, yPlane, zPlane); - glVertex3d (xPlane, yPlaneN, zPlaneN); - glVertex3d (xPlane, yPlane, zPlaneN); - glVertex3d (xPlaneN, yPlaneN, zPlaneN); - glVertex3d (xPlaneN, yPlane, zPlaneN); - } - - // Z box - set_color (props.get_zcolor_rgb ()); - if (xySym) - { - glVertex3d (xPlaneN, yPlane, zPlaneN); - glVertex3d (xPlaneN, yPlane, zPlane); - } - else - { - glVertex3d (xPlane, yPlaneN, zPlaneN); - glVertex3d (xPlane, yPlaneN, zPlane); - } - if (box) - { - glVertex3d (xPlane, yPlane, zPlaneN); - glVertex3d (xPlane, yPlane, zPlane); - if (xySym) - { - glVertex3d (xPlane, yPlaneN, zPlaneN); - glVertex3d (xPlane, yPlaneN, zPlane); - } - else - { - glVertex3d (xPlaneN, yPlane, zPlaneN); - glVertex3d (xPlaneN, yPlane, zPlane); - } - glVertex3d (xPlaneN, yPlaneN, zPlaneN); - glVertex3d (xPlaneN, yPlaneN, zPlane); - } - - glEnd (); - } - - std::string gridstyle = props.get_gridlinestyle (); - std::string minorgridstyle = props.get_minorgridlinestyle (); - - // X grid - - if (visible && xstate != AXE_DEPTH_DIR) - { - bool do_xgrid = (props.is_xgrid () && (gridstyle != "none")); - bool do_xminorgrid = (props.is_xminorgrid () && (minorgridstyle != "none")); - bool do_xminortick = props.is_xminortick (); - Matrix xticks = xform.xscale (props.get_xtick ().matrix_value ()); - // FIXME: use pre-computed minor ticks - Matrix xmticks; - // FIXME: use xticklabels property - string_vector xticklabels; - int wmax = 0, hmax = 0; - bool tick_along_z = xisinf (fy); - Matrix tickpos (xticks.numel (), 3); - - set_color (props.get_xcolor_rgb ()); - - // grid lines - if (do_xgrid) - { - set_linestyle (gridstyle, true); - glBegin (GL_LINES); - for (int i = 0; i < xticks.numel (); i++) - { - double xval = xticks(i); - - glVertex3d (xval, yPlaneN, zpTick); - glVertex3d (xval, yPlane, zpTick); - if (zstate != AXE_DEPTH_DIR) - { - glVertex3d (xval, yPlane, zPlaneN); - glVertex3d (xval, yPlane, zPlane); - } - } - glEnd (); - set_linestyle ("-", true); - } - - // tick marks - if (tick_along_z) - { - glBegin (GL_LINES); - for (int i = 0; i < xticks.numel (); i++) - { - double xval = xticks(i); - - glVertex3d (xval, yPlaneN, zPlane); - glVertex3d (xval, yPlaneN, zPlane+signum(zPlane-zPlaneN)*fz*xticklen*tickdir); - if (box && xstate != AXE_ANY_DIR) - { - glVertex3d (xval, yPlaneN, zPlaneN); - glVertex3d (xval, yPlaneN, - zPlaneN+signum(zPlaneN-zPlane)*fz*xticklen*tickdir); - } - tickpos(i,0) = xval; - tickpos(i,1) = yPlaneN; - tickpos(i,2) = zPlane+signum(zPlane-zPlaneN)*fz*xtickoffset; - } - glEnd (); - } - else - { - glBegin (GL_LINES); - for (int i = 0; i < xticks.numel (); i++) - { - double xval = xticks(i); - - glVertex3d (xval, yPlaneN, zpTick); - glVertex3d (xval, yPlaneN+signum(yPlaneN-yPlane)*fy*xticklen*tickdir, zpTick); - if (box && xstate != AXE_ANY_DIR) - { - glVertex3d (xval, yPlane, zpTick); - glVertex3d (xval, - yPlane+signum(yPlane-yPlaneN)*fy*xticklen*tickdir, zpTick); - } - tickpos(i,0) = xval; - tickpos(i,1) = yPlaneN+signum(yPlaneN-yPlane)*fy*xtickoffset; - tickpos(i,2) = zPlane; - } - glEnd (); - } - - // FIXME: tick texts - - // minor grid lines - if (do_xminorgrid) - { - set_linestyle (minorgridstyle, true); - glBegin (GL_LINES); - for (int i = 0; i < xmticks.numel (); i++) - { - double xval = xmticks(i); - - glVertex3d (xval, yPlaneN, zpTick); - glVertex3d (xval, yPlane, zpTick); - if (zstate != AXE_DEPTH_DIR) - { - glVertex3d (xval, yPlane, zPlaneN); - glVertex3d (xval, yPlane, zPlane); - } - } - glEnd (); - set_linestyle ("-", true); - } - - // minor tick marks - if (do_xminortick) - { - if (tick_along_z) - { - glBegin (GL_LINES); - for (int i = 0; i < xmticks.numel (); i++) - { - double xval = xmticks(i); - - glVertex3d (xval, yPlaneN, zPlane); - glVertex3d (xval, yPlaneN, - zPlane+signum(zPlane-zPlaneN)*fz*xticklen/2*tickdir); - if (box && xstate != AXE_ANY_DIR) - { - glVertex3d (xval, yPlaneN, zPlaneN); - glVertex3d (xval, yPlaneN, - zPlaneN+signum(zPlaneN-zPlane)*fz*xticklen/2*tickdir); - } - } - glEnd (); - } - else - { - glBegin (GL_LINES); - for (int i = 0; i < xmticks.numel (); i++) - { - double xval = xmticks(i); - - glVertex3d (xval, yPlaneN, zpTick); - glVertex3d (xval, - yPlaneN+signum(yPlaneN-yPlane)*fy*xticklen/2*tickdir, zpTick); - if (box && xstate != AXE_ANY_DIR) - { - glVertex3d (xval, yPlane, zpTick); - glVertex3d (xval, - yPlane+signum(yPlane-yPlaneN)*fy*xticklen/2*tickdir, zpTick); - } - } - glEnd (); - } - } - - text::properties& xlabel_props = - reinterpret_cast<text::properties&> (gh_manager::get_object (props.get_xlabel ()).get_properties ()); - - // FIXME: auto-positioning should be disabled if the - // label has been positioned manually - if (! xlabel_props.get_string ().empty ()) - { - xlabel_props.set_horizontalalignment (xstate > AXE_DEPTH_DIR ? "center" : (xySym ? "left" : "right")); - xlabel_props.set_verticalalignment (xstate == AXE_VERT_DIR ? "bottom" : (zd*zv(2) <= 0 ? "top" : "bottom")); - - double angle = 0; - ColumnVector p = graphics_xform::xform_vector ((xmin+xmax)/2, yPlaneN, zPlane); - - if (tick_along_z) - p(2) += (signum(zPlane-zPlaneN)*fz*xtickoffset); - else - p(1) += (signum(yPlaneN-yPlane)*fy*xtickoffset); - p = xform.transform (p(0), p(1), p(2), false); - switch (xstate) - { - case AXE_ANY_DIR: - p(0) += (xySym ? wmax : -wmax); - p(1) += (zd*zv(2) <= 0 ? hmax : -hmax); - break; - case AXE_VERT_DIR: - p(0) -= wmax; - angle = 90; - break; - case AXE_HORZ_DIR: - p(1) += hmax; - break; - } - p = xform.untransform (p(0), p(1), p(2), true); - xlabel_props.set_position (p.extract_n (0, 3).transpose ()); - xlabel_props.set_rotation (angle); - } - } - - // Y grid - - if (ystate != AXE_DEPTH_DIR && visible) - { - bool do_ygrid = (props.is_ygrid () && (gridstyle != "none")); - bool do_yminorgrid = (props.is_yminorgrid () && (minorgridstyle != "none")); - bool do_yminortick = props.is_yminortick (); - Matrix yticks = xform.yscale (props.get_ytick ().matrix_value ()); - // FIXME: use pre-computed minor ticks - Matrix ymticks; - // FIXME: use yticklabels property - string_vector yticklabels; - int wmax = 0, hmax = 0; - bool tick_along_z = xisinf (fx); - Matrix tickpos (yticks.numel (), 3); - - set_color (props.get_ycolor_rgb ()); - - // grid lines - if (do_ygrid) - { - set_linestyle (gridstyle, true); - glBegin (GL_LINES); - for (int i = 0; i < yticks.numel (); i++) - { - double yval = yticks(i); - - glVertex3d (xPlaneN, yval, zpTick); - glVertex3d (xPlane, yval, zpTick); - if (zstate != AXE_DEPTH_DIR) - { - glVertex3d (xPlane, yval, zPlaneN); - glVertex3d (xPlane, yval, zPlane); - } - } - glEnd (); - set_linestyle ("-", true); - } - - // tick marks - if (tick_along_z) - { - glBegin (GL_LINES); - for (int i = 0; i < yticks.numel (); i++) - { - double yval = yticks(i); - - glVertex3d (xPlaneN, yval, zPlane); - glVertex3d (xPlaneN, yval, zPlane+signum(zPlane-zPlaneN)*fz*yticklen*tickdir); - if (box && ystate != AXE_ANY_DIR) - { - glVertex3d (xPlaneN, yval, zPlaneN); - glVertex3d (xPlaneN, yval, - zPlaneN+signum(zPlaneN-zPlane)*fz*yticklen*tickdir); - } - tickpos(i,0) = xPlaneN; - tickpos(i,1) = yval; - tickpos(i,2) = zPlane+signum(zPlane-zPlaneN)*fz*ytickoffset; - } - glEnd (); - } - else - { - glBegin (GL_LINES); - for (int i = 0; i < yticks.numel (); i++) - { - double yval = yticks(i); - - glVertex3d (xPlaneN, yval, zpTick); - glVertex3d (xPlaneN+signum(xPlaneN-xPlane)*fx*yticklen*tickdir, yval, zpTick); - if (box && ystate != AXE_ANY_DIR) - { - glVertex3d (xPlane, yval, zpTick); - glVertex3d (xPlane+signum(xPlane-xPlaneN)*fx*yticklen*tickdir, - yval, zpTick); - } - tickpos(i,0) = xPlaneN+signum(xPlaneN-xPlane)*fx*ytickoffset; - tickpos(i,1) = yval; - tickpos(i,2) = zPlane; - } - glEnd (); - } - - // FIXME: tick texts - - // minor grid lines - if (do_yminorgrid) - { - set_linestyle (minorgridstyle, true); - glBegin (GL_LINES); - for (int i = 0; i < ymticks.numel (); i++) - { - double yval = ymticks(i); - - glVertex3d (xPlaneN, yval, zpTick); - glVertex3d (xPlane, yval, zpTick); - if (zstate != AXE_DEPTH_DIR) - { - glVertex3d (xPlane, yval, zPlaneN); - glVertex3d (xPlane, yval, zPlane); - } - } - glEnd (); - set_linestyle ("-", true); - } - - // minor tick marks - if (do_yminortick) - { - if (tick_along_z) - { - glBegin (GL_LINES); - for (int i = 0; i < ymticks.numel (); i++) - { - double yval = ymticks(i); - - glVertex3d (xPlaneN, yval, zPlane); - glVertex3d (xPlaneN, yval, - zPlane+signum(zPlane-zPlaneN)*fz*yticklen/2*tickdir); - if (box && ystate != AXE_ANY_DIR) - { - glVertex3d (xPlaneN, yval, zPlaneN); - glVertex3d (xPlaneN, yval, - zPlaneN+signum(zPlaneN-zPlane)*fz*yticklen/2*tickdir); - } - } - glEnd (); - } - else - { - glBegin (GL_LINES); - for (int i = 0; i < ymticks.numel (); i++) - { - double yval = ymticks(i); - - glVertex3d (xPlaneN, yval, zpTick); - glVertex3d (xPlaneN+signum(xPlaneN-xPlane)*fx*yticklen/2*tickdir, - yval, zpTick); - if (box && ystate != AXE_ANY_DIR) - { - glVertex3d (xPlane, yval, zpTick); - glVertex3d (xPlane+signum(xPlane-xPlaneN)*fx*yticklen/2*tickdir, - yval, zpTick); - } - } - glEnd (); - } - } - - text::properties& ylabel_props = - reinterpret_cast<text::properties&> (gh_manager::get_object (props.get_ylabel ()).get_properties ()); - - // FIXME: auto-positioning should be disabled if the - // label has been positioned manually - if (! ylabel_props.get_string ().empty ()) - { - ylabel_props.set_horizontalalignment (ystate > AXE_DEPTH_DIR ? "center" : (!xySym ? "left" : "right")); - ylabel_props.set_verticalalignment (ystate == AXE_VERT_DIR ? "bottom" : (zd*zv(2) <= 0 ? "top" : "bottom")); - - double angle = 0; - ColumnVector p = graphics_xform::xform_vector (xPlaneN, (ymin+ymax)/2, zPlane); - - if (tick_along_z) - p(2) += (signum(zPlane-zPlaneN)*fz*ytickoffset); - else - p(0) += (signum(xPlaneN-xPlane)*fx*ytickoffset); - p = xform.transform (p(0), p(1), p(2), false); - switch (ystate) - { - case AXE_ANY_DIR: - p(0) += (!xySym ? wmax : -wmax); - p(1) += (zd*zv(2) <= 0 ? hmax : -hmax); - break; - case AXE_VERT_DIR: - p(0) -= wmax; - angle = 90; - break; - case AXE_HORZ_DIR: - p(1) += hmax; - break; - } - p = xform.untransform(p(0), p(1), p(2), true); - ylabel_props.set_position (p.extract_n (0, 3).transpose ()); - ylabel_props.set_rotation (angle); - } - } - - // Z Grid - - if (zstate != AXE_DEPTH_DIR && visible) - { - bool do_zgrid = (props.is_zgrid () && (gridstyle != "none")); - bool do_zminorgrid = (props.is_zminorgrid () && (minorgridstyle != "none")); - bool do_zminortick = props.is_zminortick (); - Matrix zticks = xform.zscale (props.get_ztick ().matrix_value ()); - // FIXME: use pre-computed minor ticks - Matrix zmticks; - // FIXME: use zticklabels property - string_vector zticklabels; - int wmax = 0, hmax = 0; - Matrix tickpos (zticks.numel (), 3); - - set_color (props.get_zcolor_rgb ()); - - // grid lines - if (do_zgrid) - { - set_linestyle (gridstyle, true); - glBegin (GL_LINES); - for (int i = 0; i < zticks.numel (); i++) - { - double zval = zticks(i); - - glVertex3d (xPlaneN, yPlane, zval); - glVertex3d (xPlane, yPlane, zval); - glVertex3d (xPlane, yPlaneN, zval); - glVertex3d (xPlane, yPlane, zval); - } - glEnd (); - set_linestyle ("-", true); - } - - // tick marks - if (xySym) - { - if (xisinf (fy)) - { - glBegin (GL_LINES); - for (int i = 0; i < zticks.numel (); i++) - { - double zval = zticks(i); - - glVertex3d (xPlaneN, yPlane, zval); - glVertex3d (xPlaneN+signum(xPlaneN-xPlane)*fx*zticklen*tickdir, - yPlane, zval); - if (box && zstate != AXE_ANY_DIR) - { - glVertex3d (xPlane, yPlane, zval); - glVertex3d (xPlane+signum(xPlane-xPlaneN)*fx*zticklen*tickdir, - yPlane, zval); - } - tickpos(i,0) = xPlaneN+signum(xPlaneN-xPlane)*fx*ztickoffset; - tickpos(i,1) = yPlane; - tickpos(i,2) = zval; - } - glEnd (); - } - else - { - glBegin (GL_LINES); - for (int i = 0; i < zticks.numel (); i++) - { - double zval = zticks(i); - - glVertex3d (xPlaneN, yPlane, zval); - glVertex3d (xPlaneN, yPlane+signum(yPlane-yPlaneN)*fy*zticklen*tickdir, zval); - tickpos(i,0) = xPlaneN; - tickpos(i,1) = yPlane+signum(yPlane-yPlaneN)*fy*ztickoffset; - tickpos(i,2) = zval; - } - glEnd (); - } - } - else - { - if (xisinf (fx)) - { - glBegin (GL_LINES); - for (int i = 0; i < zticks.numel (); i++) - { - double zval = zticks(i); - - glVertex3d (xPlane, yPlaneN, zval); - glVertex3d (xPlane, yPlaneN+signum(yPlaneN-yPlane)*fy*zticklen*tickdir, zval); - if (box && zstate != AXE_ANY_DIR) - { - glVertex3d (xPlane, yPlane, zval); - glVertex3d (xPlane, yPlane+signum(yPlane-yPlaneN)*fy*zticklen*tickdir, zval); - } - tickpos(i,0) = xPlane; - tickpos(i,1) = yPlaneN+signum(yPlaneN-yPlane)*fy*ztickoffset; - tickpos(i,2) = zval; - } - glEnd (); - } - else - { - glBegin (GL_LINES); - for (int i = 0; i < zticks.numel (); i++) - { - double zval = zticks(i); - - glVertex3d (xPlane, yPlaneN, zval); - glVertex3d (xPlane+signum(xPlane-xPlaneN)*fx*zticklen*tickdir, yPlaneN, zval); - tickpos(i,0) = xPlane+signum(xPlane-xPlaneN)*fx*ztickoffset; - tickpos(i,1) = yPlaneN; - tickpos(i,2) = zval; - } - glEnd (); - } - } - - // FIXME: tick texts - - // minor grid lines - if (do_zminorgrid) - { - set_linestyle (minorgridstyle, true); - glBegin (GL_LINES); - for (int i = 0; i < zmticks.numel (); i++) - { - double zval = zmticks(i); - - glVertex3d (xPlaneN, yPlane, zval); - glVertex3d (xPlane, yPlane, zval); - glVertex3d (xPlane, yPlaneN, zval); - glVertex3d (xPlane, yPlane, zval); - } - glEnd (); - set_linestyle ("-", true); - } - - // minor tick marks - if (do_zminortick) - { - if (xySym) - { - if (xisinf (fy)) - { - glBegin (GL_LINES); - for (int i = 0; i < zmticks.numel (); i++) - { - double zval = zmticks(i); - - glVertex3d (xPlaneN, yPlane, zval); - glVertex3d (xPlaneN+signum(xPlaneN-xPlane)*fx*zticklen/2*tickdir, - yPlane, zval); - if (box && zstate != AXE_ANY_DIR) - { - glVertex3d (xPlane, yPlane, zval); - glVertex3d (xPlane+signum(xPlane-xPlaneN)*fx*zticklen/2*tickdir, - yPlane, zval); - } - } - glEnd (); - } - else - { - glBegin (GL_LINES); - for (int i = 0; i < zmticks.numel (); i++) - { - double zval = zmticks(i); - - glVertex3d (xPlaneN, yPlane, zval); - glVertex3d (xPlaneN, yPlane+signum(yPlane-yPlaneN)*fy*zticklen/2*tickdir, zval); - } - glEnd (); - } - } - else - { - if (xisinf (fx)) - { - glBegin (GL_LINES); - for (int i = 0; i < zmticks.numel (); i++) - { - double zval = zmticks(i); - - glVertex3d (xPlane, yPlaneN, zval); - glVertex3d (xPlane, yPlaneN+signum(yPlaneN-yPlane)*fy*zticklen/2*tickdir, zval); - if (box && zstate != AXE_ANY_DIR) - { - glVertex3d (xPlane, yPlane, zval); - glVertex3d (xPlane, yPlane+signum(yPlane-yPlaneN)*fy*zticklen/2*tickdir, zval); - } - } - glEnd (); - } - else - { - glBegin (GL_LINES); - for (int i = 0; i < zmticks.numel (); i++) - { - double zval = zmticks(i); - - glVertex3d (xPlane, yPlaneN, zval); - glVertex3d (xPlane+signum(xPlane-xPlaneN)*fx*zticklen/2*tickdir, yPlaneN, zval); - } - glEnd (); - } - } - } - - text::properties& zlabel_props = - reinterpret_cast<text::properties&> (gh_manager::get_object (props.get_zlabel ()).get_properties ()); - - // FIXME: auto-positioning should be disabled if the - // label has been positioned manually - if (! zlabel_props.get_string ().empty ()) - { - bool camAuto = props.cameraupvectormode_is ("auto"); - - zlabel_props.set_horizontalalignment ((zstate > AXE_DEPTH_DIR || camAuto) ? "center" : "right"); - zlabel_props.set_verticalalignment(zstate == AXE_VERT_DIR ? "bottom" : ((zd*zv(2) < 0 || camAuto) ? "bottom" : "top")); - - double angle = 0; - ColumnVector p; - - if (xySym) - { - p = graphics_xform::xform_vector (xPlaneN, yPlane, (zmin+zmax)/2); - if (xisinf (fy)) - p(0) += (signum(xPlaneN-xPlane)*fx*ztickoffset); - else - p(1) += (signum(yPlane-yPlaneN)*fy*ztickoffset); - } - else - { - p = graphics_xform::xform_vector (xPlane, yPlaneN, (zmin+zmax)/2); - if (xisinf (fx)) - p(1) += (signum(yPlaneN-yPlane)*fy*ztickoffset); - else - p(0) += (signum(xPlane-xPlaneN)*fx*ztickoffset); - } - p = xform.transform (p(0), p(1), p(2), false); - switch (zstate) - { - case AXE_ANY_DIR: - if (camAuto) - { - p(0) -= wmax; - angle = 90; - } - /* FIXME: what's the correct offset? - p[0] += (!xySym ? wmax : -wmax); - p[1] += (zd*zv[2] <= 0 ? hmax : -hmax); - */ - break; - case AXE_VERT_DIR: - p(0) -= wmax; - angle = 90; - break; - case AXE_HORZ_DIR: - p(1) += hmax; - break; - } - p = xform.untransform (p(0), p(1), p(2), true); - zlabel_props.set_position (p.extract_n (0, 3).transpose ()); - zlabel_props.set_rotation (angle); - } - } - - set_linestyle ("-"); - - // Title - - text::properties& title_props = - reinterpret_cast<text::properties&> (gh_manager::get_object (props.get_title ()).get_properties ()); - - // FIXME: auto-positioning should be disabled if the - // title has been positioned manually - if (! title_props.get_string ().empty ()) - { - Matrix bb = props.get_boundingbox (true); - ColumnVector p = xform.untransform (bb(0)+bb(2)/2, (bb(1)-10), - (x_zlim(0)+x_zlim(1))/2, true); - title_props.set_position (p.extract_n(0, 3).transpose ()); - } - - set_clipbox (xmin, xmax, ymin, ymax, zmin, zmax); - - // Children - - Matrix children = props.get_children (); - std::list<graphics_object> obj_list; - std::list<graphics_object>::iterator it; - - // 1st pass: draw light objects - - for (int i = 0; i < children.numel (); i++) - { - graphics_object go = gh_manager::get_object (children (i)); - - if (go.get_properties ().is_visible ()) - { - if (go.isa ("light")) - draw (go); - else - obj_list.push_back (go); - } - } - - // 2nd pass: draw other objects (with units set to "data") - - it = obj_list.begin (); - while (it != obj_list.end ()) - { - graphics_object go = (*it); - - // FIXME: check whether object has "units" property and it is set to "data" - if (! go.isa ("text") || go.get ("units").string_value () == "data") - { - set_clipping (go.get_properties ().is_clipping ()); - draw (go); - - it = obj_list.erase (it); - } - else - it++; - } - - // 3rd pass: draw remaining objects - - for (it = obj_list.begin (); it != obj_list.end (); it++) - { - graphics_object go = (*it); - - set_clipping (go.get_properties ().is_clipping ()); - draw (go); - } - - set_clipping (false); - // FIXME: finalize rendering (transparency processing) - // FIXME: draw zoom box, if needed -} - -void -opengl_renderer::draw (const line::properties& props) -{ - Matrix x = xform.xscale (props.get_xdata ().matrix_value ()); - Matrix y = xform.yscale (props.get_ydata ().matrix_value ()); - Matrix z = xform.zscale (props.get_zdata ().matrix_value ()); - - bool has_z = (z.numel () > 0); - int n = static_cast<int> (::xmin (::xmin (x.numel (), y.numel ()), (has_z ? z.numel () : INT_MAX))); - octave_uint8 clip_mask = (props.is_clipping () ? 0x7F : 0x40), clip_ok (0x40); - - std::vector<octave_uint8> clip (n); - - if (has_z) - for (int i = 0; i < n; i++) - clip[i] = (clip_code (x(i), y(i), z(i)) & clip_mask); - else - { - double z_mid = (zmin+zmax)/2; - - for (int i = 0; i < n; i++) - clip[i] = (clip_code (x(i), y(i), z_mid) & clip_mask); - } - - if (! props.linestyle_is ("none")) - { - set_color (props.get_color_rgb ()); - set_linestyle (props.get_linestyle (), false); - set_linewidth (props.get_linewidth ()); - - if (has_z) - { - bool flag = false; - - for (int i = 1; i < n; i++) - { - if ((clip[i-1] & clip[i]) == clip_ok) - { - if (! flag) - { - flag = true; - glBegin (GL_LINE_STRIP); - glVertex3d (x(i-1), y(i-1), z(i-1)); - } - glVertex3d (x(i), y(i), z(i)); - } - else if (flag) - { - flag = false; - glEnd (); - } - } - - if (flag) - glEnd (); - } - else - { - bool flag = false; - - for (int i = 1; i < n; i++) - { - if ((clip[i-1] & clip[i]) == clip_ok) - { - if (! flag) - { - flag = true; - glBegin (GL_LINE_STRIP); - glVertex2d (x(i-1), y(i-1)); - } - glVertex2d (x(i), y(i)); - } - else if (flag) - { - flag = false; - glEnd (); - } - } - - if (flag) - glEnd (); - } - - set_linewidth (0.5); - set_linestyle ("-"); - } - - set_clipping (false); - - if (! props.marker_is ("none") && - ! (props.markeredgecolor_is ("none") - && props.markerfacecolor_is ("none"))) - { - Matrix lc, fc; - - if (props.markeredgecolor_is ("auto")) - lc = props.get_color_rgb (); - else if (! props.markeredgecolor_is ("none")) - lc = props.get_markeredgecolor_rgb (); - - if (props.markerfacecolor_is ("auto")) - fc = props.get_color_rgb (); - else if (! props.markerfacecolor_is ("none")) - fc = props.get_markerfacecolor_rgb (); - - init_marker (props.get_marker (), props.get_markersize (), - props.get_linewidth ()); - - for (int i = 0; i < n; i++) - { - if (clip[i] == clip_ok) - draw_marker (x(i), y(i), (has_z ? z(i) : 0), lc, fc); - } - - end_marker (); - } - - set_clipping (props.is_clipping ()); -} - -void -opengl_renderer::draw (const surface::properties& props) -{ - Matrix x = xform.xscale (props.get_xdata ().matrix_value ()); - Matrix y = xform.yscale (props.get_ydata ().matrix_value ()); - Matrix z = xform.zscale (props.get_zdata ().matrix_value ()); - - int zr = z.rows (), zc = z.columns (); - - NDArray c; - NDArray n = props.get_vertexnormals ().array_value (); - - // FIXME: handle transparency - Matrix a; - - if (props.facelighting_is ("phong") || props.edgelighting_is ("phong")) - warning ("opengl_renderer::draw: phong light model not supported"); - - int fc_mode = (props.facecolor_is_rgb () ? 0 : - (props.facecolor_is ("flat") ? 1 : - (props.facecolor_is ("interp") ? 2 : - (props.facecolor_is ("texturemap") ? 3 : -1)))); - int fl_mode = (props.facelighting_is ("none") ? 0 : - (props.facelighting_is ("flat") ? 1 : 2)); - int fa_mode = (props.facealpha_is_double () ? 0 : - (props.facealpha_is ("flat") ? 1 : 2)); - int ec_mode = (props.edgecolor_is_rgb () ? 0 : - (props.edgecolor_is ("flat") ? 1 : - (props.edgecolor_is ("interp") ? 2 : -1))); - int el_mode = (props.edgelighting_is ("none") ? 0 : - (props.edgelighting_is ("flat") ? 1 : 2)); - int ea_mode = (props.edgealpha_is_double () ? 0 : - (props.edgealpha_is ("flat") ? 1 : 2)); - - Matrix fcolor = (fc_mode == 3 ? Matrix (1, 3, 1.0) : props.get_facecolor_rgb ()); - Matrix ecolor = props.get_edgecolor_rgb (); - - float as = props.get_ambientstrength (); - float ds = props.get_diffusestrength (); - float ss = props.get_specularstrength (); - float se = props.get_specularexponent (); - float cb[4] = { 0, 0, 0, 1 }; - - opengl_texture tex; - - int i1, i2, j1, j2; - bool x_mat = (x.rows () == z.rows ()); - bool y_mat = (y.columns () == z.columns ()); - - i1 = i2 = j1 = j2 = 0; - - boolMatrix clip (z.dims (), false); - - for (int i = 0; i < zr; i++) - { - if (x_mat) - i1 = i; - - for (int j = 0; j < zc; j++) - { - if (y_mat) - j1 = j; - - clip(i,j) = is_nan_or_inf (x(i1,j), y(i,j1), z(i,j)); - } - } - - if ((fc_mode > 0 && fc_mode < 3) || ec_mode > 0) - c = props.get_color_data ().array_value (); - - if (fa_mode > 0 || ea_mode > 0) - { - // FIXME: implement alphadata conversion - //a = props.get_alpha_data (); - } - - if (fl_mode > 0 || el_mode > 0) - { - float buf[4] = { ss, ss, ss, 1 }; - - glMaterialfv (LIGHT_MODE, GL_SPECULAR, buf); - glMaterialf (LIGHT_MODE, GL_SHININESS, se); - } - - // FIXME: good candidate for caching, transfering pixel - // data to OpenGL is time consuming. - if (fc_mode == 3) - tex = opengl_texture::create (props.get_color_data ()); - - if (! props.facecolor_is ("none")) - { - if (props.get_facealpha_double () == 1) - { - if (fc_mode == 0 || fc_mode == 3) - { - glColor3dv (fcolor.data ()); - if (fl_mode > 0) - { - for (int i = 0; i < 3; i++) - cb[i] = (as * fcolor(i)); - glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb); - - for (int i = 0; i < 3; i++) - cb[i] *= (ds / as); - glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb); - } - } - - if (fl_mode > 0) - glEnable (GL_LIGHTING); - glShadeModel ((fc_mode == 2 || fl_mode == 2) ? GL_SMOOTH : GL_FLAT); - set_polygon_offset (true, 1); - if (fc_mode == 3) - glEnable (GL_TEXTURE_2D); - - for (int i = 1; i < zc; i++) - { - if (y_mat) - { - i1 = i-1; - i2 = i; - } - - for (int j = 1; j < zr; j++) - { - if (clip(j-1, i-1) || clip (j, i-1) - || clip (j-1, i) || clip (j, i)) - continue; - - if (x_mat) - { - j1 = j-1; - j2 = j; - } - - glBegin (GL_QUADS); - - // Vertex 1 - if (fc_mode == 3) - tex.tex_coord (double (i-1) / (zc-1), double (j-1) / (zr-1)); - else if (fc_mode > 0) - { - // FIXME: is there a smarter way to do this? - for (int k = 0; k < 3; k++) - cb[k] = c(j-1, i-1, k); - glColor3fv (cb); - - if (fl_mode > 0) - { - for (int k = 0; k < 3; k++) - cb[k] *= as; - glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb); - - for (int k = 0; k < 3; k++) - cb[k] *= (ds / as); - glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb); - } - } - if (fl_mode > 0) - glNormal3d (n(j-1,i-1,0), n(j-1,i-1,1), n(j-1,i-1,2)); - glVertex3d (x(j1,i-1), y(j-1,i1), z(j-1,i-1)); - - // Vertex 2 - if (fc_mode == 3) - tex.tex_coord (double (i) / (zc-1), double (j-1) / (zr-1)); - else if (fc_mode == 2) - { - for (int k = 0; k < 3; k++) - cb[k] = c(j-1, i, k); - glColor3fv (cb); - - if (fl_mode > 0) - { - for (int k = 0; k < 3; k++) - cb[k] *= as; - glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb); - - for (int k = 0; k < 3; k++) - cb[k] *= (ds / as); - glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb); - } - } - if (fl_mode == 2) - glNormal3d (n(j-1,i,0), n(j-1,i,1), n(j-1,i,2)); - glVertex3d (x(j1,i), y(j-1,i2), z(j-1,i)); - - // Vertex 3 - if (fc_mode == 3) - tex.tex_coord (double (i) / (zc-1), double (j) / (zr-1)); - else if (fc_mode == 2) - { - for (int k = 0; k < 3; k++) - cb[k] = c(j, i, k); - glColor3fv (cb); - - if (fl_mode > 0) - { - for (int k = 0; k < 3; k++) - cb[k] *= as; - glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb); - - for (int k = 0; k < 3; k++) - cb[k] *= (ds / as); - glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb); - } - } - if (fl_mode == 2) - glNormal3d (n(j,i,0), n(j,i,1), n(j,i,2)); - glVertex3d (x(j2,i), y(j,i2), z(j,i)); - - // Vertex 4 - if (fc_mode == 3) - tex.tex_coord (double (i-1) / (zc-1), double (j) / (zr-1)); - else if (fc_mode == 2) - { - for (int k = 0; k < 3; k++) - cb[k] = c(j, i-1, k); - glColor3fv (cb); - - if (fl_mode > 0) - { - for (int k = 0; k < 3; k++) - cb[k] *= as; - glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb); - - for (int k = 0; k < 3; k++) - cb[k] *= (ds / as); - glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb); - } - } - if (fl_mode == 2) - glNormal3d (n(j,i-1,0), n(j,i-1,1), n(j,i-1,2)); - glVertex3d (x(j2,i-1), y(j,i1), z(j,i-1)); - - glEnd (); - } - } - - set_polygon_offset (false); - if (fc_mode == 3) - glDisable (GL_TEXTURE_2D); - - if (fl_mode > 0) - glDisable (GL_LIGHTING); - } - else - { - // FIXME: implement transparency - } - } - - if (! props.edgecolor_is ("none")) - { - if (props.get_edgealpha_double () == 1) - { - if (ec_mode == 0) - { - glColor3dv (ecolor.data ()); - if (fl_mode > 0) - { - for (int i = 0; i < 3; i++) - cb[i] = (as * ecolor(i)); - glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb); - - for (int i = 0; i < 3; i++) - cb[i] *= (ds / as); - glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb); - } - } - - if (el_mode > 0) - glEnable (GL_LIGHTING); - glShadeModel ((ec_mode == 2 || el_mode == 2) ? GL_SMOOTH : GL_FLAT); - - set_linestyle (props.get_linestyle (), false); - set_linewidth (props.get_linewidth ()); - - // Mesh along Y-axis - - if (props.meshstyle_is ("both") || props.meshstyle_is ("column")) - { - for (int i = 0; i < zc; i++) - { - if (y_mat) - { - i1 = i-1; - i2 = i; - } - - for (int j = 1; j < zr; j++) - { - if (clip(j-1,i) || clip(j,i)) - continue; - - if (x_mat) - { - j1 = j-1; - j2 = j; - } - - glBegin (GL_LINES); - - // Vertex 1 - if (ec_mode > 0) - { - for (int k = 0; k < 3; k++) - cb[k] = c(j-1, i, k); - glColor3fv (cb); - - if (fl_mode > 0) - { - for (int k = 0; k < 3; k++) - cb[k] *= as; - glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb); - - for (int k = 0; k < 3; k++) - cb[k] *= (ds / as); - glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb); - } - } - if (el_mode > 0) - glNormal3d (n(j-1,i,0), n(j-1,i,1), n(j-1,i,2)); - glVertex3d (x(j1,i), y(j-1,i2), z(j-1,i)); - - // Vertex 2 - if (ec_mode == 2) - { - for (int k = 0; k < 3; k++) - cb[k] = c(j, i, k); - glColor3fv (cb); - - if (fl_mode > 0) - { - for (int k = 0; k < 3; k++) - cb[k] *= as; - glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb); - - for (int k = 0; k < 3; k++) - cb[k] *= (ds / as); - glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb); - } - } - if (el_mode == 2) - glNormal3d (n(j,i,0), n(j,i,1), n(j,i,2)); - glVertex3d (x(j2,i), y(j,i2), z(j,i)); - - glEnd (); - } - } - } - - // Mesh along X-axis - - if (props.meshstyle_is ("both") || props.meshstyle_is ("row")) - { - for (int j = 0; j < zr; j++) - { - if (x_mat) - { - j1 = j-1; - j2 = j; - } - - for (int i = 1; i < zc; i++) - { - if (clip(j,i-1) || clip(j,i)) - continue; - - if (y_mat) - { - i1 = i-1; - i2 = i; - } - - glBegin (GL_LINES); - - // Vertex 1 - if (ec_mode > 0) - { - for (int k = 0; k < 3; k++) - cb[k] = c(j, i-1, k); - glColor3fv (cb); - - if (fl_mode > 0) - { - for (int k = 0; k < 3; k++) - cb[k] *= as; - glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb); - - for (int k = 0; k < 3; k++) - cb[k] *= (ds / as); - glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb); - } - } - if (el_mode > 0) - glNormal3d (n(j,i-1,0), n(j,i-1,1), n(j,i-1,2)); - glVertex3d (x(j2,i-1), y(j,i1), z(j,i-1)); - - // Vertex 2 - if (ec_mode == 2) - { - for (int k = 0; k < 3; k++) - cb[k] = c(j, i, k); - glColor3fv (cb); - - if (fl_mode > 0) - { - for (int k = 0; k < 3; k++) - cb[k] *= as; - glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb); - - for (int k = 0; k < 3; k++) - cb[k] *= (ds / as); - glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb); - } - } - if (el_mode == 2) - glNormal3d (n(j,i,0), n(j,i,1), n(j,i,2)); - glVertex3d (x(j2,i), y(j,i2), z(j,i)); - - glEnd (); - } - } - } - - set_linestyle ("-"); - set_linewidth (0.5); - - if (el_mode > 0) - glDisable (GL_LIGHTING); - } - else - { - // FIXME: implement transparency - } - } - - if (! props.marker_is ("none") && - ! (props.markeredgecolor_is ("none") - && props.markerfacecolor_is ("none"))) - { - // FIXME: check how transparency should be handled in markers - // FIXME: check what to do with marker facecolor set to auto - // and facecolor set to none. - - bool do_edge = ! props.markeredgecolor_is ("none"); - bool do_face = ! props.markerfacecolor_is ("none"); - - Matrix mecolor = props.get_markeredgecolor_rgb (); - Matrix mfcolor = props.get_markerfacecolor_rgb (); - Matrix cc (1, 3, 0.0); - - if (mecolor.numel () == 0 && props.markeredgecolor_is ("auto")) - { - mecolor = props.get_edgecolor_rgb (); - do_edge = ! props.edgecolor_is ("none"); - } - - if (mfcolor.numel () == 0 && props.markerfacecolor_is ("auto")) - { - mfcolor = props.get_facecolor_rgb (); - do_face = ! props.facecolor_is ("none"); - } - - if ((mecolor.numel () == 0 || mfcolor.numel () == 0) - && c.numel () == 0) - c = props.get_color_data ().array_value (); - - init_marker (props.get_marker (), props.get_markersize (), - props.get_linewidth ()); - - for (int i = 0; i < zc; i++) - { - if (y_mat) - i1 = i; - - for (int j = 0; j < zr; j++) - { - if (clip(j,i)) - continue; - - if (x_mat) - j1 = j; - - if ((do_edge && mecolor.numel () == 0) - || (do_face && mfcolor.numel () == 0)) - { - for (int k = 0; k < 3; k++) - cc(k) = c(j,i,k); - } - - Matrix lc = (do_edge ? (mecolor.numel () == 0 ? cc : mecolor) : Matrix ()); - Matrix fc = (do_face ? (mfcolor.numel () == 0 ? cc : mfcolor) : Matrix ()); - - draw_marker (x(j1,i), y(j,i1), z(j,i), lc, fc); - } - } - - end_marker (); - } -} - -// FIXME: global optimization (rendering, data structures...), there -// is probably a smarter/faster/less-memory-consuming way to do this. -void -opengl_renderer::draw (const patch::properties &props) -{ - Matrix f = props.get_faces ().matrix_value (); - Matrix v = xform.scale (props.get_vertices ().matrix_value ()); - Matrix c; - Matrix n = props.get_vertexnormals ().matrix_value (); - Matrix a; - - int nv = v.rows (); - // int vmax = v.columns (); - int nf = f.rows (); - int fcmax = f.columns (); - - bool has_z = (v.columns () > 2); - bool has_facecolor = false; - bool has_facealpha = false; - - int fc_mode = (props.facecolor_is_rgb () ? 0 : - (props.facecolor_is("flat") ? 1 : 2)); - int fl_mode = (props.facelighting_is ("none") ? 0 : - (props.facelighting_is ("flat") ? 1 : 2)); - int fa_mode = (props.facealpha_is_double () ? 0 : - (props.facealpha_is ("flat") ? 1 : 2)); - int ec_mode = (props.edgecolor_is_rgb () ? 0 : - (props.edgecolor_is("flat") ? 1 : 2)); - int el_mode = (props.edgelighting_is ("none") ? 0 : - (props.edgelighting_is ("flat") ? 1 : 2)); - int ea_mode = (props.edgealpha_is_double () ? 0 : - (props.edgealpha_is ("flat") ? 1 : 2)); - - Matrix fcolor = props.get_facecolor_rgb (); - Matrix ecolor = props.get_edgecolor_rgb (); - - float as = props.get_ambientstrength (); - float ds = props.get_diffusestrength (); - float ss = props.get_specularstrength (); - float se = props.get_specularexponent (); - - boolMatrix clip (1, nv, false); - - if (has_z) - for (int i = 0; i < nv; i++) - clip(i) = is_nan_or_inf (v(i,0), v(i,1), v(i,2)); - else - for (int i = 0; i < nv; i++) - clip(i) = is_nan_or_inf (v(i,0), v(i,1), 0); - - boolMatrix clip_f (1, nf, false); - Array<int> count_f (nf, 0); - - for (int i = 0; i < nf; i++) - { - bool fclip = false; - int count = 0; - - for (int j = 0; j < fcmax && ! xisnan (f(i,j)); j++, count++) - fclip = (fclip || clip(int (f(i,j) - 1))); - - clip_f(i) = fclip; - count_f(i) = count; - } - - if (fc_mode > 0 || ec_mode > 0) - { - c = props.get_color_data ().matrix_value (); - - if (c.rows () == 1) - { - // Single color specifications, we can simplify a little bit - - if (fc_mode > 0) - { - fcolor = c; - fc_mode = 0; - } - - if (ec_mode > 0) - { - ecolor = c; - ec_mode = 0; - } - - c = Matrix (); - } - else - has_facecolor = ((c.numel () > 0) && (c.rows () == f.rows ())); - } - - if (fa_mode > 0 || ea_mode > 0) - { - // FIXME: retrieve alpha data from patch object - //a = props.get_alpha_data (); - has_facealpha = ((a.numel () > 0) && (a.rows () == f.rows ())); - } - - Array2<vertex_data> vdata (f.dims ()); - - for (int i = 0; i < nf; i++) - for (int j = 0; j < count_f(i); j++) - { - int idx = int (f(i,j) - 1); - - Matrix vv (1, 3, 0.0); - Matrix cc; - Matrix nn(1, 3, 0.0); - double aa = 1.0; - - vv(0) = v(idx,0); vv(1) = v(idx,1); - if (has_z) - vv(2) = v(idx,2); - // FIXME: uncomment when patch object has normal computation - //nn(0) = n(idx,0); nn(1) = n(idx,1); nn(2) = n(idx,2); - if (c.numel () > 0) - { - cc.resize (1, 3); - if (has_facecolor) - cc(0) = c(i,0), cc(1) = c(i,1), cc(2) = c(i,2); - else - cc(0) = c(idx,0), cc(1) = c(idx,1), cc(2) = c(idx,2); - } - if (a.numel () > 0) - { - if (has_facealpha) - aa = a(i); - else - aa = a(idx); - } - - vdata(i,j) = - vertex_data (vv, cc, nn, aa, as, ds, ss, se); - } - - if (fl_mode > 0 || el_mode > 0) - { - float buf[4] = { ss, ss, ss, 1 }; - - glMaterialfv (LIGHT_MODE, GL_SPECULAR, buf); - glMaterialf (LIGHT_MODE, GL_SHININESS, se); - } - - if (! props.facecolor_is ("none")) - { - // FIXME: adapt to double-radio property - if (props.get_facealpha_double () == 1) - { - if (fc_mode == 0) - { - glColor3dv (fcolor.data ()); - if (fl_mode > 0) - { - float cb[4] = { 0, 0, 0, 1 }; - - for (int i = 0; i < 3; i++) - cb[i] = (as * fcolor(i)); - glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb); - - for (int i = 0; i < 3; i++) - cb[i] *= (ds / as); - glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb); - } - } - - if (fl_mode > 0) - glEnable (GL_LIGHTING); - - // FIXME: use __index__ property from patch object - patch_tesselator tess (this, fc_mode, fl_mode, 0); - - for (int i = 0; i < nf; i++) - { - if (clip_f(i)) - continue; - - tess.begin_polygon (true); - tess.begin_contour (); - - for (int j = 0; j < count_f(i); j++) - { - vertex_data::vertex_data_rep *vv = vdata(i,j).get_rep (); - - tess.add_vertex (vv->coords.fortran_vec (), vv); - } - - tess.end_contour (); - tess.end_polygon (); - } - - if (fl_mode > 0) - glDisable (GL_LIGHTING); - } - else - { - // FIXME: implement transparency - } - } - - if (! props.edgecolor_is ("none")) - { - // FIXME: adapt to double-radio property - if (props.get_edgealpha_double () == 1) - { - if (ec_mode == 0) - { - glColor3dv (ecolor.data ()); - if (el_mode > 0) - { - float cb[4] = { 0, 0, 0, 1 }; - - for (int i = 0; i < 3; i++) - cb[i] = (as * ecolor(i)); - glMaterialfv (LIGHT_MODE, GL_AMBIENT, cb); - - for (int i = 0; i < 3; i++) - cb[i] *= (ds / as); - glMaterialfv (LIGHT_MODE, GL_DIFFUSE, cb); - } - } - - if (el_mode > 0) - glEnable (GL_LIGHTING); - - set_linestyle (props.get_linestyle (), false); - set_linewidth (props.get_linewidth ()); - - // FIXME: use __index__ property from patch object; should we - // offset patch contour as well? - patch_tesselator tess (this, ec_mode, el_mode); - - for (int i = 0; i < nf; i++) - { - if (clip_f(i)) - continue; - - tess.begin_polygon (false); - tess.begin_contour (); - - for (int j = 0; j < count_f(i); j++) - { - vertex_data::vertex_data_rep *vv = vdata(i,j).get_rep (); - - tess.add_vertex (vv->coords.fortran_vec (), vv); - } - - tess.end_contour (); - tess.end_polygon (); - } - - set_linestyle ("-"); - set_linewidth (0.5); - - if (el_mode > 0) - glDisable (GL_LIGHTING); - } - else - { - // FIXME: implement transparency - } - } - - if (! props.marker_is ("none") && - ! (props.markeredgecolor_is ("none") && props.markerfacecolor_is ("none"))) - { - bool do_edge = ! props.markeredgecolor_is ("none"); - bool do_face = ! props.markerfacecolor_is ("none"); - - Matrix mecolor = props.get_markeredgecolor_rgb (); - Matrix mfcolor = props.get_markerfacecolor_rgb (); - Matrix cc (1, 3, 0.0); - - if (mecolor.numel () == 0 && props.markeredgecolor_is ("auto")) - { - mecolor = props.get_edgecolor_rgb (); - do_edge = ! props.edgecolor_is ("none"); - } - - if (mfcolor.numel () == 0 && props.markerfacecolor_is ("auto")) - { - mfcolor = props.get_facecolor_rgb (); - do_face = ! props.facecolor_is ("none"); - } - - init_marker (props.get_marker (), props.get_markersize (), - props.get_linewidth ()); - - for (int i = 0; i < nf; i++) - for (int j = 0; j < count_f(i); j++) - { - int idx = int (f(i,j) - 1); - - if (clip(idx)) - continue; - - Matrix lc = (do_edge ? (mecolor.numel () == 0 ? - vdata(i,j).get_rep ()->color : mecolor) - : Matrix ()); - Matrix fc = (do_face ? (mfcolor.numel () == 0 ? - vdata(i,j).get_rep ()->color : mfcolor) - : Matrix ()); - - draw_marker (v(idx,0), v(idx,1), (has_z ? v(idx,2) : 0), lc, fc); - } - - end_marker (); - } -} - -void -opengl_renderer::draw (const hggroup::properties &props) -{ - draw (props.get_children ()); -} - -void -opengl_renderer::set_viewport (int w, int h) -{ - glViewport (0, 0, w, h); -} - -void -opengl_renderer::set_color (const Matrix& c) -{ - glColor3dv (c.data ()); -} - -void -opengl_renderer::set_polygon_offset (bool on, double offset) -{ - if (on) - { - glPolygonOffset (offset, offset); - glEnable (GL_POLYGON_OFFSET_FILL); - } - else - glDisable (GL_POLYGON_OFFSET_FILL); -} - -void -opengl_renderer::set_linewidth (float w) -{ - glLineWidth (w); -} - -void -opengl_renderer::set_linestyle (const std::string& s, bool use_stipple) -{ - bool solid = false; - - if (s == "-") - { - glLineStipple (1, static_cast<unsigned short> (0xFFFF)); - solid = true; - } - else if (s == ":") - glLineStipple (1, static_cast<unsigned short> (0x8888)); - else if (s == "--") - glLineStipple (1, static_cast<unsigned short> (0x0FFF)); - else if (s == "-.") - glLineStipple (1, static_cast<unsigned short> (0x020F)); - else - glLineStipple (1, static_cast<unsigned short> (0x0000)); - - if (solid && ! use_stipple) - glDisable (GL_LINE_STIPPLE); - else - glEnable (GL_LINE_STIPPLE); -} - -void -opengl_renderer::set_clipbox (double x1, double x2, double y1, double y2, - double z1, double z2) -{ - double dx = (x2-x1); - double dy = (y2-y1); - double dz = (z2-z1); - - x1 -= 0.001*dx; x2 += 0.001*dx; - y1 -= 0.001*dy; y2 += 0.001*dy; - z1 -= 0.001*dz; z2 += 0.001*dz; - - ColumnVector p (4, 0.0); - - p(0) = -1; p(3) = x2; - glClipPlane (GL_CLIP_PLANE0, p.data ()); - p(0) = 1; p(3) = -x1; - glClipPlane (GL_CLIP_PLANE1, p.data ()); - p(0) = 0; p(1) = -1; p(3) = y2; - glClipPlane (GL_CLIP_PLANE2, p.data ()); - p(1) = 1; p(3) = -y1; - glClipPlane (GL_CLIP_PLANE3, p.data ()); - p(1) = 0; p(2) = -1; p(3) = z2; - glClipPlane (GL_CLIP_PLANE4, p.data ()); - p(2) = 1; p(3) = -z1; - glClipPlane (GL_CLIP_PLANE5, p.data ()); - - xmin = x1; xmax = x2; - ymin = y1; ymax = y2; - zmin = z1; zmax = z2; -} - -void -opengl_renderer::set_clipping (bool enable) -{ - bool has_clipping = (glIsEnabled (GL_CLIP_PLANE0) == GL_TRUE); - - if (enable != has_clipping) - { - if (enable) - for (int i = 0; i < 6; i++) - glEnable (GL_CLIP_PLANE0+i); - else - for (int i = 0; i < 6; i++) - glDisable (GL_CLIP_PLANE0+i); - } -} - -void -opengl_renderer::init_marker (const std::string& m, double size, float width) -{ - int vw[4]; - - glGetIntegerv (GL_VIEWPORT, vw); - - glMatrixMode (GL_PROJECTION); - glPushMatrix (); - glLoadIdentity (); - glOrtho (0, vw[2], vw[3], 0, xZ1, xZ2); - glMatrixMode (GL_MODELVIEW); - glPushMatrix (); - - set_clipping (false); - set_linewidth (width); - - marker_id = make_marker_list (m, size, false); - filled_marker_id = make_marker_list (m, size, true); -} - -void -opengl_renderer::end_marker (void) -{ - glDeleteLists (marker_id, 1); - glDeleteLists (filled_marker_id, 1); - - glMatrixMode (GL_MODELVIEW); - glPopMatrix (); - glMatrixMode (GL_PROJECTION); - glPopMatrix (); - set_linewidth (0.5f); -} - -void -opengl_renderer::draw_marker (double x, double y, double z, - const Matrix& lc, const Matrix& fc) -{ - ColumnVector tmp = xform.transform (x, y, z, false); - - glLoadIdentity (); - glTranslated (tmp(0), tmp(1), -tmp(2)); - - if (fc.numel () > 0) - { - glColor3dv (fc.data ()); - set_polygon_offset (true, 1.0); - glCallList (filled_marker_id); - set_polygon_offset (false); - } - - if (lc.numel () > 0) - { - glColor3dv (lc.data ()); - glCallList (marker_id); - } -} - -unsigned int -opengl_renderer::make_marker_list (const std::string& marker, double size, - bool filled) const -{ - unsigned int ID = glGenLists (1); - double sz = size * backend.get_screen_resolution () / 72.0; - - // constants for the * marker - const double sqrt2d4 = 0.35355339059327; - double tt = sz*sqrt2d4; - - glNewList (ID, GL_COMPILE); - - switch (marker[0]) - { - case '+': - glBegin (GL_LINES); - glVertex2f (-sz/2 ,0 ); - glVertex2f (sz/2 ,0 ); - glVertex2f (0 ,-sz/2 ); - glVertex2f (0 ,sz/2 ); - glEnd (); - break; - case 'x': - glBegin(GL_LINES); - glVertex2f (-sz/2 ,-sz/2); - glVertex2f (sz/2 ,sz/2 ); - glVertex2f (-sz/2 ,sz/2 ); - glVertex2f (sz/2 ,-sz/2 ); - glEnd (); - break; - case '*': - glBegin (GL_LINES); - glVertex2f (-sz/2 ,0 ); - glVertex2f (sz/2 ,0 ); - glVertex2f (0 ,-sz/2 ); - glVertex2f (0 ,sz/2 ); - glVertex2f (-tt ,-tt ); - glVertex2f (+tt ,+tt ); - glVertex2f (-tt ,+tt ); - glVertex2f (+tt ,-tt ); - glEnd (); - break; - case '.': - glBegin (GL_POLYGON); - glVertex2f (-sz/10, -sz/10); - glVertex2f (-sz/10, sz/10 ); - glVertex2f (sz/10 , sz/10 ); - glVertex2f (sz/10 , -sz/10); - glEnd (); - break; - case 's': - glBegin ((filled ? GL_POLYGON : GL_LINE_LOOP)); - glVertex2d (-sz/2, -sz/2); - glVertex2d (-sz/2, sz/2); - glVertex2d ( sz/2, sz/2); - glVertex2d ( sz/2, -sz/2); - glEnd(); - break; - case 'o': - { - double ang_step = M_PI / 5; - - glBegin ((filled ? GL_POLYGON : GL_LINE_LOOP)); - for (double ang = 0; ang < (2*M_PI); ang += ang_step) - glVertex2d (sz*cos(ang)/2, sz*sin(ang)/2); - glEnd (); - } - break; - case 'd': - glBegin ((filled ? GL_POLYGON : GL_LINE_LOOP)); - glVertex2d ( 0, -sz/2); - glVertex2d ( sz/2, 0); - glVertex2d ( 0, sz/2); - glVertex2d (-sz/2, 0); - glEnd(); - break; - case '^': - glBegin ((filled ? GL_POLYGON : GL_LINE_LOOP)); - glVertex2f (0 , sz/2); - glVertex2f (sz/2 , -sz/2); - glVertex2f (-sz/2 , -sz/2); - glEnd (); - break; - case 'v': - glBegin ((filled ? GL_POLYGON : GL_LINE_LOOP)); - glVertex2f (0 ,-sz/2); - glVertex2f (-sz/2 ,sz/2 ); - glVertex2f (sz/2 ,sz/2 ); - glEnd (); - break; - case '>': - glBegin ((filled ? GL_POLYGON : GL_LINE_LOOP)); - glVertex2f (sz/2 ,0 ); - glVertex2f (-sz/2 ,sz/2 ); - glVertex2f (-sz/2 ,-sz/2); - glEnd (); - break; - case '<': - glBegin ((filled ? GL_POLYGON : GL_LINE_LOOP)); - glVertex2f (-sz/2 ,0 ); - glVertex2f (sz/2 ,-sz/2); - glVertex2f (sz/2 ,sz/2 ); - glEnd (); - default: - warning ("opengl_renderer: unsupported marker `%s'", - marker.c_str ()); - break; - } - - glEndList (); - - return ID; -}
--- a/src/graphics/opengl/gl-render.h Thu Jun 05 20:42:14 2008 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,138 +0,0 @@ -/* - -Copyright (C) 2008 Michael Goffioul - -This file is part of Octave. - -Octave is free software; you can redistribute it and/or modify it -under the terms of the GNU General Public License as published by the -Free Software Foundation; either version 3 of the License, or (at your -option) any later version. - -Octave is distributed in the hope that it will be useful, but WITHOUT -ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or -FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License -for more details. - -You should have received a copy of the GNU General Public License -along with Octave; see the file COPYING. If not, see -<http://www.gnu.org/licenses/>. - -*/ - -#if !defined (gl_render_h) -#define gl_render_h 1 - -#include "config.h" - -#ifdef HAVE_WINDOWS_H -#include <windows.h> -#endif - -#include <GL/gl.h> -#include <GL/glu.h> - -#include "graphics.h" - -class -OCTGRAPHICS_API -opengl_renderer -{ -public: - opengl_renderer (void) { } - - virtual ~opengl_renderer (void) { } - - virtual void draw (const graphics_handle& h) - { draw (gh_manager::get_object (h)); } - - virtual void draw (const graphics_object& go); - - virtual void draw (const Matrix& hlist) - { - int len = hlist.length (); - - for (int i = 0; i < len; i++) - { - graphics_handle h = gh_manager::lookup (hlist(i)); - - if (h.ok ()) - draw (h); - } - } - - virtual void set_viewport (int w, int h); - -protected: - virtual void draw (const figure::properties& props); - virtual void draw (const axes::properties& props); - virtual void draw (const line::properties& props); - virtual void draw (const surface::properties& props); - virtual void draw (const patch::properties& props); - virtual void draw (const hggroup::properties& props); - - virtual void set_color (const Matrix& c); - virtual void set_polygon_offset (bool on, double offset = 0.0); - virtual void set_linewidth (float w); - virtual void set_linestyle (const std::string& s, bool stipple = false); - virtual void set_clipbox (double x1, double x2, double y1, double y2, - double z1, double z2); - virtual void set_clipping (bool on); - - virtual void init_marker (const std::string& m, double size, float width); - virtual void end_marker (void); - virtual void draw_marker (double x, double y, double z, - const Matrix& lc, const Matrix& fc); - -private: - opengl_renderer (const opengl_renderer&) { } - - opengl_renderer& operator = (const opengl_renderer&) - { return *this; } - - bool is_nan_or_inf (double x, double y, double z) const - { - return (xisnan (x) || xisnan (y) || xisnan (z) - || xisinf (x) || xisinf (y) || xisinf (z)); - } - - octave_uint8 clip_code (double x, double y, double z) const - { - return ((x < xmin ? 1 : 0) - | (x > xmax ? 1 : 0) << 1 - | (y < ymin ? 1 : 0) << 2 - | (y > ymax ? 1 : 0) << 3 - | (z < zmin ? 1 : 0) << 4 - | (z > zmax ? 1 : 0) << 5 - | (is_nan_or_inf (x, y, z) ? 0 : 1) << 6); - } - - unsigned int make_marker_list (const std::string& m, double size, - bool filled) const; - -private: - // the backend associated with the figure being rendered - graphics_backend backend; - - // axes transformation data - graphics_xform xform; - - // axis limits in model scaled coordinate - double xmin, xmax; - double ymin, ymax; - double zmin, zmax; - - // Z projection limits in windows coordinate - double xZ1, xZ2; - - // call lists identifiers for markers - unsigned int marker_id, filled_marker_id; - - // camera information for primitive sorting - ColumnVector camera_pos, camera_dir; - -private: - class patch_tesselator; -}; - -#endif