////////////////////////////////////////////////////////
//
// GEM - Graphics Environment for Multimedia
//
// mark@danks.org
//
// Implementation file
//
//    Copyright (c) 1997-1999 Mark Danks.
//    For information on usage and redistribution, and for a DISCLAIMER OF ALL
//    WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution.
//
/////////////////////////////////////////////////////////

#include "texfont.h"
#include "Base/GemPixUtil.h"

CPPEXTERN_NEW_WITH_GIMME(texfont)

/////////////////////////////////////////////////////////
//
// texfont
//
/////////////////////////////////////////////////////////
// Constructor
//
/////////////////////////////////////////////////////////
texfont :: texfont(int argc, t_atom *argv)
    	     : TextBase(argc, argv), 
  m_textureOnOff(1), 
  m_textureQuality(GL_LINEAR),
  m_rebuildList(0), 
  m_textureObj(NULL),
  m_fontname(NULL),
  m_current(0),
  m_width(80),
  m_height(25)
{
	m_dataSize[0] = m_dataSize[1] = m_dataSize[2] = -1;
	fontNameMess("default.txf");
	m_theString = new char[m_width*m_height];
}

/////////////////////////////////////////////////////////
// Destructor
//
/////////////////////////////////////////////////////////
texfont :: ~texfont()
{ }

/////////////////////////////////////////////////////////
// setUpTextureState
//
/////////////////////////////////////////////////////////
void texfont :: setUpTextureState()
{
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, m_textureQuality);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_textureQuality);
    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
}

/////////////////////////////////////////////////////////
// render
//
/////////////////////////////////////////////////////////
void texfont :: render(GemState *state)
{
  int width, ascent, descent;
  int i;

  if ( !m_textureObj || !m_textureOnOff) return;
  
  state->texture = 1;

  glPushMatrix();
  glEnable(GL_TEXTURE_2D);

#if 0
  glAlphaFunc(GL_GEQUAL, 0.0625);
  glEnable(GL_ALPHA_TEST);
  glEnable(GL_BLEND);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
#endif

#if 0
  glEnable(GL_POLYGON_OFFSET_EXT);
  glPolygonOffset(0.0, -3);
#endif

  txfEstablishTexture(m_textureObj, 0, GL_TRUE);
  
  txfGetStringMetrics(m_textureObj, m_theString, 80,
		      &width, &ascent, &descent);

  glTranslatef(-1.0, 0.0, 0.1);
  glScalef(0.01, 0.01, 0.01);

  for (i = 0; i < strlen(m_theString); i++) {
    if (m_theString[i] == '\n' || m_theString[i] == 13 || (i%80 == 0)) {
      glTranslatef(-0.99*width,-30.0,0.0);
    }
    else
      txfRenderGlyph(m_textureObj, m_theString[i]);
  }

  glDisable(GL_TEXTURE_2D);

#if 0
  glDisable(GL_BLEND);
  glDisable(GL_ALPHA_TEST);
  glDisable(GL_POLYGON_OFFSET_EXT);
#endif

  glPopMatrix();
  

}

/////////////////////////////////////////////////////////
// postrender
//
/////////////////////////////////////////////////////////
void texfont :: postrender(GemState *state)
{
    glDisable(GL_TEXTURE_2D);
}

/////////////////////////////////////////////////////////
// startRendering
//
/////////////////////////////////////////////////////////
void texfont :: startRendering()
{
  m_dataSize[0] = m_dataSize[1] = m_dataSize[2] = -1;
  
  m_textureObj = txfLoadFont(m_fontname);

  if (!m_textureObj)
    {
      error("GEM: texfont: Unable to allocate texture object");
      return;
    }
}

/////////////////////////////////////////////////////////
// stopRendering
//
/////////////////////////////////////////////////////////
void texfont :: stopRendering()
{

}


void texfont :: floatmess(int i)
{
  if (i == 0) {
    m_current = 0;
    return;
  }
  if (m_current > m_width*m_height) m_current = 0;
  //  post("setting %d to %c",m_current,i);
  m_theString[m_current++] = i;
}


/////////////////////////////////////////////////////////
// textureOnOff
//
/////////////////////////////////////////////////////////
void texfont :: textureOnOff(int on)
{
    m_textureOnOff = on;
    setModified();
}

/////////////////////////////////////////////////////////
// textureQuality
//
/////////////////////////////////////////////////////////
void texfont :: textureQuality(int type)
{
    if (type)
        m_textureQuality = GL_LINEAR;
    else
        m_textureQuality = GL_NEAREST;
    if (m_textureObj)
    {
#ifdef GL_VERSION_1_1
      //        glBindTexture(GL_TEXTURE_2D, m_textureObj);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, m_textureQuality);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_textureQuality);
#elif GL_EXT_texture_object
	//        glBindTextureEXT(GL_TEXTURE_2D, m_textureObj);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, m_textureQuality);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, m_textureQuality);
#else
#endif
    }
	setModified();
}

/////////////////////////////////////////////////////////
// static member functions
//
/////////////////////////////////////////////////////////
void texfont :: obj_setupCallback(t_class *classPtr)
{
    class_addfloat(classPtr, (t_method)&texfont::floatMessCallback);    
    class_addmethod(classPtr, (t_method)&texfont::textureMessCallback,
    	    gensym("quality"), A_FLOAT, A_NULL);
}
void texfont :: floatMessCallback(void *data, float n)
{
    GetMyClass(data)->floatmess((int)n);
}
void texfont :: textureMessCallback(void *data, t_floatarg quality)
{
    GetMyClass(data)->textureQuality((int)quality);
}
