#include <math.h>
#include <stdio.h>
#include "fasttrig.h"
#include "bezpt.h"
#include "revolve.h"
#include "mytypes.h"


RevAxisType RevAxis;


short RevMesh = DefRevMeshVal;
short RevImageR, /* revolution index */
      RevImageB; /* bezier index */

static int RotRange = DefRotRange;
static int RotStart = DefRotStart;
static int SecAngle = DefTilt;
static float SurfDist = DefSurfDist;
static float ViewDist = DefViewDist;
static bool Perspective = DefPersp;

void SetPerspective(  value)
    int value;
{
    Perspective = value;
}



void SetRevAxis( value)

{
    RevAxis = (value)? RevY : RevX;
}


void SetRotStart( value )
    int value;
{
    RotStart = value;
}

void SetRotRange(  value )
    int value;
{
    RotRange = value;
}

void SetSecAng( value )
    int value;
{
    SecAngle = value;
}

void SetRevMesh( value )
    int value;
{
    RevMesh = value;
}



void SetSurfDist( value )
    int value;
{
    SurfDist = (float )value;
}


void SetViewDist( value )
    int value;
{
    ViewDist = (float )value;
}



static
float secsin, seccos; /* trig values of secondary angle */

static
int sizeptlist = 0;

static
PtGen *ptlist1 = 0,
      *ptlist2 = 0;

static
int NumEnts; /* number of angle slices */


static
bool PrepRev()
{
    NumEnts = RevMesh+1;

    /*
     * allocate space 3d descriptions of a point revolved x degrees
     */
    if( NumEnts > sizeptlist ) {
        if( ptlist1 ) free(ptlist1);
        if( ptlist2 ) free(ptlist2);

        ptlist1 =(PtGen *) malloc( NumEnts * sizeof(PtGen)  );
        ptlist2 =(PtGen *) malloc( NumEnts * sizeof(PtGen)  );
        if( !ptlist1 || !ptlist2 ) {
            OutErr("PrepRev:not enough memory");
            return(true);
        }
    }


    if( InitFastTrig( RotStart, RotRange, NumEnts)) return(true);
    secsin = sin((float)SecAngle*PI/180);
    seccos = cos((float)SecAngle*PI/180);
    return (false);
}


static
void CalcRing(ptlist, xpos, ypos)
register PtGen *ptlist;
float xpos, ypos;
{
    int angle;

    for( angle = 0; angle < NumEnts; angle++, ptlist++) {
        float temp;
        /*
         * calculate 3d coordinate of point revolved
         */
        if( RevAxis == RevX) {
            ptlist->d3.y = ypos * fcos(angle);
            temp = ypos * fsin(angle);
            ptlist->d3.x = xpos* seccos - temp *secsin;
            ptlist->d3.z = xpos * secsin + temp * seccos;
        }
        else {
            ptlist->d3.x = xpos * fcos(angle);
            temp = xpos * fsin( angle);
            ptlist->d3.y = ypos * seccos + temp * secsin;
            ptlist->d3.z = secsin * ypos - temp * seccos;
        }
        ptlist->d3.z -= SurfDist;

/*        if( Perspective ) {
            float PerspScale;

            PerspScale = fabs(ViewDist / ptlist->d3.z);
            ptlist->d3.x *= PerspScale;
            ptlist->d3.y *= PerspScale;
        }
 */
        /*
         * calculate the 2d screen coordinate equvalent
         */
      /*
        ptlist->d2.x = (short) ptlist->d3.x;
        ptlist->d2.y = (short) ptlist->d3.y;
       */
        ptlist->d2.x = (short) (ptlist->d3.x + 0.5);
        ptlist->d2.y = (short) (ptlist->d3.y + 0.5);
    }
}






/*
 * return true on failure
 */
bool Revolve(acceptfunc)
    void (*acceptfunc)();
{
    float tparm, deltat;
    int subseg;

    if( PrepRev() ) {
        return(true);
    }

    deltat = 1.0/BezMesh;
    RevImageB = 0;
    ResetActSeg();
    do {
        float xpos, ypos;


        InitCalcBez();
        xpos = StartPtX(GetCurSeg());
        ypos = StartPtY(GetCurSeg());
        CalcRing(ptlist1, xpos, ypos );
        for( subseg = 1; subseg <= BezMesh; subseg++ ) {
            register PtGen *ptlista, *ptlistb;
            register int numpoly;

            tparm = subseg * deltat;
            if( subseg & 1 ) {
                ptlista = ptlist2; ptlistb = ptlist1;
            }
            else {
                ptlista = ptlist1; ptlistb = ptlist2;
            }

            CalcBezPt(tparm, &xpos, &ypos );
            CalcRing( ptlista, xpos, ypos );
            RevImageR = 0;
            for( numpoly = NumEnts -1; numpoly--; ) {
                (* acceptfunc)(ptlistb, ptlista, ptlista+1, ptlistb+1);
                ptlista++;
                ptlistb++;
                RevImageR++;
            }
            RevImageB++;
        }
        NextSeg();

    } while( ActSeg );
    return( false );
}

/*
 * write a ring of points
 */
static void WriteRing(fileout, ptlist, numpnts)
FILE *fileout;
PtGen *ptlist;
int numpnts;
{
    while( numpnts-- ) {
        fprintf(fileout, "%f %f %f \n", ptlist->d3.x,
            ptlist->d3.y, ptlist->d3.z );
            ptlist++;
    }
}

/*
 * write the list of vertices to file pointer
 * this function performs a similar function to revolve
 */
static void WriteRevolve(fileout)
    FILE *fileout;
{
    float tparm, deltat;
    float OldSurfDist;
    int subseg;
    float xpos, ypos;


    OldSurfDist = SurfDist;
    SurfDist = 0;
    deltat = 1.0/BezMesh;
    RevImageB = 0;
    ResetActSeg();
    /*
     * write out the starting ring
     */
    InitCalcBez();
    xpos = StartPtX(GetCurSeg());
    ypos = StartPtY(GetCurSeg());
    CalcRing(ptlist1, xpos, ypos );
    WriteRing(fileout, ptlist1, NumEnts);
    /*
     * loop to write out all the other rings
     */
    do {

        InitCalcBez();
        for( subseg = 1; subseg <= BezMesh; subseg++ ) {
            tparm = subseg * deltat;
            CalcBezPt(tparm, &xpos, &ypos );
            CalcRing( ptlist1, xpos, ypos );
            WriteRing(fileout, ptlist1, NumEnts);
            RevImageB++;
        }
        NextSeg();

    } while( ActSeg );
    SurfDist = OldSurfDist;

    return;
}

/*
 * this function writes a list of vertices to "filename"
 */
void WriteData(filename)
    char *filename;
{
        FILE *fileout;

        if(( GetNumSegs() < 1) || PrepRev()){
                return;
        }

        fileout = fopen(filename,"w");
        if(!fileout) {
            OutErr("could not open data file");
            return;
        }


        fprintf(fileout, "%d   * number of Rings\n", BezRings());
        fprintf(fileout, "%d   * Rev mesh\n", RevMesh);
        fprintf(fileout, "%d   * Rotation range\n", RotRange);
        WriteRevolve(fileout);
        fprintf(fileout, "end\n");
        fclose(fileout);
}



