Module: dtexture.cpp

class DTexture
.h

constructorDTexture()

Create a default texture object

destructor~DTexture()
SetSizevoid SetSize(int w,int h)

Sets texture size (wid/hgt); no object, just variables

CreateTexturevoid CreateTexture()

Generate the texture and texture Object (name) and parameters in OpenGL
Texture is created in the current OpenGL context (current canvas/gl)
Default uses linear filtering, S/T clamping (no texture repeat)

Selectvoid Select()

Select our texture (selects parameters as well/OpenGL)

GetWidthint GetWidth()

Returns width of actual texture (may not match used part of texture)

GetHeightint GetHeight()

Returns height of actual texture (may not match used part of texture)

SetWrapvoid SetWrap(int sWrap,int tWrap,int rWrap,int qWrap)

Sets wrapping functions for the texture; default is to repeat the texture
Possible values are CLAMP and REPEAT. OpenGL has more (CLAMP_TO_BORDER).
Note: this function implicity selects the texture

SetEnvModevoid SetEnvMode(int mode)

Set environment mode.
Possible values are: MODULATE, ADD, REPLACE
See also 'man gltexenv'

SetNamevoid SetName(cstring s)

class DBitMapTexture
.h

constructorDBitMapTexture(QBitMap *ibm)

: DTexture()
Use an existing bitmap as a texture

destructor~DBitMapTexture()

class DDrawableTexture
.h

constructorDDrawableTexture(QDrawable *_draw)

: DTexture()
Create a texture for a drawable's contents

destructor~DDrawableTexture()
Refreshvoid Refresh(bool front)

class DMovieTexture
.h

constructorDMovieTexture(QMovie *mv)

: DTexture()
Create movie texture; render movie 'mv' into a pbuffer
Note that the texture is rounded to 2**n size, so 720x576 becomes 1024x768
for the pbuffer size.

destructor~DMovieTexture()

Destroys pbuffer, DMbuffer, bufferpool

Renderbool Render()

Selects our pbuffer context and render the current frame into the pbuffer
NOTES:
- Turns off blending

SetCurFramebool SetCurFrame(int frame)

Sets current frame
BUGS:
- Currently does nothing; should set movie frame

Advancebool Advance()

Shortcut to advance movie 1 frame. Returns TRUE if movie is still
playing, FALSE if movie has ended



/*
 * DTexture - definition/implementation
 * NOTES:
 * - Some OpenGL calls are used which were *EXT in IRIX6.3
 * - Generated by mkclass
 * FUTURE:
 * - Store and check OpenGL context when creating/selecting.
 *   These contexts must match, or else the texture was created
 *   in an other GLContext than it is being used.
 * + Automatically switch to the right texture context? (warn!)
 * (C) 19-02-1999 (18:10) MarketGraph/RVG
 */

#include <d3/texture.h>
#include <qlib/app.h>
#include <qlib/error.h>
#include <qlib/opengl.h>
#include <qlib/dmvideoin.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <qlib/debug.h>
DEBUG_ENABLE

// If USE_ISTEXTURE_TEST is defined, every texture select will
// first test if the id really belongs to a texture.
// Ofcourse, this has performance impacts.
//#define USE_ISTEXTURE_TEST

// Mipmap support by default?
//#define USE_MIPMAPS

#undef  DBG_CLASS
#define DBG_CLASS "DTexture"

/*****************
* TEXTURE BASICS *
*****************/
DTexture::DTexture()
// Create a default texture object
{
  DBG_C("ctor")

  wid=hgt=0;
  textureID=0;
  gl=0;
}
DTexture::~DTexture()
{
  DBG_C("dtor")
  if(textureID)
    glDeleteTextures(1,(GLuint*)&textureID);
}

void DTexture::SetSize(int w,int h)
// Sets texture size (wid/hgt); no object, just variables
{
  if(wid!=0||hgt!=0)
  { qerr("DTexture::SetSize() called twice for the same object");
    return;
  }
  wid=w; hgt=h;
}

void DTexture::CreateTexture()
// Generate the texture and texture Object (name) and parameters in OpenGL
// Texture is created in the current OpenGL context (current canvas/gl)
// Default uses linear filtering, S/T clamping (no texture repeat)
{
  DBG_C("CreateTexture")

  //static char pic[512*512*4]; int i;
  //for(i=0;i<512*512*4;i++)pic[i]=rand();

  // Remember GL context in which this texture 'lives'
  gl=GetCurrentQGLContext();

  // Create texture ID for this texture resource
  glGenTextures(1,(GLuint*)&textureID);
  glBindTexture(GL_TEXTURE_2D,textureID);
#ifndef WIN32
  static bool fWarned;
  // Very hard to trace problems occur when creating textures
  // not in Q_BC (QCV). Warn for that, but don't overdo it, so you won't
  // get flooded with warnings if this was the intent.
  // Problems are: textures not visible, display lists VERY slow (Racer)
  if(fWarned==FALSE&&
     glXGetCurrentContext()!=QCV->GetGLContext()->GetGLXContext())
  {
    qwarn("Textures being created outside of QCV; probably NOT wanted");
    fWarned=TRUE;
  }
//qdbg("DTexture:CreateTexture(); texture ID %d in ctx %p\n",textureID,glXGetCurrentContext());
#endif
  // Create texture in system (no image yet)
  glPixelStorei(GL_UNPACK_ROW_LENGTH,0);
  glPixelStorei(GL_UNPACK_SKIP_ROWS,0);
  glPixelStorei(GL_UNPACK_SKIP_PIXELS,0);
  //glPixelStorei(GL_UNPACK_ALIGNMENT,1);
  /*glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,
    bm->GetWidth(),bm->GetHeight(),0,GL_RGBA,GL_UNSIGNED_BYTE,bm->GetBuffer());
  */
#ifdef WIN32
  glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,wid,hgt,0,
    GL_RGBA,GL_UNSIGNED_BYTE,0);
#else
  glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA8_EXT,wid,hgt,0,
    GL_RGBA,GL_UNSIGNED_BYTE,0);
#endif
  // Default settings for texturing
#ifdef USE_MIPMAPS
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,
    GL_NEAREST_MIPMAP_NEAREST);
    //GL_NEAREST_MIPMAP_LINEAR);
#else
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
#endif
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP);
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP);
  //glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_REPLACE);
  glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE);
}

void DTexture::Select()
// Select our texture (selects parameters as well/OpenGL)
{
  QASSERT_V(gl);	// No OpenGL context; texture not created
//qdbg("DTexture:Select(): id %d into context %p\n",textureID,glXGetCurrentContext());
//qdbg("DTexture:Select(): id %d into context %p\n",textureID,gl);
  gl->Select();
#ifdef USE_ISTEXTURE_TEST
  // Check first to see if texture exists in this OpenGL context
  if(!glIsTexture(textureID))
  { qwarn("DTexture::Select(); texture ID %d does not exist in current GLCtx");
    return;
  }
#endif
  glBindTexture(GL_TEXTURE_2D,textureID);
}

int DTexture::GetWidth()
// Returns width of actual texture (may not match used part of texture)
{
  return wid;
}
int DTexture::GetHeight()
// Returns height of actual texture (may not match used part of texture)
{
  return hgt;
}

void DTexture::SetWrap(int sWrap,int tWrap,int rWrap,int qWrap)
// Sets wrapping functions for the texture; default is to repeat the texture
// Possible values are CLAMP and REPEAT. OpenGL has more (CLAMP_TO_BORDER).
// Note: this function implicity selects the texture
{
  QASSERT(rWrap==REPEAT&&qWrap==REPEAT);      // r/q wrap NYI
  Select();
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,sWrap);
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,tWrap);
}

void DTexture::SetEnvMode(int mode)
// Set environment mode.
// Possible values are: MODULATE, ADD, REPLACE
// See also 'man gltexenv'
{
  Select();
  glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,mode);
}

void DTexture::SetName(cstring s)
{
  name=s;
}

/*****************
* BITMAP TEXTURE *
*****************/

#undef  DBG_CLASS
#define DBG_CLASS "DBitMapTexture"

DBitMapTexture::DBitMapTexture(QBitMap *ibm)
  : DTexture()
// Use an existing bitmap as a texture
{
  DBG_C("ctor");
  DBG_ARG_P(ibm);

  int w,h;
  QBitMap *tbm=0;

  bm=ibm;
  bwid=bm->GetWidth();
  bhgt=bm->GetHeight();

  // Find 2**n texture size to play movie in
  w=QNearestPowerOf2(bwid);
  h=QNearestPowerOf2(bhgt);
  SetSize(w,h);

  if(bwid!=wid||bhgt!=hgt)
  { // Bitmap is not directly usable
    // Either use SKIP_PIXELS etc
    // or allocate a new bitmap where you put it in
    tbm=new QBitMap(32,wid,hgt);
//qdbg("Copy into %dx%d the source bitmap %dx%d\n",wid,hgt,bwid,bhgt);
    tbm->CopyPixelsFrom(bm,0,0,bwid,bhgt,0,0);
    bm=tbm;
  }
//qdbg("DBitMapTexture: creating texture %dx%d for bitmap %dx%d\n",w,h,bwid,bhgt);

  CreateTexture();
  // Install image as texture
//qdbg("installtex\n");
#ifdef USE_MIPMAPS
  gluBuild2DMipmaps(GL_TEXTURE_2D,GL_RGBA,wid,hgt,GL_RGBA,GL_UNSIGNED_BYTE,
    bm->GetBuffer());
#else
  glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,wid,hgt,0,GL_RGBA,GL_UNSIGNED_BYTE,
    bm->GetBuffer());
#endif

  // Don't leave texture bitmap around
  if(tbm)delete tbm;
//qdbg("DBitMapTex ret\n");
}
DBitMapTexture::~DBitMapTexture()
{
//qdbg("DBitMapTexture dtor\n");
}

/*******************
* DRAWABLE TEXTURE *
*******************/
DDrawableTexture::DDrawableTexture(QDrawable *_draw)
  : DTexture()
// Create a texture for a drawable's contents
{
  draw=_draw;

  // Find 2**n texture size to store drawable in
  int w,h;
  w=QNearestPowerOf2(draw->GetWidth());
  h=QNearestPowerOf2(draw->GetHeight());
  SetSize(w,h);

//qdbg("DDrawbleTexture: creating texture %dx%d\n",w,h);

  CreateTexture();
}
DDrawableTexture::~DDrawableTexture()
{
}

void DDrawableTexture::Refresh(bool front)
{
  Select();

  int dx,dy;

  // Create texture in system (no image yet)
  glPixelStorei(GL_UNPACK_ROW_LENGTH,0);
  glPixelStorei(GL_UNPACK_SKIP_ROWS,0);
  glPixelStorei(GL_UNPACK_SKIP_PIXELS,0);

  dx=0; dy=0;
  glPixelStorei(GL_PACK_ROW_LENGTH,1024);       // Texture width
  //glPixelStorei(GL_PACK_ROW_LENGTH,0);        // Texture width
  glPixelStorei(GL_PACK_SKIP_PIXELS,dx);
  glPixelStorei(GL_PACK_SKIP_ROWS,dy);

  glPixelStorei(GL_UNPACK_ALIGNMENT,1);
  glPixelStorei(GL_PACK_ALIGNMENT,1);

  glDisable(GL_BLEND);
  if(front)glReadBuffer(GL_FRONT);
  else     glReadBuffer(GL_BACK);
  QShowGLErrors("pre glCopyTexSubImage2D");
  glCopyTexSubImage2D(GL_TEXTURE_2D,0, 0,1024-576,
    0,0, draw->GetWidth(),draw->GetHeight());
  QShowGLErrors("post glCopyTexSubImage2D");
  glReadBuffer(GL_BACK);
}

/****************
* MOVIE TEXTURE *
****************/
#ifndef WIN32
DMovieTexture::DMovieTexture(QMovie *mv)
  : DTexture()
// Create movie texture; render movie 'mv' into a pbuffer
// Note that the texture is rounded to 2**n size, so 720x576 becomes 1024x768
// for the pbuffer size.
{
  int w,h;
  movie=mv;
  // Normal dims of picture (need to cut out movie images from texture)
  mwid=movie->GetImageTrack()->GetImageWidth();
  mhgt=movie->GetImageTrack()->GetImageHeight();
  // Find 2**n texture size to play movie in
  w=QNearestPowerOf2(mwid);
  h=QNearestPowerOf2(mhgt);

qdbg("DMovieTexture: creating texture %dx%d to play %dx%d in\n",w,h,mwid,mhgt);

  pbuf=new QDMPBuffer(w,h);
  SetSize(w,h);

  // Create pbuffer (where the movies frames will be rendered)
  //pbuf=new QDMPBuffer(wid,hgt);

  // Create a DMbuffer to be used as the color buffer of 'pbuf'
  pool=new QDMBPool(1,wid*hgt*4,FALSE,FALSE);
  //pool=new QDMBPool(1,((wid*hgt*4)+0xFFFF)&~0xFFFF,FALSE,FALSE);
  //pool=new QDMBPool(1,((wid*hgt*4)+0xFFFF)&~0xFFFF,TRUE,TRUE);
  pool->AddProducer(pbuf);

  if(!pool->Create())
  { qerr("DMovieTexture ctor: can't create pool for texture dmbuffer");
    // And crash...?
  }

  //SetCurrentQGLContext(0);
  //app->GetBC()->GetCanvas()->Select();
  CreateTexture();

  dmbuf=pool->AllocateDMBuffer();

  // Complete pbuffer by linking 'dmbuf' as its color buffer
  pbuf->Associate(dmbuf);

  // Install pbuffer as texture
  pbuf->CopyTexture(app->GetBC()->GetCanvas()->GetGLContext());
 QShowGLErrors("DMovieTexture ctor; pbuf CopyTexture");

#ifndef WIN32
  // Fit renders into texture
  MVrect r;
  r.left=0; r.right=mwid;
  //r.top=0; r.bottom=thgt;
  r.top=100; r.bottom=100+mhgt;
  r.top=100+mhgt; r.bottom=100;
  r.top=hgt-1; r.bottom=hgt-mhgt-1;
  //if(!mvSetMovieRect(movie->GetImageTrack()->GetMVid(),r))
  if(!mvSetMovieRect(movie->GetMVid(),r))
    QShowMVErrors("DMovieTexture: mvSetMovieRect");
#endif

  // Setup OpenGL rendering view
  pbuf->Select();
  glViewport(0,0,wid,hgt);
 QShowGLErrors("viewport");
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
  glOrtho(0,wid,0,hgt,-1,1);
  glDisable(GL_TEXTURE_2D);

  // Reset GLX context
  //SetCurrentQGLContext(0);
  //app->GetBC()->GetCanvas()->Select();
}
DMovieTexture::~DMovieTexture()
// Destroys pbuffer, DMbuffer, bufferpool
{
//qdbg("DMovieTexture dtor\n");
  delete pbuf;
  delete dmbuf;
  delete pool;
}

static int done;
bool DMovieTexture::Render()
// Selects our pbuffer context and render the current frame into the pbuffer
// NOTES:
// - Turns off blending
{
  if(done)return TRUE;
  //done=1;
//qdbg("DMT:Render()\n");
  // Select us as current texture
  Select();

  pbuf->Select();
//#ifdef ND_DONE
  glViewport(0,0,wid,hgt);
 QShowGLErrors("viewport");
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity();
  glOrtho(0,wid,0,hgt,-1,1);
  glDisable(GL_TEXTURE_2D);
/*
  float c=rand()&255;
  c/=256;
  glClearColor(.4,.5,c,1);
  glClear(GL_COLOR_BUFFER_BIT);
 QShowGLErrors("matrix");
*/
//#endif

  movie->RenderToOpenGL();
  glDisable(GL_BLEND);
  glRasterPos2i(0,0);
  //pbuf->CopyTexture(app->GetBC()->GetCanvas()->GetGLContext());
 QShowGLErrors("DMT:Render; CopyTexture");
  // Clear GLXContext cache
  //SetCurrentQGLContext(0);

  //app->GetBC()->GetCanvas()->Select();
  //app->GetBC()->Swap(); QNap(50);
  //app->GetBC()->Swap(); QNap(50);

  return TRUE;
}

bool DMovieTexture::SetCurFrame(int frame)
// Sets current frame
// BUGS:
// - Currently does nothing; should set movie frame
{
  return TRUE;
}
bool DMovieTexture::Advance()
// Shortcut to advance movie 1 frame. Returns TRUE if movie is still
// playing, FALSE if movie has ended
{
  movie->Advance();
  if(movie->IsPlaying())return true;
  return false;
}
#endif
// ifndef Win32