#import <appkit/appkit.h>
#import "TeapotView.h"
#import "Teapot.h"

//	TeapotView -- by sam streeper 920704
//	borrowing heavily from sources by Bill Bumgarner and Dave Springer.

@implementation TeapotView

- initFrame:(const NXRect *) theRect
{
	// camera position points
	RtPoint fromP = {0,0,-5.0}, toP = {0,0,0};

	// light position points
	RtPoint lFromP = {30,20,-20};
	RtPoint lFromP2 = {-10,10,-10};
	RtPoint lFromP3 = {0,-10,-10};

	// the various 3Dkit object id''s that we will initialize here
	id ambientLight;
	id aLight;

	[super initFrame:theRect];
	[self setEyeAt:fromP toward:toP roll:0.0];
	
	theShader=[[N3DShader alloc] init];
	[theShader setUseColor:YES];
	[self getTeapotColor];
	[(N3DShader *)theShader setShader:"plastic"];

	teapot=[[Teapot alloc] init];
	teapotsBox=[[N3DShape alloc] init];
	[(N3DSha7%d) teapot setShader:theShader];

	[[self worldShape] linkDescendant:teapotsBox];
	[teapotsBox linkDescendant:teapot];

	ambientLight=[[N3DLight alloc] init];
	[ambientLight makeAmbientWithIntensity:0.1];
	[self addLight:ambientLight];
	
	aLight=[[N3DLight alloc] init];
	[aLight makeDistantFrom:lFromP to:toP intensity:0.2];
	[self addLight:aLight];

	aLight=[[N3DLight alloc] init];
	[aLight makeDistantFrom:lFromP2 to:toP intensity:0.9];
	[self addLight:aLight];

	aLight=[[N3DLight alloc] init];
	[aLight makeDistantFrom:lFromP3 to:toP intensity:0.3];
	[self addLight:aLight];

	[self getSurfaceType];

	dx = randBetween(.05, .2);
	dy = randBetween(.05, .2);
	dz = randBetween(.05, .2);
	rotationAxis[0] = 0;
	theta = 0;

	return self;
}

#define PI 3.14159

- oneStep
{
	RtMatrix m;

	rotationAxis[1] = sin(theta);
	rotationAxis[2] = cos(theta);
	theta += (2.0 * PI / 180.0);

	[teapot rotateAngle:5 axis:rotationAxis];
	[teapotsBox translate:dx :dy :dz];

	[teapotsBox getTransformMatrix:m];

// I can use these values directly only because teapot's box isn't rotated
	if (m[3][0] < -1.5) dx = randBetween(.02, .1);
	else if (m[3][0] > 1.5) dx = randBetween(-.02, -.1);
	if (m[3][1] < -1.5) dy = randBetween(.02, .1);
	else if (m[3][1] > 1.5) dy = randBetween(-.02, -.1);
	if (m[3][2] < -2.25) dz = randBetween(.02, .1);
	else if (m[3][2] > 4) dz = randBetween(-.02, -.1);


//	[self render];
	[self display];

	return self;
}

- (BOOL) useBufferedWindow
{
	return YES;
}

- (const char *)windowTitle
{	return "I'm a little teapot...";
}

- inspector:sender
{
    char buf[MAXPATHLEN];
	
    if (!inspectorPanel)
	{
		sprintf(buf,"%s/teapot.nib",[sender moduleDirectory:"Teapot"]);
		[NXApp loadNibFile:buf owner:self withNames:NO];

		[surfaceMatrix selectCellAt:surfaceMatrixSelection :0];
		[colorWell setColor:[theShader color]];
    }
    return inspectorPanel;
}

- setResolutionFrom:sender
{
	[teapot setResolution:[sender floatValue]];
	[resolutionTextField setIntValue:[sender floatValue]];
	return self;
}

- setColorFrom:sender
{
    float r,g,b;
    char str[100];

	[theShader setColor:[sender color]];

    NXConvertColorToRGB([sender color], &r, &g, &b);
    sprintf(str, "%5.3f %5.3f %5.3f", r, g, b );
	NXWriteDefault([NXApp appName], "TeapotColor", str);

	return self;
}

- getTeapotColor
{
	float r = .757, g = .875, b = .897%econst char *ptr;

	ptr = NXGetDefaultValue([NXApp appName], "TeapotColor");
    if (ptr)  sscanf (ptr, "%f %f %f", &r, &g, &b );

	[theShader setColor:NXConvertRGBToColor(r,g,b)];
	return self;
}

- setSurfaceType:sender
{
	char str[100];
	int type, val = [sender selectedRow];

	switch (val)
	{
	case 0:
		type = N3D_WireFrame;			break;
	case 1:
		type = N3D_FacetedSolids;		break;
	case 2:
		type = N3D_SmoothSolids;		break;
	default:
		type = N3D_WireFrame;			break;
	}

	surfaceMatrixSelection = val;

	sprintf(str,"%d", val);
	NXWriteDefault([NXApp appName], "TeapotSurface", str);

	[self setSurfaceTypeForAll:type chooseHider:YES];
	return self;
}

- getSurfaceType
{
	const char *ptr;
	int type, val = 0;

	ptr = NXGetDefaultValue([NXApp appName], "TeapotSurface");
	if (ptr)
	{
		sscanf(ptr,"%d",&val);
		if (val < 0 || val > 2) val = 0;
	}

	surfaceMatrixSelection = val;

	switch (val)
	{
	case 0:
		type = N3D_WireFrame;			break;
	case 1:
		type = N3D_FacetedSolids;		break;
	case 2:
		type = N3D_SmoothSolids;		break;
	default:
		type = N3D_WireFrame;			break;
	}

	[self setSurfaceTypeForAll:type chooseHider:YES];

	return self;
}


@end
