/*
 * anytopl.c
 * author:  Celeste Fowler
 * date:  June 12, 1992
 */
#include <stdlib.h>
#include "polylistP.h"
#include "bezierP.h"
#include "quadP.h"
#include "meshP.h"
#include "vectP.h"
#include "listP.h"
#include "instP.h"
#include "hpoint3.h"
#include "point3.h"
#include "plutil.h"

static char msg[] = "anytopl.c";


/*
 * AnyToPL converter.
 * Converts any geomview object to an polylist and returns a pointer
 * to the polylist.  Should return a consolidated polylist, but right
 * now, for the sake of convenience, does not.  NB to future
 * developers: There are a lot of assumptions about the internals of
 * the various data types.  If anything changes, things will have to
 * be adjusted accordingly.
 */

Geom *AnyToPL(Geom *old, Transform T) 
{  
  char *oldtype;
  int g, h, i, j, k;
  HPoint3 *point4 = NULL;
  ColorA *color = NULL;
  Point3 *normal = NULL;
  int npoly = 0;
  int *nvert = NULL, *vert = NULL;
  PolyList *new = NULL;
  int flags = 0;
  int transpts = 1;
  int fourd = 0;

  if (old == NULL) return NULL;
  oldtype = GeomName(old);
  
  /* 
   * PolyList to PolyList 
   */
  if (!strcmp(oldtype, "polylist")) {
    new = (PolyList *) GeomCopy(old);
    flags = new->flags;
  }
  

  /*
   * Bezier to PolyList
   */
  if (!strcmp(oldtype, "bezier")) {
    Bezier *b = (Bezier *)old;

    if ((b->mesh == NULL || 
	 b->mesh->nu != b->nu ||
	 b->mesh->nv != b->nv) || 
	(b->flag & BEZ_REMESH)) BezierReDice(b);
    if (b->geomflags & VERT_4D) fourd = 1;
    return(AnyToPL((Geom *)b->mesh, T));
  }

  /*
   * Quad to PolyList 
   */ 
  if (!strcmp(oldtype, "quad")) {
    Quad *o = (Quad *)old;
    
    /* Copy vertices */
    point4 = (HPoint3 *)OOG_NewE(o->maxquad * 4 * sizeof(HPoint3), msg);
    for (i = 0; i < o->maxquad; i ++) 
      for (j = 0; j < 4; j++) HPt3Copy(&o->p[i][j], &point4[(i*4) + j]);
    
    /* Copy the colors if necessary. */
    if (o->flag & QUAD_C) {
      flags |= PL_HASVCOL;
      color = (ColorA *)OOG_NewE(o->maxquad * 4 * sizeof(ColorA), msg);
      for (i = 0; i < o->maxquad; i++)
	for (j = 0; j < 4; j++)
	  bcopy(&o->c[i][j], &color[(i*4) + j], sizeof(ColorA));
    }

    /* Copy the normals if necessary. */
    if (o->flag & QUAD_N) {
      flags |= PL_HASVN;
      normal = (Point3 *)OOG_NewE(o->maxquad * 4 * sizeof(Point3), msg);
      for (i = 0; i < o->maxquad; i++)
	for (j = 0; j < 4; j++) Pt3Copy(&o->n[i][j], &normal[(i*4) + j]);
    }
    
    /* Create the polygons. */
    nvert = (int *)OOG_NewE(o->maxquad * sizeof(int), msg);
    vert = (int *)OOG_NewE(o->maxquad * 4 * sizeof(int), msg);
    for (i = 0; i < o->maxquad; i++) {
      nvert[i] = 4; 
      for (j = 0; j < 4; j++) vert[(i*4) + j] = (i*4) + j;
    }

    if (o->geomflags & VERT_4D) fourd = 1;
    
    npoly = o->maxquad;
        
  }
  
  
  /* 
   * Mesh to PolyList
   */
  if (!strcmp(oldtype, "mesh")) {
    Mesh *m = (Mesh *)old;
    
    /* Copy vertices. */
    point4 = m->p;
    
    /* Copy the colors. */
    if (m->flag & MESH_C) {
      flags |= PL_HASVCOL;
      color = m->c;
    }

    /* Copy the normals */
    if (m->flag & MESH_N) {
      flags |= PL_HASVN;
      normal = m->n;
    }

    /* Create the polygons. */
    npoly = m->nu * m->nv;
    nvert = (int *)OOG_NewE(npoly * sizeof(int), msg);
    vert = (int *)OOG_NewE(npoly * 4 * sizeof(int), msg);
    for (i = 0; i < m->nv - 1; i++) 
      for (j = 0; j < m->nu - 1; j++) {
	nvert[i * (m->nu - 1) + j] = 4;
	vert[(i * (m->nu - 1) + j) * 4] = i * m->nu + j;
	vert[(i * (m->nu - 1) + j) * 4 + 1] = i * m->nu + j + 1;
	vert[(i * (m->nu - 1) + j) * 4 + 2] = (i + 1) * m->nu + j + 1;
	vert[(i * (m->nu - 1) + j) * 4 + 3] = (i + 1) * m->nu + j;
      }
    /* Do the wrapping if necessary. */
    npoly = (m->nu - 1) * (m->nv - 1);
    if (m->flag & MESH_UWRAP) {
      j = m->nu - 1;
      for (i = 0; i < m->nv - 1; i++) {
	nvert[npoly] = 4;
	vert[npoly * 4] = i * m->nu + j;
	vert[npoly * 4 + 1] = i * m->nu;
	vert[npoly * 4 + 2] = (i + 1) * m->nu;
	vert[npoly++ * 4 + 3] = (i + 1) * m->nu + j;
      }
    }
    if (m->flag & MESH_VWRAP) {
      i = m->nv - 1;
      for (j = 0; j < m->nu - 1; j++) {
	nvert[npoly] = 4;
	vert[npoly * 4] = i * m->nu + j;
	vert[npoly * 4 + 1] = i *m->nu + j + 1;
	vert[npoly * 4 + 2] = j + 1;
	vert[npoly++ * 4 + 3] = j;
      }
    }
    if (m->flag & MESH_UWRAP && m->flag & MESH_VWRAP) {
      nvert[npoly] = 4;
      vert[npoly * 4] = m->nu * m->nv - 1;
      vert[npoly * 4 + 1] = (m->nv - 1) * m->nu;
      vert[npoly * 4 + 2] = 0;
      vert[npoly++ * 4 + 3] = m->nu - 1; 
    }

    if (m->geomflags & VERT_4D) fourd = 1;

  }
  
  
  
  /* 
   * Vect to PolyList
   */
  if (!strcmp(oldtype, "vect")) {
    Vect *v = (Vect *)old;
    
    /* Copy points. */
    point4 = v->p;

    /* Copy colors. */
    if (v->ncolor) {
      flags |= PL_HASVCOL;
      color = OOGLNewNE(ColorA, 2 * v->nvert, msg);
      for (g = h = i = 0; h < v->nvec; h++) {
	if (h && v->vncolor[h]) i++;
	for (j = k = 0; j < abs(v->vnvert[h]); j++) {
	  bcopy(&v->c[i + k], &color[g++], sizeof(ColorA));
	  if (k + 1 < v->vncolor[h]) k++;
	}
	i += k;
      }
    }
    
    /* Create polygons to connect the points. */
    nvert = (int *)OOG_NewE(v->nvert * sizeof(int), msg);
    for (i = 0; i < v->nvert; i++) nvert[i] = 2;
    vert = (int *)OOG_NewE(v->nvert * 2 * sizeof(int), msg);
    for (h = i = k = 0; i < v->nvec; i++) {
      for (j = 0; j < abs(v->vnvert[i]);) {
	vert[h++] = k+j++;
	vert[h++] = k+j;
      }
      if (j) h -= 2;
      if (v->vnvert[i] < 0) {
	vert[h++] = k;
	vert[h++] = k+j-1;
      }
      k += j;
    }

    npoly = h/2;
    
    if (v->geomflags & VERT_4D) fourd = 1;

  }
    

  /* 
   * List to PolyList
   */
  if (!strcmp(oldtype, "list") || !strcmp(oldtype, "bezierlist")) {
    List *l = (List *)old;
    Geom *a, *b;
    
    new = (PolyList *)PLCombine(a = AnyToPL((Geom *)l->car, T), 
				b = AnyToPL((Geom *)l->cdr, T));
    GeomDelete(a);
    GeomDelete(b);

    transpts = 0;

    if (l->geomflags & VERT_4D) fourd = 1;
    
  }
  
    
  /* 
   * Inst to PolyList 
   */
  if (!strcmp(oldtype, "inst")) {
    Inst *inst = (Inst *)old;
    Transform Tnew;
    GeomIter *it;
    Geom *a = NULL;
    
    it = GeomIterate((Geom *)inst, DEEP);
    while (NextTransform(it, Tnew)) {
      TmConcat(Tnew, T, Tnew); 
      a = AnyToPL(inst->geom, Tnew);
      new = (PolyList *)PLCombine((Geom *)new, a);
      GeomDelete(a);
    }

    transpts = 0;

    if (inst->geomflags & VERT_4D) fourd = 1;

  }
    
  /* Create the new object */
  if (new == NULL && npoly) new = (PolyList *) 
    GeomCreate("polylist", 
	       CR_NPOLY, npoly,
	       CR_POINT4, point4,
	       CR_COLOR, color,
	       CR_NORMAL, normal,
	       CR_NVERT, nvert,
	       CR_VERT, vert,
	       CR_FLAG, flags,
	       CR_4D, fourd,
	       CR_END);

  if (strcmp(oldtype, "mesh")) {
    if (strcmp(oldtype, "vect") && point4 != NULL) OOGLFree(point4);
    if (color != NULL) OOGLFree(color);
    if (nvert != NULL) OOGLFree(nvert);
    if (vert != NULL) OOGLFree(vert);
  }

  if (new == NULL) return NULL;
  
  /* Apply the transformation. */
  if (transpts) 
    for (i = 0; i < new->n_verts; i++) {
      HPt3Transform(T, &new->vl[i].pt, &new->vl[i].pt);
      if (!(new->geomflags & VERT_4D))
	HPt3Dehomogenize(&new->vl[i].pt, &new->vl[i].pt);
    }

  return((Geom *)new);
  
}

