[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