Module: dpoly.cpp

class DPoly
.h

constructorDPoly()
destructor~DPoly()
Definevoid Define(int nPoints,DPolyPoint *pts)
DefinePointvoid DefinePoint(int n,DPolyPoint *p)
MoveRelativevoid MoveRelative(dfloat x,dfloat y,dfloat z)

Move all points relative to current position

GetWidthdfloat GetWidth()
GetHeightdfloat GetHeight()
Disablevoid Disable(int _flags)
Enablevoid Enable(int _flags)
SetBlendModevoid SetBlendMode(int mode)
SetOpacityvoid SetOpacity(dfloat opa)

Set opacity (0..1?)

Paintvoid Paint()

Assumptions:
- Modelview/projection is set up
- OpenGL context is valid and set up

DefineTexturevoid DefineTexture(DTexture *t,QRect *r,int rotateCount,int mirrorFlags)

Define a portion of the texture as this poly's texturemap
'rotateCount' indicates the number of 90 degree rotations you want
to apply before applying the texture map to the polygon. This way you
can specify the orientation of the tmap on the polygon.
'mirrorFlags' specifies X and Y reversal; &1 = mirror X, &2=mirror Y
Mirroring is done BEFORE rotateCount is applied (!).
Works for 3 and 4-point polygons.
FUTURE: mirror tmap X/Y

SetWidthvoid SetWidth(dfloat w)

Modifies a polygon that has a shape such that every point
to the right of the leftmost point will be set to 'w' X-distance
of that leftmost point.
Practical use: rectangular polygons width setting.

SetHeightvoid SetHeight(dfloat h)

OLD Modifies a polygon that has a shape such that every point
to the right of the leftmost point will be set to 'w' X-distance
of that leftmost point.
Practical use: rectangular polygons width setting.



/*
 * DPoly - definition/implementation
 * 19-02-99: Created!
 * 02-12-99: Opacity support.
 * NOTES:
 * - Generated by mkclass
 * (C) 19-02-1999 (17:36) MarketGraph/RVG
 */

#include <d3/poly.h>
#include <GL/gl.h>
#include <qlib/debug.h>
DEBUG_ENABLE

DPoly::DPoly()
{
  texture=0;
  point=0;
  points=0;
  // Default is no blending, no culling
  flags=0;
  blendMode=BLEND_OFF;
  opacity=1.0;
}

DPoly::~DPoly()
{
  if(point)qfree(point);
}

/***********
* GEOMETRY *
***********/
void DPoly::Define(int nPoints,DPolyPoint *pts)
{
  points=nPoints;
  point=(DPolyPoint*)qcalloc(nPoints*sizeof(DPolyPoint));
  if(!point)qwarn("DPoly::Define(); out of memory");
}
void DPoly::DefinePoint(int n,DPolyPoint *p)
{
  point[n]=*p;
}

void DPoly::MoveRelative(dfloat x,dfloat y,dfloat z)
// Move all points relative to current position
{
  int i;
  for(i=0;i<points;i++)
  { point[i].x+=x;
    point[i].y+=y;
    point[i].z+=z;
  }
}

dfloat DPoly::GetWidth()
{
  int minX,maxX;
  int i;

  if(!points)return 0;
  minX=maxX=point[0].x;
  for(i=0;i<points;i++)
  { if(point[i].x<minX)minX=point[i].x;
    if(point[i].x>maxX)maxX=point[i].x;
  }
  return maxX-minX;
}
dfloat DPoly::GetHeight()
{
  int minY,maxY;
  int i;

  if(!points)return 0;
  minY=maxY=point[0].y;
  for(i=0;i<points;i++)
  { if(point[i].y<minY)minY=point[i].y;
    if(point[i].y>maxY)maxY=point[i].y;
  }
  return maxY-minY;
}

void DPoly::Disable(int _flags)
{
  flags&=~_flags;
}
void DPoly::Enable(int _flags)
{
  // Test for obsolete blend setting
  if(_flags&1 /*BLEND*/ )
  { qwarn("DPoly:Enable: obsolete attempt to set blend mode using Enable");
  }
  flags|=_flags;
}

/********
* LOOKS *
********/
void DPoly::SetBlendMode(int mode)
{
  blendMode=mode;
  /*if(blendMode==BLEND_OFF)
    flags&=~BLEND;*/
}
void DPoly::SetOpacity(dfloat opa)
// Set opacity (0..1?)
{ opacity=opa;
}

/********
* PAINT *
********/
void DPoly::Paint()
// Assumptions:
// - Modelview/projection is set up
// - OpenGL context is valid and set up
{
  DPolyPoint *p;
  int i;

//qdbg("DPoly:Paint; texture=%p %fx%f\n",texture,GetWidth(),GetHeight());
  if(texture)
  { texture->Select();
    glEnable(GL_TEXTURE_2D);
  } else
  { glDisable(GL_TEXTURE_2D);
  }
//qdbg("DPoly:Paint: flags=%d\n",flags);
  if(blendMode==BLEND_SRC_ALPHA)
  { glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
    
    // Tests to mix texture with color fragments AND alpha from texture
    
    // To modify the coloring AND alpha of the drawn polygon,
    // use texture env mode GL_MODULATE and give the polygon
    // a color (glColor4f).
    // This will enable you to colorize the polygon, and to
    // do an opacity effect by specifying a polygon color
    // of black and alpha<1
#ifdef ND
    glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE);
#endif
    
    // No idea yet how to use the texture env color practically
#ifdef ND
    //GLfloat envColor[4]={ 1,1,1,1 /*.1,.4,.6,.5*/ };
    //glTexEnvfv(GL_TEXTURE_ENV,GL_TEXTURE_ENV_COLOR,envColor);
    //glDisable(GL_TEXTURE_2D);
#endif
    
    // To affect the coloring, but NOT the alpha (no opacity)
    // use glBlendColorEXT() with alpha<1, and
    // glBlendFunc(GL_CONSTANT_ALPHA_EXT,GL_ONE_MINUS_SRC_ALPHA)
    // This will pull the colors to the constant blend color by alpha.
#ifdef ND
    glBlendColorEXT(.1,.3,.5,.6);
    glBlendColorEXT(1,1,1,.5);
    //glBlendFunc(GL_CONSTANT_COLOR_EXT,GL_ONE_MINUS_SRC_ALPHA);
    glBlendFunc(GL_CONSTANT_ALPHA_EXT,GL_ONE_MINUS_SRC_ALPHA);
    glBlendFunc(GL_ONE_MINUS_SRC_ALPHA,GL_CONSTANT_ALPHA_EXT);
#endif
  } else glDisable(GL_BLEND);

  if(opacity!=1.0)
  {
    // Opacity can be reached in numerous ways; blending, texture modulation...
    // A lot can be done with the blending/texturing hardware
    // Here I modulate the texture color with a color with alpha<1
    // Opacity works on blended and non-blended polygons (!)
    glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE);
    glColor4f(1,1,1,opacity);
  } else
  {
    glColor4f(1,1,1,opacity);
  }
  
  if(flags&CULL)
  { glEnable(GL_CULL_FACE);
  } else
  { glDisable(GL_CULL_FACE);
  }
  if(points==4)
  {
    glBegin(GL_QUADS);

    for(i=0;i<points;i++)
    { p=&point[i];
      if(texture)glTexCoord2f(p->tx,p->ty);
//glTexCoord2f(p->tx,p->ty);
//qdbg("pt %f,%f,%f tex %f,%f\n",p->x,p->y,p->z,p->tx,p->ty);
#ifdef ND_TEST_COLORING
      switch(i)
      { case 0: glColor4f(1,0,0,.1); break;
        case 1: glColor4f(0,1,0,.3); break;
        case 2: glColor4f(0,0,1,.7); break;
        case 3: glColor4f(1,1,1,1); break;
      }
#endif
      //glColor3f(1,0,0);
      glVertex3f(p->x,p->y,p->z);
    }
    glEnd();
  }
}

/************
* TEXTURING *
************/
void DPoly::DefineTexture(DTexture *t,QRect *r,int rotateCount,int mirrorFlags)
// Define a portion of the texture as this poly's texturemap
// 'rotateCount' indicates the number of 90 degree rotations you want
// to apply before applying the texture map to the polygon. This way you
// can specify the orientation of the tmap on the polygon.
// 'mirrorFlags' specifies X and Y reversal; &1 = mirror X, &2=mirror Y
// Mirroring is done BEFORE rotateCount is applied (!).
// Works for 3 and 4-point polygons.
// FUTURE: mirror tmap X/Y
{
  dfloat left,right,top,bottom,temp; //sx,sy,ex,ey;
  dfloat twid,thgt;

  texture=t;
  twid=texture->GetWidth();
  thgt=texture->GetHeight();

  // Calculate fraction location of rectangle
  left=((dfloat)r->x)/twid;
  right=((dfloat)(r->x+r->wid))/twid;
  top=((dfloat)r->y)/thgt;
  bottom=((dfloat)(r->y+r->hgt))/thgt;
//qdbg("DPoly::DefineTexture: r to float: l%f,r%f,t%f,b%f (r=%d,%d %dx%d t=%fx%f)\n",
//left,right,top,bottom,r->x,r->y,r->wid,r->hgt,twid,thgt);

  // Mirroring
  if(mirrorFlags&1)
  { // X mirroring
    temp=left; left=right; right=temp;
  }
  if(mirrorFlags&2)
  { // Y mirroring
    temp=top; top=bottom; bottom=temp;
  }

  // Picture reversal (coordinate system)
  temp=bottom; bottom=1-top; top=1-temp;

  // Redefine texture coordinates at each vertex
  int p=rotateCount%points;
  point[p].tx=left; point[p].ty=top;
  p=(p+1)%points;
  point[p].tx=right; point[p].ty=top;
  p=(p+1)%points;
  point[p].tx=right; point[p].ty=bottom;
  if(points>3)
  { p=(p+1)%points;
    point[p].tx=left; point[p].ty=bottom;
  }
}

/*******************
* DYNAMIC GEOMETRY *
*******************/
void DPoly::SetWidth(dfloat w)
// Modifies a polygon that has a shape such that every point
// to the right of the leftmost point will be set to 'w' X-distance
// of that leftmost point.
// Practical use: rectangular polygons width setting.
{
  dfloat minX;
  int i;

  if(!points)return; 

  // Find leftmost X value
  for(i=0;i<points;i++)
  { if(point[i].x<minX)minX=point[i].x;
  }

  // For every point to the right of that value, set the width
  for(i=0;i<points;i++)
  { if(point[i].x>minX)
    { point[i].x=minX+w;
    }
  }
}

void DPoly::SetHeight(dfloat h)
// OLD Modifies a polygon that has a shape such that every point
// to the right of the leftmost point will be set to 'w' X-distance
// of that leftmost point.
// Practical use: rectangular polygons width setting.
{
  dfloat minY;
  int i;

  if(!points)return;

  // Find lowest Y value
  for(i=0;i<points;i++)
  { if(point[i].y<minY)minY=point[i].y;
  }

  // For every point to the right of that value, set the width
  for(i=0;i<points;i++)
  { if(point[i].y>minY)
    { point[i].y=minY+h;
    }
  }
}