/* Jin Ding -- Period 3 -- 3/31/98 */
/* julie.cpp */

#include <iostream.h>
#include <stdio.h>
#include <glaux.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>
#include <math.h>
#include <targa.h>

const MAX=400,MAXIT=50;
double color[MAXIT][3],
  startx=-2.0, starty=2.0, 
  endx=2.0, endy=-2.0,
  z=-0.65,
  cx=0.0, cy=0.0;
int julia=0,endgot=1,origMand=1,
    red[MAX*MAX],green[MAX*MAX],blue[MAX*MAX];

/*********************************************************************/

static void Init (void) {
  glClearColor(0.0,0.0,0.0,1.0);
  glShadeModel(GL_SMOOTH);
}

static void Reshape(int width, int height) {
  glViewport(0,0,(GLsizei)width,(GLsizei)height);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluPerspective(60.0,(GLfloat)width/(GLfloat)height,1.0,0.0);
  glMatrixMode(GL_MODELVIEW);
}

static void key_esc() {
  auxQuit();
}

static void getStart(AUX_EVENTREC *mouserec) {
  startx=mouserec->data[0]/(MAX/2.0)-1.0;
  starty=1.0-mouserec->data[1]/(MAX/2.0);
  cout<<startx<<" "<<starty<<endl;
  endgot=0;
  origMand=0;
}

static void getEnd(AUX_EVENTREC *mouserec) {
  endx=mouserec->data[0]/(MAX/2.0)-1.0;
  endy=1.0-mouserec->data[1]/(MAX/2.0);
  cout<<endx<<" "<<endy<<endl;
  endgot=1;
}

static void changeMand() {
  julia=0;
  origMand=1;
  endgot=1;
}

static void changeJulia(AUX_EVENTREC *mouserec) {
  julia=1;
  origMand=0;
  endgot=1;
  cx=mouserec->data[0]/(MAX/2.0)-1.0;
  cy=1.0-mouserec->data[1]/(MAX/2.0);
  cout<< cx <<" julia=1 "
      << cy <<endl;
}

/*********************************************************************/

double abs(double num) {
  return sqrt(num*num);
}

void SetColor() {
  for (int i=0;i<MAXIT;i++) {
    color[i][0]=0.0;
    color[i][1]=i/30.0;
    color[i][2]=i/10.0;
  }
}

void DispMand() {
int x,y,index;

  glBegin(GL_POINTS);
  for (y=MAX;y>-MAX;y--)
    for (x=-MAX;x<MAX;x++) {
      index=(x+MAX)/2+((y+MAX)/2)*MAX;
      glColor3f(red[index]/256.0,green[index]/256.0,blue[index]/256.0);
      glVertex3f(2.0*x/MAX,2.0*y/MAX,0);
    }
  glEnd();
}

void DrawMyStuff() {
int it,xfac,yfac;
double x,y,xnew,ynew,xtemp,ytemp,r,xdiff;

  xdiff = endx-startx;
  glBegin(GL_POINTS);
//  for (y = 4.0;y>-4.0;y-=(starty-endy)/(2.0*MAX))
//    for (x = -4.0;x<4.0;x+=(endx-startx)/(2.0*MAX)) {
  for (y = 2.0*starty;y>2.0*(starty-xdiff);y-=.005){
    for (x = 2.0*startx;x<2.0*endx;x+=.005) {
//  for (y = 4.0;y>-4.0;y-=.05){
//    for (x = -4.0;x<4.0;x+=.05) {
      it = 0; r = 0.0;
      if (!julia) {
        cx = x/2.0;
        cy = y/2.0;
      }
      xnew = x/2.0;
      ynew = y/2.0;
      while ((r < 4) && (it < MAXIT)) {
        xtemp = xnew*xnew - ynew*ynew + cx;
        ytemp = 2 * xnew * ynew + cy;
        r = xtemp*xtemp + ytemp*ytemp;
        it++;
        xnew = xtemp;
        ynew = ytemp;
      }
      glColor3f(color[it][0],color[it][1],color[it][2]);
//      glVertex3f((x/2.0+xdiff/2.0)*(4.0/xdiff),(y/2.0-xdiff/2.0)*(4.0/xdiff),0);
//      cout<<(x/2.0+xdiff/2.0)*(4.0/xdiff)<<" "<<(y/2.0-xdiff/2.0)*(4.0/xdiff)<<endl;
      glVertex3f((4.0/xdiff)*(x/2.0-startx-xdiff/2.0),(4.0/xdiff)*(y/2.0-starty+xdiff/2.0),0);
      cout<<(4.0/xdiff)*(x/2.0-startx-xdiff/2.0)<<" "<<(4.0/xdiff)*(y/2.0-starty+xdiff/2.0)<<endl;
    }
  }
//  cout<<(starty-endy)/(2.0*MAX)<<endl;
  cout<<xdiff<<" "<<(endx-startx)/(2.0*MAX)<<endl;
  glEnd();
}
 
/*********************************************************************/
 
void FirstMand(FILE *mandel,targa &h) {
int x,y,it,index;
double xnew,ynew,xtemp,ytemp,r;

  for (y = -MAX/2;y<MAX/2;y++)
    for (x = -MAX/2;x<MAX/2;x++) {
      it = 0; r = 0.0;
      cx = 4.0*x/MAX;
      cy = 4.0*y/MAX;
      xnew = 4.0*x/MAX;
      ynew = 4.0*y/MAX;
      while ((r < 4) && (it < MAXIT)) {
        xtemp = xnew*xnew - ynew*ynew + cx;
        ytemp = 2 * xnew * ynew + cy;
        r = xtemp*xtemp + ytemp*ytemp;
        it++;
        xnew = xtemp;
        ynew = ytemp;
      }
      index=(x+MAX/2)+(y+MAX/2)*MAX;
      red[index]=(int)(color[it][0]*256);
      green[index]=(int)(color[it][1]*256);
      blue[index]=(int)(color[it][2]*256);
      fputc(blue[index],mandel);
      fputc(green[index],mandel);
      fputc(red[index],mandel);
/*      fputc((int)(color[it][2]*256),mandel);
      fputc((int)(color[it][1]*256),mandel);
      fputc((int)(color[it][0]*256),mandel);
*/
    }
}

/*********************************************************************/

static void display() {
  if (endgot) {
    glClear(GL_COLOR_BUFFER_BIT);
    glPushMatrix();
      glLoadIdentity();
      gluLookAt(0.0,0.0,1.01*MAX,0.0,0.0,0.0,0.0,1.0,0.0);
      glTranslatef(0.0,0.0,MAX-z);
      if (!origMand)
        DrawMyStuff();
      else DispMand();
    glPopMatrix();
    glFlush();
    auxSwapBuffers();
  }
}

int main(int argc,char **argv) {
FILE *mandel;
targa h;

  if ((mandel=fopen("mandel.tga","wb")) == NULL) {
    printf("Can't open mandel.tga\n");
    exit(0);
  }
  glClear(GL_COLOR_BUFFER_BIT);
  SetColor();
  h.setheader(h.width,MAX);
  h.setheader(h.height,MAX);
  h.writeheader(mandel);
  FirstMand(mandel,h);
  fclose(mandel);

  auxInitDisplayMode(AUX_RGBA);
  auxInitPosition(50,100,MAX,MAX);
  if (auxInitWindow("Julia Set") == GL_FALSE)
    auxQuit();
  Init();
  auxMouseFunc(AUX_LEFTBUTTON,AUX_MOUSEDOWN,getStart);
  auxMouseFunc(AUX_LEFTBUTTON,AUX_MOUSEUP,getEnd);
  auxMouseFunc(AUX_RIGHTBUTTON,AUX_MOUSEDOWN,changeJulia);
  auxKeyFunc(AUX_RETURN,changeMand);
//  auxKeyFunc(AUX_i,zoomIn);
//  auxKeyFunc(AUX_o,zoomOut);
  auxReshapeFunc(Reshape);
  auxMainLoop(display);
  return 0;
}
