// Copyright (c) 2001 - 2009 Bruce Justin Lindbloom. All Rights Reserved.

var X = 1.0, Y = 1.0, Z = 1.0;

function processForm(theForm)
{
	rgb1 = parseInt(theForm.parRGB1.value);
	rgb2 = parseInt(theForm.parRGB2.value);
	colorSpace = parseInt(theForm.parColorSpace.value);
	
	newInput = generateGraphicsContent(rgb1, rgb2, colorSpace);
	
	LiveApplet = document.getElementById("liveApplet")

	// use LiveGraphics3D public setGraphics3D method to change the INPUT parameter.
	try
	{
		LiveApplet.setGraphics3D(newInput);
	}
	catch(e)
	{ // whoops, that didn't work -- open a new window instead
		var popup=window.open("","lg3d","height=550,width=550");
		popup.document.write("<html><head><title>Gamut Viewer</title></head><body>");
		popup.document.write("<center><applet archive=\"live.jar\" code=\"Live.class\" Height=\"500\" Width=\"500\" >");
		popup.document.write("<param name=\"BGCOLOR\" value=\"808080\" />");
		popup.document.write("<param name=\"MAGNIFICATION\" value=\"1.3\" />");
		popup.document.write("<param name=\"INPUT\" value=\""+newInput+"\"/>");
		popup.document.write("</applet></center>");
		popup.document.write("</body></html>");
		popup.document.close();
	} // end of catch
}

function generateGraphicsContent(rgb1, rgb2, colorSpace)
{
	newContent = "Graphics3D[{";
	newContent += generateAxes(colorSpace);
	if (rgb1 >= 0)
		newContent += generateOneGamut(rgb1, colorSpace, true);
	if (rgb2 >= 0)
		newContent += generateOneGamut(rgb2, colorSpace, false);
	newContent += "}" + generateOptions() + "]";

	return(newContent);
}

function generateOneGamut(rgb, colorSpace, isPrimary)
{
	gamutInfo = "";
	var n = 10;
	var cube = new Array(
       [[0.0, 0.0, 0.0], [0.0, 0.1, 0.0], [0.0, 0.0, 0.1]], // R = 0
       [[0.0, 0.0, 0.0], [0.0, 0.0, 0.1], [0.0, 0.1, 0.0]],
       [[1.0, 0.0, 0.0], [0.0, 0.1, 0.0], [0.0, 0.0, 0.1]], // R = 1
       [[1.0, 0.0, 0.0], [0.0, 0.0, 0.1], [0.0, 0.1, 0.0]],

       [[0.0, 0.0, 0.0], [0.1, 0.0, 0.0], [0.0, 0.0, 0.1]], // G = 0
       [[0.0, 0.0, 0.0], [0.0, 0.0, 0.1], [0.1, 0.0, 0.0]],
       [[0.0, 1.0, 0.0], [0.1, 0.0, 0.0], [0.0, 0.0, 0.1]], // G = 1
       [[0.0, 1.0, 0.0], [0.0, 0.0, 0.1], [0.1, 0.0, 0.0]],

       [[0.0, 0.0, 0.0], [0.1, 0.0, 0.0], [0.0, 0.1, 0.0]], // B = 0
       [[0.0, 0.0, 0.0], [0.0, 0.1, 0.0], [0.1, 0.0, 0.0]],
       [[0.0, 0.0, 1.0], [0.1, 0.0, 0.0], [0.0, 0.1, 0.0]], // B = 1
       [[0.0, 0.0, 1.0], [0.0, 0.1, 0.0], [0.1, 0.0, 0.0]]
	);
	var R0, G0, B0, R1, G1, B1, r, g, b;
	var X0, Y0, Z0, X1, Y1, Z1;
	
  for (face = 0; face < 12; face++)
  {
		for (row = 0; row <= n; row++)
		{
			for (col = 0; col <= n; col++)
			{
				// convert RGB to Lab
				R1 = cube[face][0][0] + col * cube[face][1][0] + row * cube[face][2][0];
				G1 = cube[face][0][1] + col * cube[face][1][1] + row * cube[face][2][1];
				B1 = cube[face][0][2] + col * cube[face][1][2] + row * cube[face][2][2];
				
				RGBtoXYZ(R1, G1, B1, rgb);
				
				// convert XYZ to colorSpace, storing result generically as X1, Y1, Z1
				switch (colorSpace)
				{
				case 0:	// Lab
					{
						var xr = X / 0.96422;
						var yr = Y;
						var zr = Z / 0.82521;
						var fx = (xr > (216/24389)) ? Math.pow(xr, 1.0/3.0) : ((24389 * xr + 432) / 3132);
						var fy = (yr > (216/24389)) ? Math.pow(yr, 1.0/3.0) : ((24389 * yr + 432) / 3132);
						var fz = (zr > (216/24389)) ? Math.pow(zr, 1.0/3.0) : ((24389 * zr + 432) / 3132);
						Z1 = 116 * fy - 16;		// L
						X1 = 500 * (fx - fy);	// a
						Y1 = 200 * (fy - fz);	// b
					}
					break;
				case 1:	// Luv
					{
						var ur = 0.209160052;	// D50
						var vr = 0.488073384;
						var d = X + 15 * Y + 3 * Z;
						var u = (d > 0) ? (4 * X / d) : 0;
						var v = (d > 0) ? (9 * Y / d) : 0;
						var yr = Y;
						var fy = (yr > (216/24389)) ? Math.pow(yr, 1.0/3.0) : ((24389 * yr + 432) / 3132);
						Z1 = 116 * fy - 16;				// L
						X1 = 13 * Z1 * (u - ur);	// u
						Y1 = 13 * Z1 * (v - vr);	// v
					}
					break;
				case 2:	// xyY
					{
						var d = X + Y + Z;
						X1 = (d > 0) ? (X / d) : 0.345669186;	// x
						Y1 = (d > 0) ? (Y / d) : 0.35849618;	// y
						Z1 = Y;
					}
					break;
				case 3:	// XYZ
					{
						X1 = X;
						Y1 = Y;
						Z1 = Z;
					}
					break;
				}
				// output
				if (col != 0)
				{
					if (isPrimary == true)
					{
						r = 0.5 * (R0 + R1);
						g = 0.5 * (G0 + G1);
						b = 0.5 * (B0 + B1);
					}
					else
					{
						r = (R0 + R1 + 2) / 6;
						g = (G0 + G1 + 2) / 6;
						b = (B0 + B1 + 2) / 6;
					}
					gamutInfo += ",{RGBColor[" + r + "," + g + "," + b + "], Line[{{" + X0 + "," + Y0 + "," + Z0 + "},{" + X1 + "," + Y1 + "," + Z1 + "}}]}";
				}
				R0 = R1;
				G0 = G1;
				B0 = B1;
				X0 = X1;
				Y0 = Y1;
				Z0 = Z1;
			}
		}
  }
	return(gamutInfo);
}

function generateAxes(colorSpace)
{
	axisInfo = "{RGBColor[0,0,0],";
	switch (colorSpace)
	{
	case 0:	// Lab
		axisInfo += "Line[{{-100,0,0},{100,0,0}}],";
		axisInfo += "Line[{{0,-100,0},{0,100,0}}],";
		axisInfo += "Line[{{0,0,0},{0,0,100}}],";
		axisInfo += "Text[\"+a\", {105,0,0}],";
		axisInfo += "Text[\"-a\", {-105,0,0}],";
		axisInfo += "Text[\"+b\", {0,105,0}],";
		axisInfo += "Text[\"-b\", {0,-105,0}],";
		axisInfo += "Text[\"L\", {0,0,105}]";
		break;
	case 1:	// Luv
		axisInfo += "Line[{{-100,0,0},{100,0,0}}],";
		axisInfo += "Line[{{0,-100,0},{0,100,0}}],";
		axisInfo += "Line[{{0,0,0},{0,0,100}}],";
		axisInfo += "Text[\"+u\", {105,0,0}],";
		axisInfo += "Text[\"-u\", {-105,0,0}],";
		axisInfo += "Text[\"+v\", {0,105,0}],";
		axisInfo += "Text[\"-v\", {0,-105,0}],";
		axisInfo += "Text[\"L\", {0,0,105}]";
		break;
	case 2:	// xyY
		axisInfo += "Line[{{0,0,0},{1,0,0}}],";
		axisInfo += "Line[{{0,0,0},{0,1,0}}],";
		axisInfo += "Line[{{0.345669,0.358496,0},{0.345669,0.358496,1}}],";
		axisInfo += "Line[{";
		axisInfo += "{0.174112,0.004964,0},";
		axisInfo += "{0.174008,0.004981,0},";
		axisInfo += "{0.173801,0.004915,0},";
		axisInfo += "{0.173560,0.004923,0},";
		axisInfo += "{0.173337,0.004797,0},";
		axisInfo += "{0.173021,0.004775,0},";
		axisInfo += "{0.172577,0.004799,0},";
		axisInfo += "{0.172087,0.004833,0},";
		axisInfo += "{0.171407,0.005102,0},";
		axisInfo += "{0.170301,0.005789,0},";
		axisInfo += "{0.168878,0.006900,0},";
		axisInfo += "{0.166895,0.008556,0},";
		axisInfo += "{0.164412,0.010858,0},";
		axisInfo += "{0.161105,0.013793,0},";
		axisInfo += "{0.156641,0.017705,0},";
		axisInfo += "{0.150985,0.022740,0},";
		axisInfo += "{0.143960,0.029703,0},";
		axisInfo += "{0.135503,0.039879,0},";
		axisInfo += "{0.124118,0.057803,0},";
		axisInfo += "{0.109594,0.086843,0},";
		axisInfo += "{0.091294,0.132702,0},";
		axisInfo += "{0.068706,0.200723,0},";
		axisInfo += "{0.045391,0.294976,0},";
		axisInfo += "{0.023460,0.412703,0},";
		axisInfo += "{0.008168,0.538423,0},";
		axisInfo += "{0.003859,0.654823,0},";
		axisInfo += "{0.013870,0.750186,0},";
		axisInfo += "{0.038852,0.812016,0},";
		axisInfo += "{0.074302,0.833803,0},";
		axisInfo += "{0.114161,0.826207,0},";
		axisInfo += "{0.154722,0.805864,0},";
		axisInfo += "{0.192876,0.781629,0},";
		axisInfo += "{0.229620,0.754329,0},";
		axisInfo += "{0.265775,0.724324,0},";
		axisInfo += "{0.301604,0.692308,0},";
		axisInfo += "{0.337363,0.658848,0},";
		axisInfo += "{0.373102,0.624451,0},";
		axisInfo += "{0.408736,0.589607,0},";
		axisInfo += "{0.444062,0.554714,0},";
		axisInfo += "{0.478775,0.520202,0},";
		axisInfo += "{0.512486,0.486591,0},";
		axisInfo += "{0.544787,0.454434,0},";
		axisInfo += "{0.575151,0.424232,0},";
		axisInfo += "{0.602933,0.396497,0},";
		axisInfo += "{0.627037,0.372491,0},";
		axisInfo += "{0.648233,0.351395,0},";
		axisInfo += "{0.665764,0.334011,0},";
		axisInfo += "{0.680079,0.319747,0},";
		axisInfo += "{0.691504,0.308342,0},";
		axisInfo += "{0.700606,0.299301,0},";
		axisInfo += "{0.707918,0.292027,0},";
		axisInfo += "{0.714032,0.285929,0},";
		axisInfo += "{0.719033,0.280935,0},";
		axisInfo += "{0.723032,0.276948,0},";
		axisInfo += "{0.725992,0.274008,0},";
		axisInfo += "{0.728272,0.271728,0},";
		axisInfo += "{0.729969,0.270031,0},";
		axisInfo += "{0.731089,0.268911,0},";
		axisInfo += "{0.731993,0.268007,0},";
		axisInfo += "{0.732719,0.267281,0},";
		axisInfo += "{0.733417,0.266583,0},";
		axisInfo += "{0.734047,0.265953,0},";
		axisInfo += "{0.734390,0.265610,0},";
		axisInfo += "{0.734592,0.265408,0},";
		axisInfo += "{0.734690,0.265310,0},";
		axisInfo += "{0.174112,0.004964,0}";
		axisInfo += "}],";
		axisInfo += "Text[\"x\", {1.05,0,0}],";
		axisInfo += "Text[\"y\", {0,1.05,0}],";
		axisInfo += "Text[\"Y\", {0.345669,0.358496,1.05}]";
		break;
	case 3:	// XYZ
		axisInfo += "Line[{{0,0,0},{1,0,0}}],";
		axisInfo += "Line[{{0,0,0},{0,1,0}}],";
		axisInfo += "Line[{{0,0,0},{0,0,1}}],";
		axisInfo += "Line[{{0,0,0},{0.96422,1,0.82521}}],";
		axisInfo += "Text[\"X\", {1.05,0,0}],";
		axisInfo += "Text[\"Y\", {0,1.05,0}],";
		axisInfo += "Text[\"Z\", {0,0,1.05}]";
		break;
	}
	axisInfo += "}";
	return(axisInfo);
}

function generateOptions()
{
	return(", Boxed -> False");
}

function RGBtoXYZ(R, G, B, rgb)
{	// global variables X, Y and Z contain the XYZ values of the conversion, adapted to D50 using Bradford
	var r, g, b;	// linear values
	var x, y, z;	// unadapted values
	switch (rgb)
	{
	case 0:	// Adobe RGB (1998)
		{
			r = Math.pow(R, 2.2);
			g = Math.pow(G, 2.2);
			b = Math.pow(B, 2.2);
			x = r * 0.576700  + g * 0.185556  + b * 0.188212;
			y = r * 0.297361  + g * 0.627355  + b * 0.0752847;
			z = r * 0.0270328 + g * 0.0706879 + b * 0.991248;
			// D65 to D50
			X = x *  1.047835 + y * 0.022897 + z * -0.050147;
			Y = x *  0.029556 + y * 0.990481 + z * -0.017056;
			Z = x * -0.009238 + y * 0.015050 + z *  0.752034;
		}
		break;
	case 1:	// Apple RGB
		{
			r = Math.pow(R, 1.8);
			g = Math.pow(G, 1.8);
			b = Math.pow(B, 1.8);
			x = r * 0.449695  + g * 0.316251 + b * 0.184520;
			y = r * 0.244634  + g * 0.672034 + b * 0.0833318;
			z = r * 0.0251829 + g * 0.141184 + b * 0.922602;
			// D65 to D50
			X = x *  1.047835 + y * 0.022897 + z * -0.050147;
			Y = x *  0.029556 + y * 0.990481 + z * -0.017056;
			Z = x * -0.009238 + y * 0.015050 + z *  0.752034;
		}
		break;
	case 2:	// Best RGB
		{
			r = Math.pow(R, 2.2);
			g = Math.pow(G, 2.2);
			b = Math.pow(B, 2.2);
			X = r * 0.632670 + g * 0.204556   + b * 0.126995;
			Y = r * 0.228457 + g * 0.737352   + b * 0.0341908;
			Z = r * 0.000000 + g * 0.00951424 + b * 0.815696;
		}
		break;
	case 3:	// Beta RGB
		{
			r = Math.pow(R, 2.2);
			g = Math.pow(G, 2.2);
			b = Math.pow(B, 2.2);
			X = r * 0.671254 + g * 0.174583 + b * 0.118383;
			Y = r * 0.303273 + g * 0.663786 + b * 0.0329413;
			Z = r * 0.000000 + g * 0.040701 + b * 0.784509;
		}
		break;
	case 4:	// Bruce RGB
		{
			r = Math.pow(R, 2.2);
			g = Math.pow(G, 2.2);
			b = Math.pow(B, 2.2);
			x = r * 0.467384  + g * 0.294454  + b * 0.188629;
			y = r * 0.240995  + g * 0.683554  + b * 0.0754517;
			z = r * 0.0219086 + g * 0.0736135 + b * 0.993447;
			// D65 to D50
			X = x *  1.047835 + y * 0.022897 + z * -0.050147;
			Y = x *  0.029556 + y * 0.990481 + z * -0.017056;
			Z = x * -0.009238 + y * 0.015050 + z *  0.752034;
		}
		break;
	case 5:	// CIE RGB
		{
			r = Math.pow(R, 2.2);
			g = Math.pow(G, 2.2);
			b = Math.pow(B, 2.2);
			x = r * 0.488718 + g * 0.310680  + b * 0.200602;
			y = r * 0.176204 + g * 0.812985  + b * 0.0108109;
			z = r * 0.000000 + g * 0.0102048 + b * 0.989795;
			// E to D50
			X = x *  0.997754 + y * -0.004163 + z * -0.029371;
			Y = x * -0.009768 + y *  1.018316 + z * -0.008549;
			Z = x * -0.007417 + y *  0.013442 + z *  0.819186;
		}
		break;
	case 6:	// ColorMatch RGB
		{
			r = Math.pow(R, 1.8);
			g = Math.pow(G, 1.8);
			b = Math.pow(B, 1.8);
			X = r * 0.509344  + g * 0.320907 + b * 0.133969;
			Y = r * 0.274884  + g * 0.658132 + b * 0.0669845;
			Z = r * 0.0242545 + g * 0.108782 + b * 0.692174;
		}
		break;
	case 7:	// Don RGB 4
		{
			r = Math.pow(R, 2.2);
			g = Math.pow(G, 2.2);
			b = Math.pow(B, 2.2);
			X = r * 0.645771   + g * 0.193351  + b * 0.125098;
			Y = r * 0.278350   + g * 0.687970  + b * 0.0336802;
			Z = r * 0.00371134 + g * 0.0179862 + b * 0.803513;
		}
		break;
	case 8:	// ECI RGB
		{
			r = Math.pow(R, 1.8);
			g = Math.pow(G, 1.8);
			b = Math.pow(B, 1.8);
			X = r * 0.650204 + g * 0.178077  + b * 0.135938;
			Y = r * 0.320250 + g * 0.602071  + b * 0.0776791;
			Z = r * 0.000000 + g * 0.0678390 + b * 0.757371;
		}
		break;
	case 9:	// Ekta Space PS5
		{
			r = Math.pow(R, 2.2);
			g = Math.pow(G, 2.2);
			b = Math.pow(B, 2.2);
			X = r * 0.593891 + g * 0.272980  + b * 0.0973486;
			Y = r * 0.260629 + g * 0.734946  + b * 0.00442493;
			Z = r * 0.000000 + g * 0.0419970 + b * 0.783213;
		}
		break;
	case 10:	// NTSC RGB
		{
			r = Math.pow(R, 2.2);
			g = Math.pow(G, 2.2);
			b = Math.pow(B, 2.2);
			x = r * 0.606734 + g * 0.173564  + b * 0.200112;
			y = r * 0.298839 + g * 0.586811  + b * 0.114350;
			z = r * 0.000000 + g * 0.0661196 + b * 1.11491;
			// C to D50
			X = x *  1.037765 + y * 0.015460 + z * -0.058148;
			Y = x *  0.017182 + y * 1.005438 + z * -0.018868;
			Z = x * -0.011978 + y * 0.020371 + z *  0.691416;
		}
		break;
	case 11:	// PAL/SECAM RGB
		{
			r = Math.pow(R, 2.2);
			g = Math.pow(G, 2.2);
			b = Math.pow(B, 2.2);
			x = r * 0.430587  + g * 0.341545 + b * 0.178336;
			y = r * 0.222021  + g * 0.706645 + b * 0.0713342;
			z = r * 0.0201837 + g * 0.129551 + b * 0.939234;
			// D65 to D50
			X = x *  1.047835 + y * 0.022897 + z * -0.050147;
			Y = x *  0.029556 + y * 0.990481 + z * -0.017056;
			Z = x * -0.009238 + y * 0.015050 + z *  0.752034;
		}
		break;
	case 12:	// ProPhoto RGB
		{
			r = Math.pow(R, 1.8);
			g = Math.pow(G, 1.8);
			b = Math.pow(B, 1.8);
			X = r * 0.797675 + g * 0.135192 + b * 0.0313534;
			Y = r * 0.288040 + g * 0.711874 + b * 0.000086;
			Z = r * 0.000000 + g * 0.000000 + b * 0.825210;
		}
		break;
	case 13:	// SMPTE-C RGB
		{
			r = Math.pow(R, 2.2);
			g = Math.pow(G, 2.2);
			b = Math.pow(B, 2.2);
			x = r * 0.393555  + g * 0.365253 + b * 0.191659;
			y = r * 0.212395  + g * 0.701049 + b * 0.0865558;
			z = r * 0.0187407 + g * 0.111932 + b * 0.958297;
			// D65 to D50
			X = x *  1.047835 + y * 0.022897 + z * -0.050147;
			Y = x *  0.029556 + y * 0.990481 + z * -0.017056;
			Z = x * -0.009238 + y * 0.015050 + z *  0.752034;
		}
		break;
	case 14:	// sRGB
		{
			r = (R <= 0.04045) ? (R / 12.92) : Math.pow((R + 0.055) / 1.055, 2.4);
			g = (G <= 0.04045) ? (G / 12.92) : Math.pow((G + 0.055) / 1.055, 2.4);
			b = (B <= 0.04045) ? (B / 12.92) : Math.pow((B + 0.055) / 1.055, 2.4);
			x = r * 0.412424  + g * 0.357579  + b * 0.180464;
			y = r * 0.212656  + g * 0.715158  + b * 0.0721856;
			z = r * 0.0193324 + g * 0.119193 + b * 0.950444;
			// D65 to D50
			X = x *  1.047835 + y * 0.022897 + z * -0.050147;
			Y = x *  0.029556 + y * 0.990481 + z * -0.017056;
			Z = x * -0.009238 + y * 0.015050 + z *  0.752034;
		}
		break;
	case 15:	// Wide Gamut RGB
		{
			r = Math.pow(R, 2.2);
			g = Math.pow(G, 2.2);
			b = Math.pow(B, 2.2);
			X = r * 0.716105 + g * 0.100930  + b * 0.147186;
			Y = r * 0.258187 + g * 0.724938  + b * 0.0168748;
			Z = r * 0.000000 + g * 0.0517813 + b * 0.773429;
		}
		break;
	}
}

