Mercurial > hg > octave-nkf
diff src/graphics/opengl/gl-render.cc @ 7829:8ca8e97e8c0a
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.
author | Michael Goffioul <michael.goffioul@gmail.com> |
---|---|
date | Thu, 14 Feb 2008 12:17:44 +0100 |
parents | 13871b7de124 |
children | c7925666f0bf |
line wrap: on
line diff
--- a/src/graphics/opengl/gl-render.cc +++ b/src/graphics/opengl/gl-render.cc @@ -30,12 +30,15 @@ #include <GL/gl.h> #include <GL/glu.h> +#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<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 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);