changeset 7831:c7925666f0bf

Add OpenGL texture wrapper class (not complete yet). * * * Implement texture mapping. Fix bug in surface clipping computation. * * * Fix texture scaling. * * * Fix data types when creating OpenGL textures.
author Michael Goffioul <michael.goffioul@gmail.com>
date Mon, 18 Feb 2008 17:02:12 +0100
parents 61aee739a4da
children e06fdf7ea647
files src/graphics/ChangeLog src/graphics/opengl/gl-render.cc
diffstat 2 files changed, 194 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- a/src/graphics/ChangeLog	Sun Feb 17 22:27:48 2008 +0100
+++ b/src/graphics/ChangeLog	Mon Feb 18 17:02:12 2008 +0100
@@ -1,3 +1,20 @@
+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
--- a/src/graphics/opengl/gl-render.cc	Sun Feb 17 22:27:48 2008 +0100
+++ b/src/graphics/opengl/gl-render.cc	Mon Feb 18 17:02:12 2008 +0100
@@ -39,6 +39,172 @@
   AXE_VERT_DIR  = 3
 };
 
+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, (4*tw*th));
+
+	  for (int i = 0; i < h; i++)
+	    for (int j = 0, idx = i*tw*4; j < w; j++, idx += 4)
+	      {
+		a[idx]   = _a(i,j,0);
+		a[idx+1] = _a(i,j,1);
+		a[idx+2] = _a(i,j,2);
+		a[idx+3] = 1.0;
+	      }
+
+	  glTexImage2D (GL_TEXTURE_2D, 0, 4, tw, th, 0,
+			GL_RGBA, GL_FLOAT, a);
+	}
+      else if (data.is_uint8_type ())
+	{
+	  uint8NDArray _a = data.uint8_array_value ();
+
+	  OCTAVE_LOCAL_BUFFER (octave_uint8, a, (4*tw*th));
+
+	  for (int i = 0; i < h; i++)
+	    for (int j = 0, idx = i*tw*4; j < w; j++, idx += 4)
+	      {
+		a[idx]   = _a(i,j,0);
+		a[idx+1] = _a(i,j,1);
+		a[idx+2] = _a(i,j,2);
+		a[idx+3] = octave_uint8 (0xFF);
+	      }
+
+	  glTexImage2D (GL_TEXTURE_2D, 0, 4, tw, th, 0,
+			GL_RGBA, 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;
+}
+
 void
 opengl_renderer::draw (const graphics_object& go)
 {
@@ -1245,20 +1411,22 @@
   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 ());
+  boolMatrix clip (z.dims (), false);
 
   for (int i = 0; i < zr; i++)
     {
       if (x_mat)
 	i1 = i;
 
-      for (int j = 0; j < zr; j++)
+      for (int j = 0; j < zc; j++)
 	{
 	  if (y_mat)
 	    j1 = j;
@@ -1284,10 +1452,10 @@
       glMaterialf (LIGHT_MODE, GL_SHININESS, se);
     }
 
+  // FIXME: good candidate for caching, transfering pixel
+  // data to OpenGL is time consuming.
   if (fc_mode == 3)
-    {
-      // FIXME: transfer texture to OpenGL
-    }
+    tex = opengl_texture::create (props.get_color_data ());
 
   if (! props.facecolor_is ("none"))
     {
@@ -1340,7 +1508,7 @@
 
 		  // Vertex 1
 		  if (fc_mode == 3)
-		    /* FIXME: set texture coordinates */;
+		    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?
@@ -1365,7 +1533,7 @@
 
 		  // Vertex 2
 		  if (fc_mode == 3)
-		    /* FIXME: set texture coordinates */;
+		    tex.tex_coord (double (i) / (zc-1), double (j-1) / (zr-1));
 		  else if (fc_mode == 2)
 		    {
 		      for (int k = 0; k < 3; k++)
@@ -1389,7 +1557,7 @@
 		  
 		  // Vertex 3
 		  if (fc_mode == 3)
-		    /* FIXME: set texture coordinates */;
+		    tex.tex_coord (double (i) / (zc-1), double (j) / (zr-1));
 		  else if (fc_mode == 2)
 		    {
 		      for (int k = 0; k < 3; k++)
@@ -1413,7 +1581,7 @@
 		  
 		  // Vertex 4
 		  if (fc_mode == 3)
-		    /* FIXME: set texture coordinates */;
+		    tex.tex_coord (double (i-1) / (zc-1), double (j) / (zr-1));
 		  else if (fc_mode == 2)
 		    {
 		      for (int k = 0; k < 3; k++)