/* BBRenderingStyle.m				 
 *
 * This object knows how the rendering quality should be. It will produce the
 * necessary RenderMan code too.
 *
 * For interface-info see the header file. The comments in this file mostly
 * cover only the real implementation details.
 *
 * Written by: 		Thomas Engel
 * Created:    		08.03.1994 (Copyleft)
 * Last modified: 	30.05.1994
 */

#import "BBRenderingStyle.h"

@implementation BBRenderingStyle

- init
{
	N3DShader * aShader;
	
	self = [super init];
	if( !self ) return self;

	// OK. We really are an object...here we go with our init.
	// We should ensure that there are at least some useful values preset.

	aShader = [N3DShader new];
	[aShader setShader:"matte"];

	[self setSurfaceType:N3D_SmoothSolids];
	[self setGeometryType:BB_RenderedShape];
	[self setShader:aShader];
	[self setShadingQuality:BB_LowQuality];
	[self setGeometryQuality:BB_LowQuality];

	return self;	
}	

- applySettingsTo:aShape
{
	// By default everything is visible and we won't draw any boxes.
	// The rest will come as needed.
	
	int	i;
	id	aList;
	
	[aShape setVisible:YES];
	[aShape setDrawAsBox:NO];
	aList = [self subshapesOf:aShape];
	for( i=0; i<[aList count]; i++ )
		[[[aList objectAt:i] setDrawAsBox:NO] setVisible:YES];

	// Now lets apply the settings.
	
	[(N3DShape *)aShape setShader:shader];
	
	if( surfaceType == N3D_SmoothSolids )
		[aShape setSurfaceType:N3D_SmoothSolids andDescendants:YES];

	else if( surfaceType == N3D_FacetedSolids )
		[aShape setSurfaceType:N3D_FacetedSolids andDescendants:YES];

	else if( surfaceType == N3D_ShadedWireFrame )
		[aShape setSurfaceType:N3D_ShadedWireFrame andDescendants:YES];

	else if( surfaceType == N3D_WireFrame )
		[aShape setSurfaceType:N3D_WireFrame andDescendants:YES];

	else if( surfaceType == N3D_PointCloud )
		[aShape setSurfaceType:N3D_PointCloud andDescendants:YES];
 	else
		[aShape setSurfaceType:N3D_ShadedWireFrame andDescendants:YES];

	// And new we'll check the geometry type.
	
	if( geometryType == BB_BoundedElements )
	{
		for( i=0; i<[aList count]; i++ )
			[[aList objectAt:i] setDrawAsBox:YES];
	}
	else if( geometryType == BB_BoundedRegion )
	{
		[aShape setDrawAsBox:YES];
		for( i=0; i<[aList count]; i++ )
			[[aList objectAt:i] setVisible:NO];
	}
	
	return self;
}

- executeRiCommands
{
	RiShadingRate( shadingRate );
	RiGeometricApproximation( RI_TESSELATION, RI_PARAMETRIC, 
							  parameticRate, RI_NULL );
	return self;
}

- setSurfaceType:(N3DSurfaceType)theSurface
{
	surfaceType = theSurface;
	return self;
}

- (N3DSurfaceType)surfaceType
{
	return surfaceType;
}

- setGeometryType:(BBGeometryType)theGeometry
{
	geometryType = theGeometry;
	return self;
}

- (BBGeometryType)geometryType
{
	return geometryType;
}

- setShader:aShader
{
	shader = aShader;
	return self;
}

- shader
{
	return shader;
}

- setShadingQuality:(BBQualityType)aQuality
{
	shadingQuality = aQuality;
	
	if( shadingQuality == BB_ExcellentQuality )
		shadingRate = 1;

	else if( shadingQuality == BB_GoodQuality )
		shadingRate = 4;

	else if( shadingQuality == BB_AverageQuality )
		shadingRate = 8;

	else if( shadingQuality == BB_LowQuality )
		shadingRate = 16;

	else
		shadingRate = 32;
		
	return self;
}

- (BBQualityType)shadingQuality
{
	return shadingQuality;
}

- setGeometryQuality:(BBQualityType)aQuality
{
	geometryQuality = aQuality;

	if( geometryQuality == BB_ExcellentQuality )
	{
		parameticRate[0] = 20;
		parameticRate[1] = 20;
	}
	else if( geometryQuality == BB_GoodQuality )
	{
		parameticRate[0] = 14;
		parameticRate[1] = 14;
	}
	else if( geometryQuality == BB_AverageQuality )
	{
		parameticRate[0] = 8;
		parameticRate[1] = 8;
	}
	else if( geometryQuality == BB_LowQuality )
	{
		parameticRate[0] = 4;
		parameticRate[1] = 4;
	}
	else
	{
		parameticRate[0] = 1;
		parameticRate[1] = 1;
	}
	return self;
}

- (BBQualityType)geometryQuality
{
	return geometryQuality;
}

- subshapesOf:aShape
{
	// Well not really perfect but it should work here. We only get the
	// first level descentants.
	
	id	newShape;
	id	aList;
	
	aList = [List new];
	newShape = [aShape descendant];
	
	while( newShape )
	{
		[aList addObject:newShape];
		newShape = [newShape nextPeer];
	}
	return aList;
}

@end

/*
 * History: 27.03.94 The real code did find its way.
 *
 *			08.03.94 First try.
 *
 *
 * Bugs: What ?!
 */