
#include <iostream.h>
#include <fstream.h>
#include <gl/gl.h>
#include "glwin.h"
#include "subdobj.h"

int rot_x = 0;
int rot_y = 0;
int need_to_update = 1;
int drawnormals = 0;

float idmat[4][4] = {
  1.0, 0.0, 0.0, 0.0,
  0.0, 1.0, 0.0, 0.0,
  0.0, 0.0, 1.0, 0.0,
  0.0, 0.0, 0.0, 1.0
};


void SetupLights() {

    static float lmodel[] = {
      TWOSIDE, 0.0,
      LMNULL
    };

    static float mat1_array[] = {
      EMISSION, 0.0, 0.0, 0.0,
      AMBIENT,  0.2, 0.2, 0.2,
      DIFFUSE,  1.00, 0.14, 0.60,
      SPECULAR,  0.0, 0.0, 0.0,
      SHININESS, 5.0,
      LMNULL
    };

    lmdef(DEFLMODEL,1,sizeof(lmodel)/sizeof(lmodel[0]),lmodel);

    {
        static float larray1[] = {
            POSITION, 0.0, 0.5, 1.0, 0.0,
            LMNULL
        };
        lmdef(DEFLIGHT,1,sizeof(larray1)/sizeof(larray1[0]),larray1);
    }

    lmdef(DEFMATERIAL, 1, sizeof(mat1_array)/sizeof(mat1_array[0]), mat1_array);

    lmbind(LIGHT0, 1);
    lmbind(LMODEL, 1);
    lmbind(MATERIAL, 1);
}

void SetupView() {

    mmode(MVIEWING);
    loadmatrix(idmat);

    perspective(350, 1.0, 1.0, 1000.0);
    lookat(0, 0, 8,
           0, 0, 0,
           0);

	rotate(rot_x, 'x');
	rotate(rot_y, 'y');
}

void RotateWithMouse(int Continue) {

    static int lastx;
    static int lasty;

    if (!Continue) {
        lastx = (int) getvaluator(MOUSEX);
        lasty = (int) getvaluator(MOUSEY);
    }
    else {
        int dx = (int) (getvaluator(MOUSEX) - lastx);
        int dy = (int) (getvaluator(MOUSEY) - lasty);
        lastx += dx;
        lasty += dy;
        rot_y += (int) ((float) dx * 1600 / 400);
        rot_x += (int) ((float) -dy * 1600 / 400);
        need_to_update = 1;
    }
}


void main(int argc, char *argv[]) {

	SubdObj SDO;
	GLWin W(640, 640, "Linked Half-Edge Object");
	JLString filenames[10];

	ifstream iFile("subd.view.config",ios::in);
	if (iFile) {
		int num;
		JLString fname;
		for (int i=0; i<10; i++) {
			iFile >> num;
			if (num != i)
				cerr << "Error in main.config file" << endl;
			iFile >> fname;
			filenames[i] = fname;
		}
		iFile.close();
	}
	else
		cerr << "Error: main.config file not found" << endl;

//	SDO.MakeCube();
//	SDO.MakePyramid();

	W.ZBuffer().DoubleBuffer().Open();
	concave(TRUE);
	SetupView();
	SetupLights();
//	cpack(0xFFFFFF);

	qdevice(WINQUIT);
	qdevice(WINCLOSE);
	qdevice(LEFTMOUSE);
	qdevice(MIDDLEMOUSE);
	qdevice(RIGHTMOUSE);
	qdevice(ESCKEY);

	qdevice(AKEY);
	qdevice(CKEY);
	qdevice(DKEY);
	qdevice(HKEY);
	qdevice(IKEY);
	qdevice(JKEY);
	qdevice(LKEY);
	qdevice(MKEY);
	qdevice(NKEY);
	qdevice(OKEY);
	qdevice(PKEY);
	qdevice(RKEY);
	qdevice(SKEY);
	qdevice(TKEY);
	qdevice(WKEY);


	qdevice(ZEROKEY);
	qdevice(EQUALKEY);
	qdevice(MINUSKEY);

	qdevice(ONEKEY);
	qdevice(TWOKEY);
	qdevice(THREEKEY);
	qdevice(FOURKEY);
	qdevice(FIVEKEY);
	qdevice(SIXKEY);
	qdevice(SEVENKEY);
	qdevice(EIGHTKEY);
	qdevice(NINEKEY);

//	SDO.Draw();

	short val;
	int ok = 1;
	int rotating = 0;

	while (ok) {

		if (rotating) {
			RotateWithMouse(1);
			SetupView();
		}

		if (need_to_update) {
			W.Clear();
			SDO.Draw();
			if (drawnormals)
				SDO.DrawNormals(0.2f);
			swapbuffers();
			need_to_update = 0;
		}

		if (qtest()) switch (qread(&val)) {

            case WINQUIT:
            case WINCLOSE: // user closes window
                ok = 0;
                break;

            case ESCKEY: // usr quits
                ok = !val; break;

            case LEFTMOUSE: // rotate object
                rotating = val;
                RotateWithMouse(0);
                break;

			case MIDDLEMOUSE: // Subdivide!
				if (val) {
					SDO.CatmullClark();
					need_to_update = 1;
				}
				break;

			case RIGHTMOUSE: // Subdivide!
				if (val) {
					SDO.DooSabin();
					need_to_update = 1;
				}
				break;

			case ONEKEY: // Subdivide!
				if (val) {
					SDO.DooSabin(1);
					need_to_update = 1;
				}
				break;

			case TWOKEY: // Subdivide!
				if (val) {
					SDO.DooSabin(2);
					need_to_update = 1;
				}
				break;

			case AKEY:
				if (val)
					cout << "HalfEdges: " << HalfEdge::Allocated() << endl;
				break;

			case JKEY:
				if (val) {
					SDO.JitterVertecies(0.25);
					need_to_update = 1;
				}
				break;

			case DKEY:
				if (val)
					drawnormals = !drawnormals;
				break;

			case NKEY:
				if (val) {
					SDO.CalcAllVertexNormals();
					need_to_update = 1;
				}
				break;


			case ZEROKEY:
				if (val)
					cout << (SDO.GetNotMidpoint() = 0.5) << endl;;
				break;
			case MINUSKEY:
				if (val)
					cout << (SDO.GetNotMidpoint() -= 0.1) << endl;;
				break;
			case EQUALKEY:
				if (val)
					cout << (SDO.GetNotMidpoint() += 0.1) << endl;;
				break;


			case THREEKEY:
				if (val) {
					SDO.ReadFromFile(filenames[3]);
					need_to_update = 1;
				}
				break;
			case FOURKEY:
				if (val) {
					SDO.ReadFromFile(filenames[4]);
					need_to_update = 1;
				}
				break;
			case FIVEKEY:
				if (val) {
					SDO.ReadFromFile(filenames[5]);
					need_to_update = 1;
				}
				break;
			case SIXKEY:
				if (val) {
					SDO.ReadFromFile(filenames[6]);
					need_to_update = 1;
				}
				break;
			case SEVENKEY:
				if (val) {
					SDO.ReadFromFile(filenames[7]);
					need_to_update = 1;
				}
				break;
			case EIGHTKEY:
				if (val) {
					SDO.ReadFromFile(filenames[8]);
					need_to_update = 1;
				}
				break;
			case NINEKEY:
				if (val) {
					SDO.ReadFromFile(filenames[9]);
					need_to_update = 1;
				}
				break;

			case LKEY:
				if (val) {
					SDO.ReadFromFile(argv[1]);
					need_to_update = 1;
				}
				break;


			case RKEY:
				if (val) {
					SDO.ReverseAllVertexNormals();
					need_to_update = 1;
				}
				break;

			case IKEY:
				if (val) {
					SDO.OutputInventor("InventorFileOut.iv");
				}
				break;

			case MKEY:
				if (val) {
					SDO.ReadRonsFile(argv[1], NULL, 0);
					need_to_update = 1;
				}
				break;

			case WKEY:
				if (val) {
					SDO.ReadWavefrontFile("../models/3free1.obj");
					// SDO.ReadWavefrontFile("Mesh/cube.obj.wf");
					need_to_update = 1;
				}
				break;
		}
	}

	W.Close();
}
