/****************************************************************************
** GMAF - The Geometry Modeling Algorithms Framework
**
** Created : 07132000
**
** Copyright (C) 2000 by Le-Jeng Shiue.  All rights reserved.
**
****************************************************************************/
#include <iostream>

#ifdef _MAM_VERSION
#include <vrs/vrs.h>
#include <mam/mam.h>
#include "vrsSubPCCMQuadVertexIterator.h"
#endif _MAM_VERSION

#ifdef _OGL_VERSION
#include <GL/glut.h>
#endif _OGL_VERSION

#include "gmafConfig.h"
#include "BlitzExtension/blitzConfig.h"

#include "gmafPCCMVisualObject.h"
#include "gmafPCCMQuadMap.h"
#include "gmafPCCMQuad.h"


gmafPCCMVisualObject::gmafPCCMVisualObject(gmafPCCMQuadMap* pccmqm) 
  : mpPCCMQuadMap(pccmqm), mSamplingTolerance(10.0), mpKnots(NULL) {
  mOrder = mUPoints = mVPoints = 0;

  mPCCMQuadList = mpPCCMQuadMap->getPCCMQuadList();
}

gmafPCCMVisualObject::~gmafPCCMVisualObject() {
  delete mpKnots;
}


#ifdef _MAM_VERSION
MThing* gmafPCCMVisualObject::createMAMObject() {
  return (MThing*) visualizeQuadMap();
}

static int meshOn = 0;

RSharedObj* gmafPCCMVisualObject::visualizeQuadMap() {
  cout << "mesh on ? " ;
  cin >> meshOn;


  MThing* obj = new MThing();
  
  /*
  obj->append(new RFaceStyle(mStyle, mStyle));
  */
  mOrder = 4;
  mVPoints = mPCCMQuadList[0]->getHeight();
  mUPoints = mPCCMQuadList[0]->getWidth();

  createKnots(mUPoints + mOrder);

  for (int i = 0; i < mPCCMQuadList.size(); i++)
    obj->append(visualizeQuad(mPCCMQuadList[i]));
  
  return obj;
}

inline RSharedObj* gmafPCCMVisualObject::visualizeQuad(gmafPCCMQuad* quad) {
  if (!meshOn) {
      RNurbs* s = new RNurbs(mOrder, mOrder, mUPoints, mVPoints);
      s->loadKnotsUfv(mUPoints + mOrder, mpKnots);
      s->loadKnotsVfv(mVPoints + mOrder, mpKnots);
      s->setSamplingTolerance(mSamplingTolerance);
      s->loadVertices3fv(mVPoints*mUPoints, 
			 quad->getPCCMControlNet().data()->data());
      return s;
  } else {
      MThing* q = new MThing();
      RNurbs* s = new RNurbs(mOrder, mOrder, mUPoints, mVPoints);
      s->loadKnotsUfv(mUPoints + mOrder, mpKnots);
      s->loadKnotsVfv(mVPoints + mOrder, mpKnots);
      s->setSamplingTolerance(mSamplingTolerance);
      s->loadVertices3fv(mVPoints*mUPoints, 
			 quad->getPCCMControlNet().data()->data());
      q->append(s);
      
      q->append(new RColorAttribute(1, 0, 0));
      q->append(new RMaterial(1, 0, 0));
      q->append(visualizeQuad(quad, RFaceStyle::Outlined));
      
      return q;
  }
}

RSharedObj* gmafPCCMVisualObject::visualizeQuad(gmafPCCMQuad* quad, int style) {
  MThing* obj = new MThing();

  obj->append(new RFaceStyle(style, style));
  RPolygonSet* p = new RPolygonSet(RPolygonSet::Quads, 
				   new vrsSubPCCMQuadVertexIterator(quad));
  obj->append(p);

  return obj;
}

#endif _MAM_VERSION


#ifdef _OGL_VERSION
void gmafPCCMVisualObject::display() {
  visualizeQuadMap();
}

void gmafPCCMVisualObject::visualizeQuadMap() {
  GLUnurbsObj* pNURBS = gluNewNurbsRenderer();
  gluNurbsProperty(pNURBS, (GLenum)GLU_SAMPLING_TOLERANCE, 10.0);
  gluNurbsProperty(pNURBS, (GLenum)GLU_DISPLAY_MODE, GLU_FILL);

  mOrder = 4;
  mUPoints = mPCCMQuadList[0]->getWidth();
  mVPoints = mPCCMQuadList[0]->getHeight();

  createKnots(mUPoints + mOrder);

  for (int i = 0; i < mPCCMQuadList.size(); i++)
    visualizeQuad(mPCCMQuadList[i], pNURBS);

  gluDeleteNurbsRenderer(pNURBS);
}

inline void gmafPCCMVisualObject::visualizeQuad(gmafPCCMQuad* quad, GLUnurbsObj* pNURBS) {
  gluBeginSurface(pNURBS);
  gluNurbsSurface(pNURBS,
		  mUPoints+mOrder, mpKnots, mVPoints+mOrder, mpKnots,
		  mUPoints*3, 3, 
		  quad->getPCCMControlNet().data()->data(),
		  mOrder, mOrder, GL_MAP2_VERTEX_3);
  gluEndSurface(pNURBS);
}

#endif _OGL_VERSION


void gmafPCCMVisualObject::createKnots(int n) {
  delete mpKnots;
  mpKnots = new DOUBLE[n];

  mpKnots[0] = 0;  mpKnots[1] = 0;  mpKnots[2] = 0;  mpKnots[3] = 0;
  mpKnots[4] = 1;  mpKnots[5] = 1;

  DOUBLE k = n-6-2-1;
  mpKnots[n-1] = k;  mpKnots[n-2] = k;  mpKnots[n-3] = k;  mpKnots[n-4] = k;
  mpKnots[n-5] = k-1;  mpKnots[n-6] = k-1;

  for (int i = 6; i < n-6; i++) mpKnots[i] = i-4; 
}
