# HG changeset patch # User Michael Goffioul # Date 1202987864 -3600 # Node ID 8ca8e97e8c0aef9132d581b74c67634ef2a2742c # Parent 4739b6a1925cc9abca61ee4e5d13dc6ff9141700 Add rendering interface for surface object (no implementation yet). * * * Add surface properties. * * * Add cdata -> RGB color conversion function. Use it in surface objects. * * * Add normals automatic computation to surface objects. * * * Make sure the correct "get" method is called. * * * Extend scaler interface to accept NDArray. * * * Surface rendering (1st part). * * * Fix wrong indexing. * * * Fix bug in xget_ancestor argument declaration. * * * Initialize OpenGL context correctly. Fix bug in surface rendering. * * * Set material color when rendering surface facets. * * * Add rendering of surface mesh and markers. diff -r 4739b6a1925c -r 8ca8e97e8c0a src/ChangeLog --- a/src/ChangeLog Wed Feb 13 17:06:22 2008 +0100 +++ b/src/ChangeLog Thu Feb 14 12:17:44 2008 +0100 @@ -15,6 +15,49 @@ 2008-06-04 Michael Goffioul + * graphics.cc (xget_ancestor): Pass graphics_object argument by value + instead of by reference. + + * graphics.h.in (surface::properties::xdata, + surface::properties::ydata, surface::properties::zdata, + surface::properties::normalmode, surface::properties::vertexnormals): + Add 'u' modifier. + (surface::properties::update_normals): New method to compute normals + automatically. + (surface::properties::update_xdata, surface::properties::update_ydata, + surface::properties::update_zdata, + surface::properties::update_normalmode, + surface::properties::update_vertexnormals): New updaters to update + normals automatically. + * graphics.cc (surface::properties::update_normals): Likewise. + (cross_product): New inlined utility function for cross product + computation adn accumulation. + + * graphics.h.in (class base_scaler, class lin_scaler, class + log_scaler, class scaler): Add scale method for NDArray. + (log_scaler::do_scale): Factorize scaling code. + + * graphics.h.in (figure::properties::update_position): Re-remove. + (figure::properties::facecolor): Re-add 'texturemap' value. + (surface::properties::get_color_data): New method to compute actual + surface color data from cdata. + * graphics.cc (surface::properties::get_color_data): Likewise. + (xget_ancestor): New utility function to retrieve an ancestor of a + given type. + (convert_cdata): New utility function to convert cdata property into + actual color data. + + * graphics.h.in (surface::properties::facecolor): Add "texturemap" + as possible value. + (class surface::properties): New properties alphadata, + alphadatmapping, ambientstrength, backfacelighting, diffusestrength, + edgealpha, edgelighting, erasemode, facelighting, meshstyle, + normalmode, specularcolorreflectance, specularexponent, + specularstrength, vertexnormals. + (surface::properties::init): Add constraints for alphadata, + vertexnormals and cdata (the latter are commented until cdata + has changed type). + * graphics.h.in (base_properties::update_boundingbox): New method to handle object resize. (figure::properties::set_boundingbox): New method to set figure diff -r 4739b6a1925c -r 8ca8e97e8c0a src/graphics.cc --- a/src/graphics.cc Wed Feb 13 17:06:22 2008 +0100 +++ b/src/graphics.cc Thu Feb 14 12:17:44 2008 +0100 @@ -333,6 +333,101 @@ return retval; } +static graphics_object +xget_ancestor (graphics_object go, const std::string& type) +{ + do + { + if (go.valid_object ()) + { + if (go.isa (type)) + return go; + else + go = gh_manager::get_object (go.get_parent ()); + } + else + return graphics_object (); + } while (true); +} + +static octave_value +convert_cdata (const base_properties& props, const octave_value& cdata, + bool is_scaled, int cdim) +{ + dim_vector dv (cdata.dims ()); + + if (dv.length () == cdim && dv(cdim-1) == 3) + return cdata; + + Matrix cmap (1, 3, 0.0); + Matrix clim (1, 2, 0.0); + + graphics_object go = gh_manager::get_object (props.get___myhandle__ ()); + graphics_object fig = xget_ancestor (go, "figure"); + + if (fig.valid_object ()) + { + Matrix _cmap = fig.get (caseless_str ("colormap")).matrix_value (); + + if (! error_state) + cmap = _cmap; + } + + if (is_scaled) + { + graphics_object ax = xget_ancestor (go, "axes"); + + if (ax.valid_object ()) + { + Matrix _clim = ax.get (caseless_str ("clim")).matrix_value (); + + if (! error_state) + clim = _clim; + } + } + + dv.resize (cdim); + dv(cdim-1) = 3; + + NDArray a (dv); + + int lda = static_cast (a.numel () / 3); + int nc = cmap.rows (); + + double *av = a.fortran_vec (); + const double *cmapv = cmap.data (); + const double *cv = 0; + const octave_uint8 *icv = 0; + + if (cdata.is_integer_type ()) + icv = cdata.uint8_array_value ().data (); + else + cv = cdata.array_value ().data (); + + for (int i = 0; i < lda; i++) + { + double x = (cv ? cv[i] : double (icv[i])); + + if (is_scaled) + x = xround ((nc - 1) * (x - clim(0)) / (clim(1) - clim(0))); + else + x = xround (x - 1); + + if (x < 0) + x = 0; + else if (x >= nc) + x = (nc - 1); + + int idx = static_cast (x); + + av[i] = cmapv[idx]; + av[i+lda] = cmapv[idx+nc]; + av[i+2*lda] = cmapv[idx+2*nc]; + } + + return octave_value (a); +} + // --------------------------------------------------------------------- radio_values::radio_values (const std::string& opt_string) @@ -2660,7 +2755,90 @@ // --------------------------------------------------------------------- -// Note: "surface" code is entirely auto-generated +octave_value +surface::properties::get_color_data (void) const +{ + return convert_cdata (*this, get_cdata (), cdatamapping_is ("scaled"), 3); +} + +inline void +cross_product (double x1, double y1, double z1, + double x2, double y2, double z2, + double& x, double& y, double& z) +{ + x += (y1 * z2 - z1 * y2); + y += (z1 * x2 - x1 * z2); + z += (x1 * y2 - y1 * x2); +} + +void +surface::properties::update_normals (void) +{ + if (normalmode_is ("auto")) + { + Matrix x = get_xdata ().matrix_value (); + Matrix y = get_ydata ().matrix_value (); + Matrix z = get_zdata ().matrix_value (); + + int p = z.columns (), q = z.rows (); + int i1, i2, i3; + int j1, j2, j3; + + bool x_mat = (x.rows () == q); + bool y_mat = (y.columns () == p); + + NDArray n (dim_vector (q, p, 3), 0.0); + + i1 = i2 = i3 = 0; + j1 = j2 = j3 = 0; + + // FIXME: normal computation at boundaries + for (int i = 1; i < (p-1); i++) + { + if (y_mat) + { + i1 = i-1; + i2 = i; + i3 = i+1; + } + + for (int j = 1; j < (q-1); j++) + { + if (x_mat) + { + j1 = j-1; + j2 = j; + j3 = j+1; + } + + double& nx = n(j, i, 0); + double& ny = n(j, i, 1); + double& nz = n(j, i, 2); + + cross_product (x(j3,i)-x(j2,i), y(j+1,i2)-y(j,i2), z(j+1,i)-z(j,i), + x(j2,i+1)-x(j2,i), y(j,i3)-y(j,i2), z(j,i+1)-z(i,j), + nx, ny, nz); + cross_product (x(j2,i-1)-x(j2,i), y(j,i1)-y(j,i2), z(j,i-1)-z(j,i), + x(j3,i)-x(j2,i), y(j+1,i2)-y(j,i2), z(j+1,i)-z(i,j), + nx, ny, nz); + cross_product (x(j1,i)-x(j2,i), y(j-1,i2)-y(j,i2), z(j-1,i)-z(j,i), + x(j2,i-1)-x(j2,i), y(j,i1)-y(j,i2), z(j,i-1)-z(i,j), + nx, ny, nz); + cross_product (x(j2,i+1)-x(j2,i), y(j,i3)-y(j,i2), z(j,i+1)-z(j,i), + x(j1,i)-x(j2,i), y(j-1,i2)-y(j,i2), z(j-1,i)-z(i,j), + nx, ny, nz); + + double d = - sqrt (nx*nx + ny*ny + nz*nz); + + nx /= d; + ny /= d; + nz /= d; + } + } + + vertexnormals = n; + } +} // --------------------------------------------------------------------- diff -r 4739b6a1925c -r 8ca8e97e8c0a src/graphics.h.in --- a/src/graphics.h.in Wed Feb 13 17:06:22 2008 +0100 +++ b/src/graphics.h.in Thu Feb 14 12:17:44 2008 +0100 @@ -195,6 +195,12 @@ return m; } + virtual NDArray scale (const NDArray& m) const + { + error ("invalid axis scale"); + return m; + } + virtual double scale (double d) const { error ("invalid axis scale"); @@ -218,6 +224,8 @@ Matrix scale (const Matrix& m) const { return m; } + NDArray scale (const NDArray& m) const { return m; } + double scale (double d) const { return d; } double unscale (double d) const { return d; } @@ -233,12 +241,16 @@ Matrix scale (const Matrix& m) const { Matrix retval (m.rows (), m.cols ()); - const double *d1 = m.fortran_vec (); - double *d2 = retval.fortran_vec (); - - for (int i = 0; i < m.numel (); i++) - d2[i] = log10 (d1[i]); - + + do_scale (m.data (), retval.fortran_vec (), m.numel ()); + return retval; + } + + NDArray scale (const NDArray& m) const + { + NDArray retval (m.dims ()); + + do_scale (m.data (), retval.fortran_vec (), m.numel ()); return retval; } @@ -250,6 +262,13 @@ base_scaler* clone (void) const { return new log_scaler (); } + +private: + void do_scale (const double *src, double *dest, int n) const + { + for (int i = 0; i < n; i++) + dest[i] = log10(src[i]); + } }; class scaler @@ -264,6 +283,9 @@ Matrix scale (const Matrix& m) const { return rep->scale (m); } + NDArray scale (const NDArray& m) const + { return rep->scale (m); } + double scale (double d) const { return rep->scale (d); } @@ -2900,16 +2922,20 @@ class OCTINTERP_API properties : public base_properties { public: + octave_value get_color_data (void) const; + // See the genprops.awk script for an explanation of the // properties declarations. BEGIN_PROPERTIES(surface) - data_property xdata l , Matrix () - data_property ydata l , Matrix () - data_property zdata l , Matrix () + data_property xdata lu , Matrix () + data_property ydata lu , Matrix () + data_property zdata lu , Matrix () + // FIXME: cdata can be of type "double" or "uint8" data_property cdata l , Matrix () radio_property cdatamapping a , "{scaled}|direct" - color_property facecolor , "{flat}|none|interp" + color_property facecolor , "{flat}|none|interp|texturemap" + // FIXME: should be a double-radio property double_property facealpha , 1.0 color_property edgecolor , color_property (color_values (0, 0, 0), radio_values ("flat|none|interp")) radio_property linestyle , "{-}|--|:|-.|none" @@ -2920,12 +2946,50 @@ double_property markersize , 6 string_property keylabel , "" radio_property interpreter , "{tex}|none|latex" + array_property alphadata , Matrix () + radio_property alphadatamapping , "none|direct|{scaled}" + double_property ambientstrength , 0.3 + radio_property backfacelighting , "unlit|lit|{reverselit}" + double_property diffusestrength , 0.6 + // FIXME: should be a double-radio property + double_property edgealpha , 1.0 + radio_property edgelighting , "{none}|flat|gouraud|phong" + radio_property erasemode , "{normal}|none|xor|background" + radio_property facelighting , "{none}|flat|gouraud|phong" + radio_property meshstyle , "{both}|row|column" + radio_property normalmode u , "{auto}|manual" + double_property specularcolorreflectance , 1 + double_property specularexponent , 10 + double_property specularstrength , 0.9 + array_property vertexnormals u , Matrix () END_PROPERTIES protected: void init (void) { + alphadata.add_constraint ("double"); + alphadata.add_constraint ("uint8"); + alphadata.add_constraint (dim_vector (-1, -1)); + vertexnormals.add_constraint (dim_vector (-1, -1, 3)); + // FIXME: uncomment this when cdata has the right type + //cdata.add_constraint ("double"); + //cdata.add_constraint ("double"); + //cdata.add_constraint (dim_vector (-1, -1)); + //cdata.add_constraint (dim_vector (-1, -1, 3)); } + + private: + void update_normals (void); + + void update_xdata (void) { update_normals (); } + void update_ydata (void) { update_normals (); } + void update_zdata (void) { update_normals (); } + + void update_normalmode (void) + { update_normals (); } + + void update_vertexnormals (void) + { set_normalmode ("manual"); } }; private: diff -r 4739b6a1925c -r 8ca8e97e8c0a src/graphics/ChangeLog --- a/src/graphics/ChangeLog Wed Feb 13 17:06:22 2008 +0100 +++ b/src/graphics/ChangeLog Thu Feb 14 12:17:44 2008 +0100 @@ -1,3 +1,23 @@ +2008-02-17 Michael Goffioul + + * 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 + + * 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 + + * opengl/gl-render.h opengl/gl-render.cc: Add rendering + interface for surface objects (actual implement still + missing). + 2008-06-04 Michael Goffioul * Makefile.in Makerules.in: Initial import diff -r 4739b6a1925c -r 8ca8e97e8c0a src/graphics/opengl/gl-render.cc --- a/src/graphics/opengl/gl-render.cc Wed Feb 13 17:06:22 2008 +0100 +++ b/src/graphics/opengl/gl-render.cc Thu Feb 14 12:17:44 2008 +0100 @@ -30,12 +30,15 @@ #include #include +#define LIGHT_MODE GL_FRONT_AND_BACK + enum { AXE_ANY_DIR = 0, AXE_DEPTH_DIR = 1, AXE_HORZ_DIR = 2, AXE_VERT_DIR = 3 }; + void opengl_renderer::draw (const graphics_object& go) { @@ -50,6 +53,8 @@ draw (dynamic_cast (props)); else if (go.isa ("line")) draw (dynamic_cast (props)); + else if (go.isa ("surface")) + draw (dynamic_cast (props)); else warning ("opengl_renderer: cannot render object of type `%s'", props.graphics_object_name ().c_str ()); @@ -60,6 +65,15 @@ { 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) @@ -68,6 +82,8 @@ glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } + // Draw children + draw (props.get_children ()); } @@ -1187,6 +1203,508 @@ } 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)); + // FIXME: use facealpha as double-radio property + int fa_mode = 0; + 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)); + // FIXME: use edgealpha as double-radio property + int ea_mode = 0; + + 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 }; + + 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 ()); + + for (int i = 0; i < zr; i++) + { + if (x_mat) + i1 = i; + + for (int j = 0; j < zr; 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); + } + + if (fc_mode == 3) + { + // FIXME: transfer texture to OpenGL + } + + if (! props.facecolor_is ("none")) + { + // FIXME: adapt to double-radio property type + if (props.get_facealpha () == 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) + /* FIXME: set texture coordinates */; + 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) + /* FIXME: set texture coordinates */; + 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) + /* FIXME: set texture coordinates */; + 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) + /* FIXME: set texture coordinates */; + 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")) + { + // FIXME: adapt to double-radio property + if (props.get_edgealpha () == 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 (); + } +} + +void opengl_renderer::set_viewport (int w, int h) { glViewport (0, 0, w, h); diff -r 4739b6a1925c -r 8ca8e97e8c0a src/graphics/opengl/gl-render.h --- a/src/graphics/opengl/gl-render.h Wed Feb 13 17:06:22 2008 +0100 +++ b/src/graphics/opengl/gl-render.h Thu Feb 14 12:17:44 2008 +0100 @@ -58,6 +58,7 @@ 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 set_color (const Matrix& c); virtual void set_polygon_offset (bool on, double offset = 0.0);