[vtk-developers] Re: [vtkusers] fix for large OpenGL Textures

Tim Hutton T.Hutton at eastman.ucl.ac.uk
Fri Aug 10 07:40:09 EDT 2001


Hi guys,

Could we get this change incorporated into the main VTK tree? Several users 
(myself included) seem have this texture limit problem.

Feelings?

Tim.

At 13:17 10/08/2001 +0200, you wrote:
>Content-Type: text/plain;
>         charset="iso-8859-1"
>X-MIME-Autoconverted: from 8bit to quoted-printable by public.kitware.com 
>id HAA07047
>
>Hi,
>
>OpenGL has a maximum texture size (defined by GL_MAX_TEXTURE_SIZE), which
>depends on your video card/drivers.
>vtk resamples an image in vtkOpenGLTexture but does not take into account
>this maximum. I include a fix that does take it into account.
>
>
>================
>Joris Vanden Wyngaerd
>coordinates : http://www.esat.kuleuven.ac.be/~joris/personalia.html
>
>"Quand les degoûtés s'en vont il ne restent que les degoûtants"
>
>
-------------- next part --------------
// vtkPSIOpenGLTexture.cpp: implementation of the vtkPSIOpenGLTexture class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "vtkPSIOpenGLTexture.h"
#include "vtkPSIGlobalFunctions.h"
#include "vtkPSIDebugFunctions.h"
#include "vtkRenderWindow.h"
#include <GL/gl.h>

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

vtkPSIOpenGLTexture::vtkPSIOpenGLTexture()
{

}

vtkPSIOpenGLTexture::~vtkPSIOpenGLTexture()
{

}
/*
// Release the graphics resources used by this texture.  
void vtkPSIOpenGLTexture::ReleaseGraphicsResources(vtkWindow *renWin)
{
	// removed because of memory violation when texture exists
	// problem : renWin->MakeCurrent() is called on freed memory
//	return;
	// TODO CODE QUALITY : fix this
	// => done by changing order of deleting renderer and rendererwindow

  if (this->Index && renWin)
    {
    ((vtkRenderWindow *) renWin)->MakeCurrent();
#ifdef GL_VERSION_1_1
    // free any textures
    if (glIsTexture(this->Index))
      {
      GLuint tempIndex;
      tempIndex = this->Index;
      // NOTE: Sun's OpenGL seems to require disabling of texture before delete
      glDisable(GL_TEXTURE_2D);
      glDeleteTextures(1, &tempIndex);
      }
#else
    if (glIsList(this->Index))
      {
      glDeleteLists(this->Index,1);
      }
#endif
    }
  this->Index = 0;
  this->RenderWindow = NULL;
  this->Modified();
}
*/
void vtkPSIOpenGLTexture::Load(vtkRenderer *ren)
{
    // code copied from vtk, adapted to also be robust against textures that are to big
  GLenum format = GL_LUMINANCE;

  // need to reload the texture
  if (this->GetMTime() > this->LoadTime.GetMTime() ||
      this->Input->GetMTime() > this->LoadTime.GetMTime() ||
      (this->GetLookupTable() && this->GetLookupTable()->GetMTime () >
       this->LoadTime.GetMTime()))
    {
    int bytesPerPixel;
    int *size;
    vtkScalars *scalars;
    unsigned char *dataPtr;
    int rowLength;
    unsigned char *resultData=NULL;
    int xsize, ysize;
    unsigned short xs,ys;
    GLuint tempIndex;

    // get some info
    size = this->Input->GetDimensions();
    scalars = (this->Input->GetPointData())->GetScalars();

    // make sure scalars are non null
    if (!scalars)
      {
      vtkErrorMacro(<< "No scalar values found for texture input!");
      return;
      }

    bytesPerPixel = scalars->GetNumberOfComponents();

    // make sure using unsigned char data of color scalars type
    if (this->MapColorScalarsThroughLookupTable ||
       scalars->GetDataType() != VTK_UNSIGNED_CHAR )
      {
      dataPtr = this->MapScalarsToColors (scalars);
      bytesPerPixel = 4;
      }
    else
      {
      dataPtr = ((vtkUnsignedCharArray *)scalars->GetData())->GetPointer(0);
      }

    // we only support 2d texture maps right now
    // so one of the three sizes must be 1, but it
    // could be any of them, so lets find it
    if (size[0] == 1)
      {
      xsize = size[1]; ysize = size[2];
      }
    else
      {
      xsize = size[0];
      if (size[1] == 1)
        {
        ysize = size[2];
        }
      else
        {
        ysize = size[1];
        if (size[2] != 1)
          {
          vtkErrorMacro(<< "3D texture maps currently are not supported!");
          return;
          }
        }
      }

    // xsize and ysize must be a power of 2 in OpenGL
    xs = (unsigned short)xsize;
    ys = (unsigned short)ysize;
    while (!(xs & 0x01))
      {
        xs = xs >> 1;
      }
    while (!(ys & 0x01))
      {
        ys = ys >> 1;
      }

    // JORIS : resampling has to be done if
    // it is not power of two or if it is to big
    bool resampleNeeded = false;
    if ((xs > 1)||(ys > 1))
    {
        resampleNeeded = true;
    }
    int maxDimGL;
    glGetIntegerv(GL_MAX_TEXTURE_SIZE,&maxDimGL);
    if ( xsize > maxDimGL || ysize > maxDimGL )
    {
        vtkPSIDebugMacro( "Texture too big for gl, maximum is " << maxDimGL);
        resampleNeeded = true;
    }
    if ( resampleNeeded )
    {
        vtkDebugMacro(<< "Resampling texture to power of two for OpenGL");
        resultData = this->ResampleToPowerOfTwo(xsize, ysize, dataPtr,
                                              bytesPerPixel);
    }

    // format the data so that it can be sent to opengl
    // each row must be a multiple of 4 bytes in length
    // the best idea is to make your size a multiple of 4
    // so that this conversion will never be done.
    rowLength = ((xsize*bytesPerPixel +3 )/4)*4;
    if (rowLength == xsize*bytesPerPixel)
      {
      if ( resultData == NULL )
        {
        resultData = dataPtr;
        }
      }
    else
      {
      int col;
      unsigned char *src,*dest;
      int srcLength;

      srcLength = xsize*bytesPerPixel;
      resultData = new unsigned char [rowLength*ysize];

      src = dataPtr;
      dest = resultData;

      for (col = 0; col < ysize; col++)
        {
        memcpy(dest,src,srcLength);
        src += srcLength;
        dest += rowLength;
        }
      }

    // define a display list for this texture
    // free any old display lists
    if (this->Index)
      {
#ifdef GL_VERSION_1_1
      tempIndex = this->Index;
      glDeleteTextures(1, &tempIndex);
#else
      glDeleteLists(this->Index,1);
#endif
      this->Index = 0;
      }
    // get a unique display list id
#ifdef GL_VERSION_1_1
    glGenTextures(1, &tempIndex);
    this->Index = tempIndex;
    glBindTexture(GL_TEXTURE_2D, this->Index);
#else
    this->Index = glGenLists(1);
    glDeleteLists ((GLuint) this->Index, (GLsizei) 0);
    glNewList ((GLuint) this->Index, GL_COMPILE);
#endif
    if (this->Interpolate)
      {
      glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
                       GL_LINEAR);
      glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
                       GL_LINEAR );
      }
    else
      {
      glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
      glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
      }
    if (this->Repeat)
      {
      glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,     GL_REPEAT );
      glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,     GL_REPEAT );
      }
    else
      {
      glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S,     GL_CLAMP );
      glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T,     GL_CLAMP );
      }
    switch (bytesPerPixel)
      {
      case 1: format = GL_LUMINANCE; break;
      case 2: format = GL_LUMINANCE_ALPHA; break;
      case 3: format = GL_RGB; break;
      case 4: format = GL_RGBA; break;
      }
    glTexImage2D( GL_TEXTURE_2D, 0 , bytesPerPixel,
                  xsize, ysize, 0, format,
                  GL_UNSIGNED_BYTE, (const GLvoid *)resultData );
#ifndef GL_VERSION_1_1
    glEndList ();
#endif
    // modify the load time to the current time
    this->LoadTime.Modified();

    // free memory
    if (resultData != dataPtr)
      {
      delete [] resultData;
      }
    }

  // execute the display list that uses creates the texture
#ifdef GL_VERSION_1_1
  glBindTexture(GL_TEXTURE_2D, this->Index);
#else
  glCallList ((GLuint) this->Index);
#endif

  // don't accept fragments if they have zero opacity. this will stop the
  // zbuffer from be blocked by totally transparent texture fragments.
  glAlphaFunc (GL_GREATER, (GLclampf) 0);
  glEnable (GL_ALPHA_TEST);

  // now bind it
  glEnable(GL_TEXTURE_2D);

}
static int FindPowerOfTwo(int i)
{
    int size;

    for ( i--, size=1; i > 0; size*=2 )
    {
        i /= 2;
    }
    int maxDimGL;
    glGetIntegerv(GL_MAX_TEXTURE_SIZE,&maxDimGL);
    if ( size > maxDimGL )
    {
        size = maxDimGL ;
    }
    return size;
}

unsigned char * vtkPSIOpenGLTexture::ResampleToPowerOfTwo(int &xs, int &ys, unsigned char *dptr, int bpp)
{
    // copied from vtk, but FindPowerOfTwo is adapted
  unsigned char *tptr, *p, *p1, *p2, *p3, *p4;
  int xsize, ysize, i, j, k, jOffset, iIdx, jIdx;
  float pcoords[3], hx, hy, rm, sm, w0, w1, w2, w3;

  xsize = FindPowerOfTwo(xs);
  ysize = FindPowerOfTwo(ys);

  hx = (float)(xs - 1.0) / (xsize - 1.0);
  hy = (float)(ys - 1.0) / (ysize - 1.0);

  tptr = p = new unsigned char[xsize*ysize*bpp];

  //Resample from the previous image. Compute parametric coordinates and interpolate
  for (j=0; j < ysize; j++)
    {
    pcoords[1] = j*hy;

    jIdx = (int)pcoords[1];
    if ( jIdx >= (ys-1) ) //make sure to interpolate correctly at edge
      {
      jIdx = ys - 2;
      pcoords[1] = 1.0;
      }
    else
      {
      pcoords[1] = pcoords[1] - jIdx;
      }
    jOffset = jIdx*xs;
    sm = 1.0 - pcoords[1];

    for (i=0; i < xsize; i++)
      {
      pcoords[0] = i*hx;
      iIdx = (int)pcoords[0];
      if ( iIdx >= (xs-1) )
        {
        iIdx = xs - 2;
        pcoords[0] = 1.0;
        }
      else
        {
        pcoords[0] = pcoords[0] - iIdx;
        }
      rm = 1.0 - pcoords[0];

      // Get pointers to 4 surrounding pixels
      p1 = dptr + bpp*(iIdx + jOffset);
      p2 = p1 + bpp;
      p3 = p1 + bpp*xs;
      p4 = p3 + bpp;

      // Compute interpolation weights interpolate components
      w0 = rm*sm;
      w1 = pcoords[0]*sm;
      w2 = rm*pcoords[1];
      w3 = pcoords[0]*pcoords[1];
      for (k=0; k < bpp; k++)
        {
        *p++ = p1[k]*w0 + p2[k]*w1 + p3[k]*w2 + p4[k]*w3;
        }
      }
    }

  xs = xsize;
  ys = ysize;

  return tptr;

}
-------------- next part --------------
// vtkPSIOpenGLTexture.h: interface for the vtkPSIOpenGLTexture class.
//
//////////////////////////////////////////////////////////////////////

#if !defined(AFX_VTKPSIOPENGLTEXTURE_H__5DF776DA_C9A9_11D3_B932_080036DAD703__INCLUDED_)
#define AFX_VTKPSIOPENGLTEXTURE_H__5DF776DA_C9A9_11D3_B932_080036DAD703__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include "vtkPSITexture.h"
class vtkRenderer;

// this will automatically resample to power of two, but also 
// take into account limits of OpenGL
	// TODO EFFICIENCY : 
	// TODO FUNCTIONALITY : 
	// Do it smarter : ss3d texture are often very unefficient, with big unused parts
	// Cropping should be interesting, however, then texture coordinates have to be changed too

class vtkPSIOpenGLTexture : public vtkPSITexture  
{
public:
//	virtual void ReleaseGraphicsResources(vtkWindow *);
	void Load(vtkRenderer *ren);
	vtkPSIOpenGLTexture();
	virtual ~vtkPSIOpenGLTexture();
	vtkTypeMacro(vtkPSIOpenGLTexture,vtkPSITexture);
	static vtkPSIOpenGLTexture *New() {return new vtkPSIOpenGLTexture;};

protected:
	unsigned char * ResampleToPowerOfTwo(int &xsize, int &ysize, unsigned char *dptr, int bpp);
};

#endif // !defined(AFX_VTKPSIOPENGLTEXTURE_H__5DF776DA_C9A9_11D3_B932_080036DAD703__INCLUDED_)


More information about the vtk-developers mailing list