/*
<?xml version='1.0' standalone='yes' ?>

<script>
	<name>Platonic Solid</name>
	<author>Fran�ois Guillet</author>
	<version>1.9</version>
	<date>08/22/2007</date>
	<description>
This script creates one of the five platonic solids:
tetrahedron, hexahedron, octahedron, dodecahedron, icosahedron.
The polyhedron created consists of a triangular mesh
with an optional vertex at the center of each face
after "Geometric Tools for Computer Graphics", Philip J. Schneider and David H. Eberly, pp 346-351
Morgan and Kaufmann 2003
    </description>
</script>
*/

/* Copyright (C) 2004 by Fran�ois Guillet

   This program is free software; you can redistribute it and/or modify it under the
   terms of the GNU General Public License as published by the Free Software
   Foundation; either version 2 of the License, or (at your option) any later version.

   This program is distributed in the hope that it will be useful, but WITHOUT ANY 
   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A 
   PARTICULAR PURPOSE.  See the GNU General Public License for more details. */
   
//Script localization test

HashMap translations = new HashMap();
if (Translate.getLocale().equals(Locale.FRENCH))
{
         translations.put("Hexahedron", "Hexah\u00E8dre (6)");
         translations.put("Tetrahedron", "Tetrah\u00E8dre (4)");
         translations.put("Octahedron", "Octah\u00E8dre (8)");
         translations.put("Dodecahedron", "Dodecah\u00E8dre (12)");
         translations.put("Icosahedron", "Icosah\u00E8dre (20)");
         translations.put("centeredFaces", "sommets aux centres des faces");
         translations.put("selectPolyhedron", "S\u00E9lectionnez un polyh\u00E8dre :");
         translations.put("noSmoothing", "Pas de lissage" );
         translations.put("smoothShading", "Ombrage doux" );
         translations.put("interpolating", "Interpolation" );
         translations.put("approximating", "Approximation" );
         translations.put("polyhedron", "Polyh\u00E8dre:" );
         translations.put("faceCenteredMesh", "Maillage face centr\u00E9e" );
         translations.put("radius", "Rayon :" );
         translations.put("smoothingMethod", "M\u00E9thode de lissage:");
         translations.put("verticesSmoothness", "Lissage des sommets :");
         translations.put("edgesSmoothness", "Lissages des ar\u00EAtes :");
         translations.put("texture", "Texture :");
         translations.put("material", "Mat\u00E9riau :");
         translations.put("hexahedron", "Hexah\u00E8dre");
         translations.put("tetrahedron", "Tetrah\u00E8dre");
         translations.put("octahedron", "Octah\u00E8dre");
         translations.put("dodecahedron", "Dodecah\u00E8dre");
         translations.put("icosahedron", "Icosah\u00E8dre");
}
else
{
         translations.put("Hexahedron", "Hexahedron (6)");
         translations.put("Tetrahedron", "Tetrahedron (4)");
         translations.put("Octahedron", "Octahedron (8)");
         translations.put("Dodecahedron", "Dodecahedron (12)");
         translations.put("Icosahedron", "Icosahedron (20)");
         translations.put("centeredFaces", "vertices at faces centers");
         translations.put("selectPolyhedron", "Select a polyhedron:");
         translations.put("noSmoothing", "No Smoothing" );
         translations.put("smoothShading", "Smooth Shading" );
         translations.put("interpolating", "Interpolating" );
         translations.put("approximating", "Approximating" );
         translations.put("polyhedron", "Polyhedron:" );
         translations.put("faceCenteredMesh", "Face centered mesh" );
         translations.put("radius", "Radius:" );
         translations.put("smoothingMethod", "Smoothing Method:");
         translations.put("verticesSmoothness", "Vertices Smoothness:");
         translations.put("edgesSmoothness", "Edges smoothness:");
         translations.put("texture", "Texture:");
         translations.put("material", "Material:");
         translations.put("hexahedron", "Hexahedron");
         translations.put("tetrahedron", "Tetrahedron");
         translations.put("octahedron", "Octahedron");
         translations.put("dodecahedron", "Dodecahedron");
         translations.put("icosahedron", "Icosahedron");
}
//end of script localization test
   
   
//given a set of faces, this function computes the centers of the faces and adds them to the list of vertices
Vec3[] completeVertices(Vec3[] vert, int[][] polyFaces, int vertNum)
{	vertices = new Vec3[vert.length + polyFaces.length];
    
    for (i = 0 ; i < vert.length ; ++i)
        vertices[i] = vert[i];
    
    for (i = vertNum; i < vertNum + polyFaces.length; ++i)
	{	v = new Vec3();
		for (j = 0 ; j < polyFaces[i - vertNum].length; ++j)
			v.add(vertices[polyFaces[i - vertNum][j]]);
		v.scale(1.0/polyFaces[i - vertNum].length);
		vertices[i] = v;
	}
    
    return vertices;
}

//given a set of faces and a set of vertices,
//this function computes centered faces to form a triangular mesh
//presumably equivalent to subdivide face command in the mesh editor
TriangleMesh triangulateFaces(Vec3[] vertices, int[][] polyFaces, int vertNum)
{	vertices = completeVertices(vertices, polyFaces, vertNum);
    
    faces = new int[polyFaces.length * polyFaces[0].length][3];
	
	f = 0;
	for (i = 0 ; i < polyFaces.length ; ++i)
	{	for (j = 0; j < polyFaces[i].length ; ++j)
		{	if (j < polyFaces[i].length-1)
			{	faces[f][0] = polyFaces[i][j];
				faces[f][1] = polyFaces[i][j+1];
				faces[f][2] = vertNum + i;
			}
			else
			{	faces[f][0] = polyFaces[i][j];
				faces[f][1] = polyFaces[i][0];
				faces[f][2] = vertNum + i;
			}
			++f;
		}
	}
    mesh = new TriangleMesh(vertices, faces);
	return mesh;
}


scene = window.getScene();

//setup the list of polyhedra
polyList = new BList(new String [] {
	translations.get("Tetrahedron"),
	translations.get("Hexahedron"),
	translations.get("Octahedron"),
	translations.get("Dodecahedron"),
	translations.get("Icosahedron")
});
polyList.setPreferredVisibleRows(5);
polyList.setSelected(0, true);

//face centered checkbox
centeredCheckbox = new BCheckBox(translations.get("centeredFaces"), false);

//radius value field
radiusValueField = new ValueField(1.0, ValueField.NONNEGATIVE);

//smoothing method
smoothList = new BList(new String [] {
	translations.get("noSmoothing"),
	translations.get("smoothShading"),
	translations.get("interpolating"),
	translations.get("approximating")
});
smoothList.setPreferredVisibleRows(4);
smoothList.setSelected(0, true);

//vertices smoothness value field
vertSmoothnessValueField = new ValueField(1.0, ValueField.NONNEGATIVE);

//edges smoothness value field
edgesSmoothnessValueField = new ValueField(1.0, ValueField.NONNEGATIVE);

// get list of scene textures
numTex=scene.getNumTextures();
textureList=new BList();
textureList.setPreferredVisibleRows(3 < numTex ? 3 : numTex);
for (i = 0 ; i < numTex ; i++)
{
   iTex=scene.getTexture(i);
   name=iTex.getName();
   textureList.add(name);
}
textureList.setSelected(0, true);

// get list of materials
numMat=scene.getNumMaterials();
materialList=new BList();
materialList.setPreferredVisibleRows(3 < numMat + 1 ? 3 : numMat + 1);
materialList.add("none");
for (i = 0 ; i < numMat ; i++)
{
   iMat=scene.getMaterial(i);
   name=iMat.getName();
   materialList.add(name);
}
materialList.setSelected(0, true);


dlg = new ComponentsDialog(window, translations.get("selectPolyhedron"),
new Widget [] { UIUtilities.createScrollingList(polyList), centeredCheckbox, radiusValueField, UIUtilities.createScrollingList(smoothList), vertSmoothnessValueField, edgesSmoothnessValueField, UIUtilities.createScrollingList(textureList), UIUtilities.createScrollingList(materialList)},
new String [] { translations.get("polyhedron"), translations.get("faceCenteredMesh"), translations.get("radius"), translations.get("smoothingMethod"), translations.get("verticesSmoothness"), translations.get("edgesSmoothness"), translations.get("texture"), translations.get("material") } );

if (!dlg.clickedOk()) return;

centered = centeredCheckbox.getState();

switch (polyList.getSelectedIndex())
{	case 0 : //tetrahedra
		vertices = new Vec3[4]; // 4 vertices + 4 faces
		vertices[0] = new Vec3(0, 0, 1);
		vertices[1] = new Vec3(2*Math.sqrt(2)/3, 0, -1.0/3.0);
		vertices[2] = new Vec3(-Math.sqrt(2)/3, Math.sqrt(6)/3, -1.0/3.0);
		vertices[3] = new Vec3(-Math.sqrt(2)/3, -Math.sqrt(6)/3, -1.0/3.0);
		int[][] faces = {{ 0, 1, 2 },  { 0, 2, 3 }, { 0, 3, 1 }, { 1, 3, 2 }};
        if (centered)
            mesh = triangulateFaces(vertices, faces, 4);
		else
            mesh = new TriangleMesh(vertices, faces);
		name = translations.get("tetrahedron") + (centered ? " FC" : "");
		break;
        
	case 1 : //hexahedron
		vertices = new Vec3[8]; // 8 vertices + 6 faces
		vertices[0] = new Vec3(-1, -1, -1);
		vertices[1] = new Vec3(1, -1, -1);
		vertices[2] = new Vec3(1, 1, -1);
		vertices[3] = new Vec3(-1, 1, -1);
		vertices[4] = new Vec3(-1, -1, 1);
		vertices[5] = new Vec3(1, -1, 1);
		vertices[6] = new Vec3(1, 1, 1);
		vertices[7] = new Vec3(-1, 1, 1);
		for (i = 0 ; i < 8 ; ++i)
			vertices[i].scale(1.0/Math.sqrt(3));
		
        //polygon faces when different from triangular faces
		int[][] hexaFaces = {{ 0, 3, 2, 1 },  { 0, 1, 5, 4 }, { 0, 4, 7, 3 },
            { 6, 5, 1, 2 }, { 6, 2, 3, 7 }, { 6, 7, 4, 5 } };
        
        //triangular faces
        int[][] faces = {{ 0, 3, 2}, { 0, 2, 1}, { 0, 1, 5}, { 0, 5, 4}, { 0, 4, 7}, {0, 7, 3},
            { 6, 5, 1}, { 6, 1, 2}, { 6, 2, 3}, { 6, 3, 7}, { 6, 7, 4}, {6, 4, 5}};
		if (centered)
            mesh = triangulateFaces(vertices, hexaFaces, 8);
		else 
            mesh = new TriangleMesh(vertices, faces);
		name = translations.get("hexahedron") + (centered ? " FC" : "");
		break;
        
    case 2 : //octahedron
		vertices = new Vec3[6]; // 6 vertices + 8 faces
		vertices[0] = new Vec3(1, 0, 0);
		vertices[1] = new Vec3(-1, 0, 0);
		vertices[2] = new Vec3(0, 1, 0);
		vertices[3] = new Vec3(0, -1, 0);
		vertices[4] = new Vec3(0, 0, 1);
		vertices[5] = new Vec3(0, 0, -1);
		
		int[][] faces = {
			{ 4, 0, 2 }, { 4, 2, 1 }, { 4, 1, 3 }, { 4, 3, 0 }, 
            { 5, 2, 0 }, { 5, 1, 2 }, { 5, 3, 1 }, { 5, 0, 3 }
        };
		
		 if (centered)
            mesh = triangulateFaces(vertices, faces, 6);
		else
            mesh = new TriangleMesh(vertices, faces);
		
		name = translations.get("octahedron") + (centered ? " FC" : "");
		break;
	
    case 3 : //dodecahedron
		vertices = new Vec3[20]; // 20 vertices + 12 faces
        a = 1/Math.sqrt(3);
        b = Math.sqrt( (3.0 - Math.sqrt(5)) /6.0);
        c = Math.sqrt( (3.0 + Math.sqrt(5)) /6.0);
		vertices[0] = new Vec3(a, a, a);
		vertices[1] = new Vec3(a, a, -a);
		vertices[2] = new Vec3(a, -a, a);
		vertices[3] = new Vec3(a, -a, -a);
		vertices[4] = new Vec3(-a, a, a);
		vertices[5] = new Vec3(-a, a, -a);
		vertices[6] = new Vec3(-a, -a, a);
		vertices[7] = new Vec3(-a, -a, -a);
		vertices[8] = new Vec3(b, c, 0);
		vertices[9] = new Vec3(-b, c, 0);
		vertices[10] = new Vec3(b, -c, 0);
		vertices[11] = new Vec3(-b, -c, 0);
		vertices[12] = new Vec3(c, 0, b);
		vertices[13] = new Vec3(c, 0, -b);
		vertices[14] = new Vec3(-c, 0, b);
		vertices[15] = new Vec3(-c, 0, -b);
		vertices[16] = new Vec3(0, b, c);
		vertices[17] = new Vec3(0, -b, c);
		vertices[18] = new Vec3(0, b, -c);
		vertices[19] = new Vec3(0, -b, -c);
		
        int[][] faces = { //*quite* dull
			{ 0, 8, 9 }, { 0, 12, 13 }, { 0, 16, 17 }, { 8, 1, 18 }, 
            { 12, 2, 10 }, { 16, 4, 14 }, { 9, 5, 15 }, { 6, 11, 10 },
            { 3, 19, 18 }, { 7, 15, 5 }, { 7, 11, 6 }, { 7, 19, 3 },
            { 0, 9, 4 }, { 0, 13, 1 }, { 0, 17, 2 }, { 8, 18, 5 }, 
            { 12, 10, 3 }, { 16, 14, 6 }, { 9, 15, 14 }, { 6, 10, 2 },
            { 3, 18, 1 }, { 7, 5, 18 }, { 7, 6, 14 }, { 7, 3, 10 },
            { 0, 4, 16 }, { 0, 1, 8 }, { 0, 2, 12 }, { 8, 5, 9 }, 
            { 12, 3, 13 }, { 16, 6, 17 }, { 9, 14, 4 }, { 6, 2, 17 },
            { 3, 1, 13 }, { 7, 18, 19 }, { 7, 14, 15 }, { 7, 10, 11 }
        };
		
        int[][] dodeFaces = {
            { 0, 8, 9, 4, 16}, { 0, 16, 17, 2, 12}, { 12, 2, 10, 3, 13},
            { 9, 5, 15, 14, 4}, { 3, 19, 18, 1, 13}, { 7, 11, 6, 14, 15},
            { 0, 12, 13, 1, 8}, { 8, 1, 18, 5, 9}, { 16, 4, 14, 6, 17},
            { 6, 11, 10, 2, 17}, { 7, 15, 5, 18, 19}, { 7, 19, 3, 10, 11}
        };
        
		 if (centered)
            mesh = triangulateFaces(vertices, dodeFaces, 20);
		else
            mesh = new TriangleMesh(vertices, faces);
		
		name = translations.get("dodecahedron") + (centered ? " FC" : "");
		break;
        
   case 4 : //icosahedron
		vertices = new Vec3[12]; // 12 vertices + 20 faces
        t = ( 1.0 + Math.sqrt(5) )/2.0;
        vertices[0] = new Vec3(t, 1, 0);
		vertices[1] = new Vec3(-t, 1, -0);
		vertices[2] = new Vec3(t, -1, 0);
		vertices[3] = new Vec3(-t, -1, 0);
		vertices[4] = new Vec3(1, 0, t);
		vertices[5] = new Vec3(1, 0, -t);
		vertices[6] = new Vec3(-1, 0, t);
		vertices[7] = new Vec3(-1, 0, -t);
		vertices[8] = new Vec3(0, t, 1);
		vertices[9] = new Vec3(0, -t, 1);
		vertices[10] = new Vec3(0, t, -1);
		vertices[11] = new Vec3(0, -t, -1);
		for (i = 0 ; i < 12 ; ++i)
			vertices[i].scale( 1.0 / Math.sqrt( 1.0 + t*t) );
        
        int[][] faces = {
			{ 0, 8, 4 }, { 0, 5, 10 }, { 2, 4, 9 }, { 2, 11, 5 }, 
            { 1, 6, 8 }, { 1, 10, 7 }, { 3, 9, 6 }, { 3, 7, 11 },
            { 0, 10, 8 }, { 1, 8, 10 }, { 2, 9, 11 }, { 3, 11, 9 },
            { 4, 2, 0 }, { 5, 0, 2 }, { 6, 1, 3 }, { 7, 3, 1 }, 
            { 8, 6, 4 }, { 9, 4, 6 }, { 10, 5, 7 }, { 11, 7, 5 }
        };
		
        
		if (centered)
            mesh = triangulateFaces(vertices, faces, 12);
		else
            mesh = new TriangleMesh(vertices, faces);
		
		name = translations.get("icosahedron") + (centered ? " FC" : "");
		break;
    default :
        return;
}

//set vertices smoothness and scale mesh in the process
meshVertices = mesh.getVertices();
radius = radiusValueField.getValue();
for ( i = 0 ; i < meshVertices.length ; ++i)
{	meshVertices[i].smoothness = (float) vertSmoothnessValueField.getValue();
	meshVertices[i].r.scale(radius);
}

//set edges smoothness
meshEdges = mesh.getEdges();
for ( i = 0 ; i < meshEdges.length ; ++i)
	meshEdges[i].smoothness = (float) edgesSmoothnessValueField.getValue();

//set mesh smoothing method
mesh.setSmoothingMethod(smoothList.getSelectedIndex());

//set texture
tex = scene.getTexture(textureList.getSelectedIndex());
mesh.setTexture(tex, tex.getDefaultMapping(mesh));

//set material
matIndex = materialList.getSelectedIndex();
if ( matIndex > 0 )
{	mat = scene.getMaterial(matIndex-1);
	mesh.setMaterial(mat, mat.getDefaultMapping(mesh));
}

//we're done
window.addObject(mesh, new CoordinateSystem(), name, null);

 
