/*
 * $Id: legoblocks.cpp,v 1.20 2002/07/22 11:44:37 jkaarlas Exp $
 *
 *
 * $Log: legoblocks.cpp,v $
 * Revision 1.20  2002/07/22 11:44:37  jkaarlas
 * naama
 *
 * Revision 1.19  2002/07/18 23:05:31  msell
 * Partikkelit ja kakkospelaajan liike
 *
 * Revision 1.18  2002/07/17 20:32:47  msell
 * Detail-optio toimii
 *
 * Revision 1.17  2002/07/16 17:16:34  msell
 * Fontit ja valikot
 *
 * Revision 1.16  2002/07/16 00:42:43  msell
 * Uusia skyboxeja ja areenan säätöä
 *
 * Revision 1.15  2002/07/15 20:32:35  msell
 * Uudet valot ja ulkoasun parantelua
 *
 * Revision 1.14  2002/07/15 15:22:08  msell
 * Parantelua
 *
 * Revision 1.13  2002/07/14 21:40:43  msell
 * Conflictit pois, liikkumiset (hyppy, kävely, lyönti), uusi areena
 *
 * Revision 1.12  2002/06/30 16:05:04  msell
 * Törmäyksien parantelua, transformaatioita mukana
 *
 * Revision 1.11  2002/06/27 00:08:04  msell
 * Kimmotukset palloille myös pyöritettyihin mesheihin
 *
 * Revision 1.10  2002/06/24 14:12:15  msell
 * Nyt toimii sphere -> mesh -törmäykset, ihan tosi
 *
 * Revision 1.9  2002/06/24 04:41:43  jkaarlas
 * tekstuurikoordinaatteja korjattu
 *
 * Revision 1.8  2002/06/20 22:50:12  msell
 * Meshit
 *
 * Revision 1.7  2002/06/20 00:21:01  jkaarlas
 * materiaali- ja tekstuurihommia edistetty
 *
 * Revision 1.6  2002/06/17 19:58:08  msell
 * #includeiden parantelua
 *
 * Revision 1.5  2002/06/15 17:18:37  msell
 * Toimiva törmäystarkastus kiinteille laatikoille
 *
 * Revision 1.4  2002/06/05 18:39:04  msell
 * Jotain pientä
 *
 * Revision 1.3  2002/06/05 15:00:41  msell
 * Palikoihin lisää detailia, facet jaetaan halutun kokosiin osiin
 *
 * Revision 1.2  2002/06/04 16:28:32  msell
 * #pragma once
 *
 * Revision 1.1  2002/06/03 23:06:38  msell
 * no message
 *
 *
 *
 *
 * $Date: 2002/07/22 11:44:37 $
 *
 */

#include "main.h"

#include <math.h>

#include "legoblocks.h"
#include "utils.h"
#include "3dutils.h"
#include "objectfactory.h"
#include "vector.h"
#include "glapi.h"

BasicBlock::BasicBlock(int width, int height, int depth) : MeshObject(createBox(-width/2.0, width/2.0, -height/2.0*BLOCKHEIGHT, BLOCKHEIGHT*height/2.0, -depth/2.0, depth/2.0)){
	appearance = new BasicBlockAppearance(width, height, depth);
	//geometry = new MeshShape(this);
}

void BasicBlock::setColor(float red, float green, float blue){
	appearance->getMaterial()->setColor(red, green, blue, 1);
}



BasicBlockAppearance::BasicBlockAppearance(int width, int height, int depth){
	this->width = width;
	this->height = height;
	this->depth = depth;
	vectorSet(displacement, 0, 0, 0);
	gllist = glGenLists(1);
	usematerial = true;
}

void BasicBlockAppearance::prepare(){
	glNewList(gllist, GL_COMPILE);

	
	float width = this->width;
	float height = this->height * BLOCKHEIGHT;

  if (usematerial) material.enable();
	{//Block
		//Front Face
		glPushMatrix();
		glTranslatef(-width/2.0, -height/2.0, depth/2.0);
		drawDetailRectangle(width, height);
		glPopMatrix();

		// Back Face
		glPushMatrix();
		glTranslatef(width/2.0, -height/2.0, -depth/2.0);
		glRotatef(180, 0, 1, 0);
		drawDetailRectangle(width, height);
		glPopMatrix();

		// Top Face
		glPushMatrix();
		glTranslatef(-width/2.0, height/2.0, depth/2.0);
		glRotatef(-90, 1, 0, 0);
		drawDetailRectangle(width, depth);
		glPopMatrix();

		// Bottom Face
		glPushMatrix();
		glTranslatef(-width/2.0, -height/2.0, -depth/2.0);
		glRotatef(90, 1, 0, 0);
		drawDetailRectangle(width, depth);
		glPopMatrix();

		// Right face
		glPushMatrix();
		glTranslatef(width/2.0, -height/2.0, depth/2.0);
		glRotatef(90, 0, 1, 0);
		drawDetailRectangle(depth, height);
		glPopMatrix();

		// Left Face
		glPushMatrix();
		glTranslatef(-width/2.0, -height/2.0, -depth/2.0);
		glRotatef(-90, 0, 1, 0);
		drawDetailRectangle(depth, height);
		glPopMatrix();
	}

	glPushMatrix();
	glTranslatef(0.5 - width/2.0, height - height/2.0, 0.5 - depth/2.0);
	int x, z;
	for (x = 0; x < width; x++){
		//glPushMatrix();
		for (z = 0; z < depth; z++){
			createKnob();
			glTranslatef(0, 0, 1);
		}
		glTranslatef(1, 0, -depth);
		//glPopMatrix();
	}
	glPopMatrix();

  if (usematerial) material.disable();
	glEndList();
}

void BasicBlockAppearance::draw(){
	glPushMatrix();
	glTranslatef(displacement[0], displacement[1], displacement[2]);
	glCallList(gllist);
	glPopMatrix();
	//prepare();
}


#define BLOCKDETAILGRID 1

void drawDetailRectangle(float width, float height){
	glBegin(GL_QUADS);
		float x, y, x2, y2;
		glNormal3f(0, 0, 1);
        
		for (y = 0; y < height; y += BLOCKDETAILGRID){
			y2 = y + BLOCKDETAILGRID;
			if (y2 > height) y2 = height;
			for (x = 0; x < width; x += BLOCKDETAILGRID){
				x2 = x + BLOCKDETAILGRID;
				if (x2 > width) x2 = width;
 				
				glTexCoord2f(x / width, y / height);
				glVertex3f(x, y, 0);

				glTexCoord2f(x2 / width, y / height);
				glVertex3f(x2, y, 0);

				glTexCoord2f(x2 / width, y2 / height);
				glVertex3f(x2, y2, 0);

				glTexCoord2f(x / width, y2 / height);
				glVertex3f(x, y2, 0);
			}
		}
	glEnd();
}

#define KNOBROUNDNESS 0.03

int knobgllist;
int knobdetail;

void renderKnob(int knobsegments){
	point2d knobpoints[4];
	knobpoints[0].x = 0.3;
	knobpoints[0].y = 0;
	knobpoints[1].x = 0.3;
	knobpoints[1].y = BLOCKHEIGHT*0.5 - KNOBROUNDNESS;
	knobpoints[2].x = 0.3 - KNOBROUNDNESS;
	knobpoints[2].y = BLOCKHEIGHT*0.5;
	knobpoints[3].x = 0;
	knobpoints[3].y = BLOCKHEIGHT*0.5;

	point2d knobderivates[4];
	knobderivates[0].x = 0;
	knobderivates[0].y = knobpoints[1].y - knobpoints[0].y;
	knobderivates[1].x = 0;
	knobderivates[1].y = knobpoints[2].y - knobpoints[1].y;
	knobderivates[2].x = knobpoints[2].x - knobpoints[1].x;
	knobderivates[2].y = 0;
	knobderivates[3].x = knobpoints[3].x - knobpoints[2].x;
	knobderivates[3].y = 0;

	createLathedSurface(knobpoints, knobderivates, 4, knobsegments, 4);	
}

void initKnob(void){
	glNewList(knobgllist, GL_COMPILE);

	renderKnob(knobdetail);
	
	glEndList();
}

void createKnob(int knobsegments){
	if (knobsegments != -1){
		renderKnob(knobsegments);
		return;
	}
	glCallList(knobgllist);
}





float knobroundness=0.05;
float pillarroundness=0.03;

HeadAppearance::HeadAppearance(void){
	gllist = glGenLists(1);
}

void HeadAppearance::prepare(void){
	glNewList(gllist, GL_COMPILE);
	
	glPushMatrix();

	glTranslatef(0, -0.5, 0);

	point2d headpoints[14];

	headpoints[0].x=0.0; headpoints[0].y=BLOCKHEIGHT*(0);
	headpoints[1].x=0.4; headpoints[1].y=BLOCKHEIGHT*(0);
	headpoints[2].x=0.45; headpoints[2].y=BLOCKHEIGHT*(0.35);
	headpoints[3].x=0.55; headpoints[3].y=BLOCKHEIGHT*(0.5);
	headpoints[4].x=0.62*1.0; headpoints[4].y=BLOCKHEIGHT*(0.65);
	headpoints[5].x=0.65*1.0; headpoints[5].y=BLOCKHEIGHT*(1);
	headpoints[6].x=0.65*1.0; headpoints[6].y=BLOCKHEIGHT*(1.75);
	headpoints[7].x=0.65*1.0; headpoints[7].y=BLOCKHEIGHT*(2.35);
	headpoints[8].x=0.62*1.0; headpoints[8].y=BLOCKHEIGHT*(2.60);
	headpoints[9].x=0.55*1.0; headpoints[9].y=BLOCKHEIGHT*(2.80);
	headpoints[10].x=0.4; headpoints[10].y=BLOCKHEIGHT*(2.95);
	headpoints[11].x=0.3; headpoints[11].y=BLOCKHEIGHT*3.5-pillarroundness;
	headpoints[12].x=0.3-pillarroundness; headpoints[12].y=BLOCKHEIGHT*3.5;
	headpoints[13].x=0; headpoints[13].y=BLOCKHEIGHT*3.5;
	headpoints[11].x=0; headpoints[11].y=BLOCKHEIGHT*3.0;

	glColor4f(0.8,0.8,0.0,1.0);

	
	faceTexture->enable();
	glBlendFunc(GL_ONE, GL_SRC_ALPHA);
	createLathedSurface(headpoints,NULL,12,16,24);
	faceTexture->disable();	

	glTranslatef(0, BLOCKHEIGHT*3-0.05, 0);

	createKnob(16);

	glPopMatrix();

	glEndList();
}

void HeadAppearance::draw(void){
	glCallList(gllist);
}





FlowerAppearance::FlowerAppearance(int color1, int color2, int color3){
	gllist = glGenLists(1);
	this->color1 = color1;
	this->color2 = color2;
	this->color3 = color3;
}

void FlowerAppearance::prepare(void){
	glNewList(gllist, GL_COMPILE);
	
	glPushMatrix();


	int colors[]={color1,color2,color3};

	glColor3f(0.0,0.6,0.0);

	point2d basepoints[8];
	basepoints[0].x=0.4; basepoints[0].y=0;
	basepoints[1].x=0.4; basepoints[1].y=BLOCKHEIGHT*1.5-pillarroundness;
	basepoints[2].x=0.4-pillarroundness; basepoints[2].y=BLOCKHEIGHT*1.5;
	basepoints[3].x=0.3+pillarroundness; basepoints[3].y=BLOCKHEIGHT*1.5;
	basepoints[4].x=0.3; basepoints[4].y=BLOCKHEIGHT*1.5+pillarroundness;
	basepoints[5].x=0.3; basepoints[5].y=BLOCKHEIGHT*2.0-pillarroundness;
	basepoints[6].x=0.3-pillarroundness; basepoints[6].y=BLOCKHEIGHT*2.0;
	basepoints[7].x=0; basepoints[7].y=BLOCKHEIGHT*2.0;

	point2d basederivates[8];
	basederivates[0].x=0; basederivates[0].y=basepoints[1].y-basepoints[0].y;
	basederivates[1].x=0; basederivates[1].y=basepoints[2].y-basepoints[1].y;
	basederivates[2].x=basepoints[2].x-basepoints[1].x; basederivates[2].y=0;
	basederivates[3].x=basepoints[4].x-basepoints[3].x; basederivates[3].y=0;
	basederivates[4].x=0; basederivates[4].y=basepoints[4].y-basepoints[3].y;
	basederivates[5].x=0; basederivates[5].y=basepoints[6].y-basepoints[5].y;
	basederivates[6].x=basepoints[6].x-basepoints[5].x; basederivates[6].y=0;
	basederivates[7].x=basepoints[7].x-basepoints[6].x; basederivates[7].y=0;

	createLathedSurface(basepoints,basederivates,8,8,8);

	int i,j;
	for (i=0;i<3;i++){
		glColor3f(0.0,0.6,0.0);
		glPushMatrix();
		glTranslatef(0,BLOCKHEIGHT,0.4);
		glRotatef(20-90,1,0,0);
		gluCylinder(gluNewQuadric(),0.1,0.1,BLOCKHEIGHT*(3+i*0.7),4,1);
		glRotatef(90,1,0,0);
		glTranslatef(0,BLOCKHEIGHT*(3+i*0.7),0);

		float r,g,b;
		switch(colors[i]){
		case FLOWER_RED:
			r=1.0; g=0.0; b=0.0;
			break;
		case FLOWER_YELLOW:
			r=1.0; g=1.0; b=0.0;
			break;
		case FLOWER_WHITE:
			r=1.0; g=1.0; b=1.0;
			break;
		}
		
		glDisable(GL_CULL_FACE);
		glColor3f(r,g,b);
		createKnob();

    /* Terälehdet tehdään triangle-fanilla */
		glBegin(GL_TRIANGLE_FAN);
			glNormal3f(0.0,1.0,0.0);
			glVertex3f(0.0,0.0,0.0);
			float x,z;
			for (j=0;j<24;j+=4){
				x=sin((j+0)*2*PI/24)*0.4;
				z=cos((j+0)*2*PI/24)*0.4;
				glVertex3f(x,0.0,z);
				x=sin((j+1)*2*PI/24)*0.55;
				z=cos((j+1)*2*PI/24)*0.55;
				glVertex3f(x,0.0,z);
				x=sin((j+2)*2*PI/24)*0.6;
				z=cos((j+2)*2*PI/24)*0.6;
				glVertex3f(x,0.0,z);
				x=sin((j+3)*2*PI/24)*0.55;
				z=cos((j+3)*2*PI/24)*0.55;
				glVertex3f(x,0.0,z);
			}
			glVertex3f(0,0.0,0.4);
		glEnd();
		glEnable(GL_CULL_FACE);

		glPopMatrix();

		glRotatef(120,0,1,0);
	}

	glPopMatrix();

	glEndList();
}

void FlowerAppearance::draw(void){
	glCallList(gllist);
}





LampAppearance::LampAppearance(void){
	gllist = glGenLists(1);
}

void LampAppearance::prepare(void){
	glNewList(gllist, GL_COMPILE);
	
	glPushMatrix();

	//glTranslatef(0, -1, 0);

	//glRotatef(180, 1, 0, 0);

  glDisable(GL_LIGHTING);

	point2d lightpoints[11];
	lightpoints[0].x=0.4; lightpoints[0].y=BLOCKHEIGHT*(0);
	lightpoints[1].x=0.55; lightpoints[1].y=BLOCKHEIGHT*(0);
	lightpoints[2].x=0.62; lightpoints[2].y=BLOCKHEIGHT*(0+0.15);
	lightpoints[3].x=0.65; lightpoints[3].y=BLOCKHEIGHT*(0+0.5);
	lightpoints[4].x=0.68; lightpoints[4].y=BLOCKHEIGHT*(0+1.25);
	lightpoints[5].x=0.65; lightpoints[5].y=BLOCKHEIGHT*(0+2);
	lightpoints[6].x=0.62; lightpoints[6].y=BLOCKHEIGHT*(0+2.35);
	lightpoints[7].x=0.55; lightpoints[7].y=BLOCKHEIGHT*(0+2.5);
	lightpoints[8].x=0.4; lightpoints[8].y=BLOCKHEIGHT*(0+2.5);
	lightpoints[9].x=0.4; lightpoints[9].y=BLOCKHEIGHT*(0+3);
	lightpoints[10].x=0.0; lightpoints[10].y=BLOCKHEIGHT*(0+3);
	glColor4f(0.8,0.8,0.8,0.5);
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);

	createLathedSurface(lightpoints,NULL,11,8,11);

	glEnable(GL_LIGHTING);

	/*glColor3f(0.5, 0.5, 0.5);

	glBegin(GL_LINES);
		glVertex3f(0, 1, 0);
		glVertex3f(0, -100, 0);
	glEnd();*/


	/*float screencoords[3]
	getPointCoordinates(0,lighty,0);

	glLoadIdentity();
	glTranslatef(screencoords.x,screencoords.y,0);
	glDisable(GL_DEPTH_TEST);
	glEnable(GL_CULL_FACE);
	glEnable(GL_BLEND);

	glBlendFunc(GL_ONE,GL_ONE);
	glEnable(GL_TEXTURE_2D);
	glBindTexture(GL_TEXTURE_2D,*flaretexture);

	glMatrixMode(GL_PROJECTION);
	glPushMatrix();
	glLoadIdentity();
	float sizey=8.0/distance*staticlightflarebrightnesses[lightnumber];
	float sizex=sizey*height/width;

	if (distance>0.5){
		glBegin(GL_QUADS);
			glColor3f(staticlightflarebrightnesses[lightnumber],staticlightflarebrightnesses[lightnumber],staticlightflarebrightnesses[lightnumber]);

			glTexCoord2f(0.0, 0.0);
			glVertex2f(-sizex,sizey);

			glTexCoord2f(0.0, 1.0);
			glVertex2f(-sizex,-sizey);
			
			glTexCoord2f(1.0, 1.0);
			glVertex2f( sizex,-sizey);
			
			glTexCoord2f(1.0, 0.0);
			glVertex2f( sizex,sizey);
		glEnd();
	}

	glDisable(GL_TEXTURE_2D);

	glDisable(GL_BLEND);

	glPopMatrix();
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();*/



	glPopMatrix();

	glEndList();
}

void LampAppearance::draw(void){
	glCallList(gllist);
}