

#ifndef __TskmdViewer_h__
#include "TskmdViewer.h"
#endif

#include <string.h>

#include "vec3.h"
#include "skelmodel.h"
#include <XError.h>

TskmdViewer::TskmdViewer( XGView *parent, XGArgStream &s ):
	XGOpenGLView( parent, s )
{
	shadeMode = shadeSmooth;
	normalsShown = false;
	twosided = false;
	
	pos = 0;
	uv = 0;
	tri = 0;
	vcount = 0;
	tcount = 0;
	
	collision_pos = 0;
	collision_norm = 0;
	collision_indices = 0;
	collision_vertex_count = 0;
	collision_index_count = 0;
	
	shadow_cylinders = 0;
	shadow_cylinder_count = 0;
	
	modelRadius = -1.0f;
	collisionRadius = -1.0f;
	collisionArrayRadius = -1.0f;
	hilightRadius = -1.0f;
	clickRadius = -1.0f;
	shadowArrayRadius = -1.0f;
	
	xRot = 10.0f;
	yRot = 0.0f;
}


TskmdViewer::~TskmdViewer()
{
	free_model();
}


void TskmdViewer::DoDrawView( XRect )
{
	int i, j;
	
	static const GLfloat white[] = { 1.0, 1.0, 1.0, 1.0 };
	static const GLfloat collision_blue[] = { 0.0, 0.0, 1.0, 0.2 };
	static const GLfloat selection_yellow[] = { 1.0, 1.0, 0.0, 0.5 };
	static const GLfloat selection_green[] = { 0.0, 1.0, 0.0, 0.3 };
	static const GLfloat click_red[] = { 1.0, 0.0, 0.0, 0.2 };
			
	XGOpenGLDraw draw( this );
	
	Color back = draw.ColorFromPalette( KXGColorBtnFace );
	glClearColor( GetRValue(back) / 255.0f, GetGValue(back) / 255.0f, GetBValue(back) / 255.0f, 1.0f );
	glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
	
	XRect bounds = GetContentRect();
	
	float totalRadius = 0.0f, totalUpperBound = 0.0f, totalLowerBound = 0.0f;
	if (modelRadius > 0.0f)
	{
		if (modelRadius > totalRadius) totalRadius = modelRadius;
		if (modelUpperBound > totalUpperBound) totalUpperBound = modelUpperBound;
		if (modelLowerBound < totalLowerBound) totalLowerBound = modelLowerBound;
	}
	if (hilightRadius > 0.0f)
	{
		if (hilightRadius * 1.1 > totalRadius) totalRadius = hilightRadius * 1.1;
		if (hilightUpperBound > totalUpperBound) totalUpperBound = hilightUpperBound;
		if (hilightLowerBound < totalLowerBound) totalLowerBound = hilightLowerBound;
	}
	if (clickRadius > 0.0f)
	{
		if (clickRadius * 1.1 > totalRadius) totalRadius = clickRadius * 1.1;
		if (clickUpperBound > totalUpperBound) totalUpperBound = clickUpperBound;
		if (clickLowerBound < totalLowerBound) totalLowerBound = clickLowerBound;
	}
	if (collisionArrayRadius > 0.0f)
	{
		if (collisionArrayRadius * 1.1 > totalRadius) totalRadius = collisionArrayRadius * 1.1;
		if (collisionArrayUpperBound > totalUpperBound) totalUpperBound = collisionArrayUpperBound;
		if (collisionArrayLowerBound < totalLowerBound) totalLowerBound = collisionArrayLowerBound;
	}
	if (collisionRadius > 0.0f)
	{
		if (collisionRadius > totalRadius) totalRadius = collisionRadius;
		if (collisionUpperBound > totalUpperBound) totalUpperBound = collisionUpperBound;
		if (collisionLowerBound < totalLowerBound) totalLowerBound = collisionLowerBound;
	}
	if (shadowArrayRadius > 0.0f)
	{
		if (shadowArrayRadius > totalRadius) totalRadius = shadowArrayRadius;
		if (shadowArrayUpperBound > totalUpperBound) totalUpperBound = shadowArrayUpperBound;
		if (shadowArrayLowerBound < totalLowerBound) totalLowerBound = shadowArrayLowerBound;
	}
	
	
	glMatrixMode( GL_PROJECTION );
	glLoadIdentity();
	float maxheight = 0.5f * (totalUpperBound - totalLowerBound);
	maxheight = sqrt( maxheight * maxheight + totalRadius * totalRadius );
	float maxwidth = totalRadius;
	float height, width;
	
	width = maxwidth;
	height = width * (float)(bounds.bottom - bounds.top) / (float)(bounds.right - bounds.left);
	if (height < maxheight) {
		height = maxheight;
		width = height * (float)(bounds.right - bounds.left) / (float)(bounds.bottom - bounds.top);
	}
	glOrtho( -width, width, -height, height, -maxheight, maxheight );
	
	glMatrixMode( GL_MODELVIEW );
	glLoadIdentity();
	GLfloat light_position[] = { 0.5, 1.0, 0.5, 0.0 };
	glLightfv( GL_LIGHT0, GL_POSITION, light_position );
	glRotatef(xRot, 1.0, 0.0, 0.0);
	glRotatef(yRot, 0.0, 1.0, 0.0);
	glTranslatef( 0.0f, -0.5f * (totalUpperBound + totalLowerBound), 0.0f );
	//glScalef( -1.0f, 1.0f, 1.0f );
	glRotatef(-90.0, 1.0, 0.0, 0.0);
	if (twosided) {
		glDisable( GL_CULL_FACE );
	} else {
		glEnable( GL_CULL_FACE );
		glCullFace( GL_FRONT );
	}
	
	if (pos && uv && tri && vcount >= 3 && tcount >= 1) {
		if (shadeMode == shadeWire) {
			glDisable( GL_LIGHTING );
			if (GetRValue(back) + GetGValue(back) + GetBValue(back) < 128*3) {
				glColor3f( 1.0f, 1.0f, 1.0f );
			} else {
				glColor3f( 0.0f, 0.0f, 0.0f );
			}
			glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
			glBegin( GL_TRIANGLES );
			for (i = 0; i < tcount; ++i) {
				for (j = 0; j < 3; ++j) {
					glVertex3fv( (const float *)(pos + tri[i][j]) );
				}
			}
			glEnd();
		} else {
			glEnable( GL_NORMALIZE );
			glEnable( GL_LIGHTING );
			glLightModeli( GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE );
			glEnable( GL_LIGHT0 );
			glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, white );
			glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
			
			if (shadeMode == shadeFlat) {
				glShadeModel( GL_FLAT );
				glBegin( GL_TRIANGLES );
				for (i = 0; i < tcount; ++i) {
					glNormal3fv( cross( pos[tri[i][2]] - pos[tri[i][0]], pos[tri[i][1]] - pos[tri[i][0]] ) );
					for (j = 0; j < 3; ++j) {
						glVertex3fv( (const float *)(pos + tri[i][j]) );
					}
				}
				glEnd();
			} else {
				glShadeModel( GL_SMOOTH );
				glBegin( GL_TRIANGLES );
				for (i = 0; i < tcount; ++i) {
					for (j = 0; j < 3; ++j) {
						glNormal3fv( (const float *)(norm + tri[i][j]) );
						glVertex3fv( (const float *)(pos + tri[i][j]) );
					}
				}
				glEnd();
			}
		}
		
		if (normalsShown) {
			glDisable( GL_LIGHTING );
			glColor3f( 1, 0, 0 );
			float scale = 10.0 * 2.0 * width / (float)(bounds.right - bounds.left);
			glBegin( GL_LINES );
			for (i = 0; i < vcount; ++i) {
				glVertex3fv( pos[i] );
				float l = dot(norm[i],norm[i]);
				if (l > 0.0f)
				{
					glVertex3fv( pos[i] + (scale / sqrtf(l)) * norm[i] );
				}
				else
				{
					glVertex3fv( pos[i] );
				}
			}
			glEnd();
		}
	}
	
	glDepthMask( GL_FALSE );
	glEnable( GL_LIGHTING );
	glLightModeli( GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE );
	glEnable( GL_LIGHT0 );
	glShadeModel( GL_SMOOTH );
	glEnable( GL_BLEND );
	glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
	glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
	
	if (collision_pos && collision_norm && collision_indices && collision_vertex_count > 0 && collision_index_count > 0)
	{
		glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, collision_blue );
		glEnable( GL_CULL_FACE );
		glCullFace( GL_BACK );
		glBegin( GL_TRIANGLES );
		for (i = 0; i < collision_index_count; ++i)
		{
			glNormal3fv( (const float *)(collision_norm + collision_indices[i]) );
			glVertex3fv( (const float *)(collision_pos + collision_indices[i]) );
		}
		glEnd();
	}
	
	if (collisionRadius > 0.0f)
	{
		glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, collision_blue );
		draw_cylinder( vec3(0,0,0), vec3(0,0,1), collisionRadius, collisionLowerBound, collisionUpperBound, 20 );
	}
	
	if (clickRadius > 0.0f)
	{
		glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, click_red );
		draw_cylinder( vec3(0,0,0), vec3(0,0,1), clickRadius, clickLowerBound, clickUpperBound, 20 );
	}
	
	if (shadow_cylinders && shadow_cylinder_count > 0)
	{
		for (i = 0; i < shadow_cylinder_count; ++i)
		{
			glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, shadow_cylinders[i].rgba );
			draw_cylinder( shadow_cylinders[i].base, shadow_cylinders[i].axis,
							shadow_cylinders[i].r, shadow_cylinders[i].h0, shadow_cylinders[i].h1,
							shadow_cylinders[i].segments );
		}
	}
	
	if (hilightRadius > 0.0f)
	{
		glDisable( GL_CULL_FACE );
		glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, selection_yellow );
		glBegin( GL_TRIANGLE_STRIP );
		glNormal3f( 0.0f, 0.0f, 1.0f );
		for (i = 0; i < 42; ++i)
		{
			float r = (i & 1) ? 1.1f : 0.9f;
			r *= hilightRadius;
			float t = (i >> 1) * 2.0 * 3.14159265 / 20;
			glVertex3f( sin(t) * r, cos(t) * r, hilightLowerBound );
		}
		glEnd();
		
		float bar_width = hilightRadius * 0.1;
		float bar_pos = -30.0f * 3.14159265/180.0;
		float bar_x = cos(bar_pos) * hilightRadius;
		float bar_y = sin(bar_pos) * hilightRadius;
		glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, selection_green );
		draw_cylinder( vec3(bar_x, bar_y, 0), vec3(0,0,1), bar_width, hilightLowerBound, hilightUpperBound, 8 );
	}
	
	glDisable( GL_BLEND );
	glDepthMask( GL_TRUE );
	
	glFinish();
	
	this->ShowBackBuffer();
}


void TskmdViewer::draw_cylinder( vec3 base, vec3 axis, float r, float h0, float h1, int segments )
{
	int i;
	
	vec3 side1, side2;
	side1 = vec3( 1.0f, 1.0f, 1.0f );
	int longest = 0;
	for (i = 1; i < 3; ++i)
	{
		if (fabs(axis[i]) > fabs(axis[longest])) longest = i;
	}
	side1[longest] = 0.0f;
	side2 = normalized( cross( axis, side1 ) );
	side1 = -normalized( cross( axis, side2 ) );
	
	glEnable( GL_CULL_FACE );
	glCullFace( GL_BACK );
	
	glBegin( GL_TRIANGLE_STRIP );
	for (i = 0; i < 2 * (segments+1); ++i)
	{
		float t = i * 3.14159265 / segments;
		float x = cos(t);
		float y = sin(t);
		glNormal3fv( x * side1 + y * side2 );
		glVertex3fv( base + x * r * side1 + y * r * side2 + ((i & 1) ? h0 : h1) * axis );
	}
	glEnd();
	
	glNormal3fv( axis );
	glBegin( GL_TRIANGLE_FAN );
	glVertex3fv( base + h1 * axis );
	for (i = 0; i <= segments; ++i)
	{
		float t = i * 2.0f * 3.14159265 / segments;
		float x = cos(t);
		float y = sin(t);
		glVertex3fv( base + x * r * side1 + y * r * side2 + h1 * axis );
	}
	glEnd();
	
	glNormal3fv( -axis );
	glBegin( GL_TRIANGLE_FAN );
	glVertex3fv( base + h0 * axis );
	for (i = 0; i <= segments; ++i)
	{
		float t = (0.5 - i) * 2.0f * 3.14159265 / segments;
		float x = cos(t);
		float y = sin(t);
		glVertex3fv( base + x * r * side1 + y * r * side2 + h0 * axis );
	}
	glEnd();
}


void TskmdViewer::SetData( const float pos[][4], const float norm[][4], const float uv[][2], int vcount, const unsigned short tri[][3], int tcount )
{
	int i, j;
	
	free_model();
	
	if (!pos || !uv || !tri || vcount < 3 || tcount < 1) {
		//DoDrawView( GetContentRect() );
		return;
	}
	
	for (i = 0; i < tcount; ++i) {
		for (j = 0; j < 3; ++j) {
			if (tri[i][j] < 0 || tri[i][j] > vcount) {
				//DoDrawView( GetContentRect() );
				return;
			}
		}
	}
	
	this->pos = new vec3[vcount];
	this->norm = new vec3[vcount];
	this->uv = new float[vcount][2];
	this->tri = new unsigned short[tcount][3];
	
	if (!this->pos || !this->uv || !this->tri) return;
	
	modelRadius = 0.0f;
	modelLowerBound = modelUpperBound = pos[0][2];
	for (i = 0; i < vcount; ++i) {
		this->pos[i].x = pos[i][0];
		this->pos[i].y = pos[i][1];
		this->pos[i].z = pos[i][2];
		float r = pos[i][0] * pos[i][0] + pos[i][1] * pos[i][1];
		if (r > modelRadius) modelRadius = r;
		if (pos[i][2] < modelLowerBound) {
			modelLowerBound = pos[i][2];
		} else if (pos[i][2] > modelUpperBound) {
			modelUpperBound = pos[i][2];
		}
		
		this->norm[i].x = -norm[i][0];
		this->norm[i].y = -norm[i][1];
		this->norm[i].z = -norm[i][2];
		
		this->uv[i][0] = uv[i][0];
		this->uv[i][1] = uv[i][1];
	}
	modelRadius = sqrt(modelRadius);
	
	memcpy( this->tri, tri, tcount * 6 );
	
	this->vcount = vcount;
	this->tcount = tcount;
}


void TskmdViewer::SetShading( int shadeMode )
{
	if (shadeMode < 0 || shadeMode > 3) return;
	if (shadeMode == this->shadeMode) return;
	this->shadeMode = shadeMode;
	//DoDrawView( GetContentRect() );
}


void TskmdViewer::ShowNormals( bool show )
{
	if (show == normalsShown) return;
	normalsShown = show;
	//DoDrawView( GetContentRect() );
}


void TskmdViewer::SetTwoSided( bool twosided )
{
	if (twosided == this->twosided) return;
	this->twosided = twosided;
	//DoDrawView( GetContentRect() );
}



inline vec3 box_vert( const skmd_complex_collision_box &box, int x, int y, int z, float scale )
{
	vec3 out;
	out.x = x ? box.bounds.maximum_corner.x : box.bounds.minimum_corner.x;
	out.y = y ? box.bounds.maximum_corner.y : box.bounds.minimum_corner.y;
	out.z = z ? box.bounds.maximum_corner.z : box.bounds.minimum_corner.z;
	return out * scale;
}


void TskmdViewer::SetCollision( skmd_complex_collision_box *boxes, int count, world_distance radius, world_distance height0, world_distance height1, float scale )
{
	int i;
	
	delete [] collision_pos;
	delete [] collision_norm;
	delete [] collision_indices;
	collision_pos = 0;
	collision_norm = 0;
	collision_indices = 0;
	collision_vertex_count = 0;
	collision_index_count = 0;
	
	collisionRadius = radius * scale;
	collisionLowerBound = height0 * scale;
	collisionUpperBound = height1 * scale;
	
	collisionArrayRadius = -1.0f;
	collisionArrayLowerBound = 100000000.0f;
	collisionArrayUpperBound = -100000000.0f;
	
	collision_vertex_count = (count * 6 * 4);
	collision_pos = new vec3[collision_vertex_count];
	collision_norm = new vec3[collision_vertex_count];
	collision_index_count = (count * 2*3*6);
	collision_indices = new int[collision_index_count];
	
	int v = 0;
	int t = 0;
	
	for (i = 0; i < count; ++i)
	{
		skmd_complex_collision_box &b = boxes[i];
		vec3 norm;
		
		collision_norm[v+0] = collision_norm[v+1] = collision_norm[v+2] = collision_norm[v+3] = vec3( -1, 0, 0 );
		collision_pos[v+0] = box_vert( b, 0, 0, 0, scale );
		collision_pos[v+1] = box_vert( b, 0, 1, 0, scale );
		collision_pos[v+2] = box_vert( b, 0, 1, 1, scale );
		collision_pos[v+3] = box_vert( b, 0, 0, 1, scale );
		collision_indices[t++] = v+0;
		collision_indices[t++] = v+3;
		collision_indices[t++] = v+2;
		collision_indices[t++] = v+0;
		collision_indices[t++] = v+2;
		collision_indices[t++] = v+1;
		v += 4;
		
		collision_norm[v+0] = collision_norm[v+1] = collision_norm[v+2] = collision_norm[v+3] = vec3( 1, 0, 0 );
		collision_pos[v+0] = box_vert( b, 1, 0, 0, scale );
		collision_pos[v+1] = box_vert( b, 1, 1, 0, scale );
		collision_pos[v+2] = box_vert( b, 1, 1, 1, scale );
		collision_pos[v+3] = box_vert( b, 1, 0, 1, scale );
		collision_indices[t++] = v+0;
		collision_indices[t++] = v+1;
		collision_indices[t++] = v+2;
		collision_indices[t++] = v+0;
		collision_indices[t++] = v+2;
		collision_indices[t++] = v+3;
		v += 4;
		
		collision_norm[v+0] = collision_norm[v+1] = collision_norm[v+2] = collision_norm[v+3] = vec3( 0, -1, 0 );
		collision_pos[v+0] = box_vert( b, 0, 0, 0, scale );
		collision_pos[v+1] = box_vert( b, 1, 0, 0, scale );
		collision_pos[v+2] = box_vert( b, 1, 0, 1, scale );
		collision_pos[v+3] = box_vert( b, 0, 0, 1, scale );
		collision_indices[t++] = v+0;
		collision_indices[t++] = v+1;
		collision_indices[t++] = v+2;
		collision_indices[t++] = v+0;
		collision_indices[t++] = v+2;
		collision_indices[t++] = v+3;
		v += 4;
		
		collision_norm[v+0] = collision_norm[v+1] = collision_norm[v+2] = collision_norm[v+3] = vec3( 0, 1, 0 );
		collision_pos[v+0] = box_vert( b, 0, 1, 0, scale );
		collision_pos[v+1] = box_vert( b, 1, 1, 0, scale );
		collision_pos[v+2] = box_vert( b, 1, 1, 1, scale );
		collision_pos[v+3] = box_vert( b, 0, 1, 1, scale );
		collision_indices[t++] = v+0;
		collision_indices[t++] = v+3;
		collision_indices[t++] = v+2;
		collision_indices[t++] = v+0;
		collision_indices[t++] = v+2;
		collision_indices[t++] = v+1;
		v += 4;
		
		collision_norm[v+0] = collision_norm[v+1] = collision_norm[v+2] = collision_norm[v+3] = vec3( 0, 0, -1 );
		collision_pos[v+0] = box_vert( b, 0, 0, 0, scale );
		collision_pos[v+1] = box_vert( b, 0, 1, 0, scale );
		collision_pos[v+2] = box_vert( b, 1, 1, 0, scale );
		collision_pos[v+3] = box_vert( b, 1, 0, 0, scale );
		collision_indices[t++] = v+0;
		collision_indices[t++] = v+1;
		collision_indices[t++] = v+2;
		collision_indices[t++] = v+0;
		collision_indices[t++] = v+2;
		collision_indices[t++] = v+3;
		v += 4;
		
		collision_norm[v+0] = collision_norm[v+1] = collision_norm[v+2] = collision_norm[v+3] = vec3( 0, 0, 1 );
		collision_pos[v+0] = box_vert( b, 0, 0, 1, scale );
		collision_pos[v+1] = box_vert( b, 0, 1, 1, scale );
		collision_pos[v+2] = box_vert( b, 1, 1, 1, scale );
		collision_pos[v+3] = box_vert( b, 1, 0, 1, scale );
		collision_indices[t++] = v+0;
		collision_indices[t++] = v+3;
		collision_indices[t++] = v+2;
		collision_indices[t++] = v+0;
		collision_indices[t++] = v+2;
		collision_indices[t++] = v+1;
		v += 4;
	}
	
	Assert( v == collision_vertex_count );
	Assert( t == collision_index_count );
	
	for (i = 0; i < v; ++i)
	{
		float r = collision_pos[i].x * collision_pos[i].x + collision_pos[i].y * collision_pos[i].y;
		if (r > collisionArrayRadius) collisionArrayRadius = r;
		r = collision_pos[i].z;
		if (r < collisionArrayLowerBound) collisionArrayLowerBound = r;
		if (r > collisionArrayUpperBound) collisionArrayUpperBound = r;
	}
	collisionArrayRadius = sqrt(collisionRadius);
}


void TskmdViewer::SetClick( world_distance radius, world_distance height0, world_distance height1, float scale )
{
	clickRadius = radius * scale;
	clickLowerBound = height0 * scale;
	clickUpperBound = height1 * scale;
}


void TskmdViewer::SetHilight( world_distance radius, world_distance height0, world_distance height1, float scale )
{
	hilightRadius = radius * scale;
	hilightLowerBound = height0 * scale;
	hilightUpperBound = height1 * scale;
}


void TskmdViewer::SetShadowCylinders( skmdViewerCylinder *cyls, int count )
{
	shadowArrayRadius = -1.0f;
	delete [] shadow_cylinders;
	shadow_cylinders = 0;
	shadow_cylinder_count = 0;
	
	if (!cyls || count <= 0) return;
	
	shadow_cylinders = new skmdViewerCylinder[count];
	memcpy( shadow_cylinders, cyls, count * sizeof(skmdViewerCylinder) );
	shadow_cylinder_count = count;
	
	float r = 0.0f;
	float hi = -100000000.0f;
	float low = -hi;
	for (int i = 0; i < count; ++i)
	{
		shadow_cylinders[i].axis = normalized(shadow_cylinders[i].axis);
		
		vec3 p;
		
		p = shadow_cylinders[i].base + shadow_cylinders[i].h0 * shadow_cylinders[i].axis;
		{
			float t = sqrtf(p.x*p.x + p.y*p.y) + cyls[i].r;
			if (t > r) r = t;
			t = p.z - cyls[i].r;
			if (t < low) low = t;
			t = p.z + cyls[i].r;
			if (t > hi) hi = t;
		}
		
		p = shadow_cylinders[i].base + shadow_cylinders[i].h1 * shadow_cylinders[i].axis;
		{
			float t = sqrtf(p.x*p.x + p.y*p.y) + cyls[i].r;
			if (t > r) r = t;
			t = p.z - cyls[i].r;
			if (t < low) low = t;
			t = p.z + cyls[i].r;
			if (t > hi) hi = t;
		}
	}
	
	shadowArrayRadius = r;
	shadowArrayUpperBound = hi;
	shadowArrayLowerBound = low;
}


void TskmdViewer::free_model()
{
	delete [] pos;
	pos = 0;
	
	delete [] uv;
	uv = 0;
	
	delete [] tri;
	tri = 0;
	
	vcount = 0;
	tcount = 0;
	
	delete [] collision_pos;
	delete [] collision_norm;
	delete [] collision_indices;
	collision_pos = 0;
	collision_norm = 0;
	collision_indices = 0;
	collision_vertex_count = 0;
	collision_index_count = 0;
	
	delete [] shadow_cylinders;
	shadow_cylinders = 0;
	shadow_cylinder_count = 0;
	
	modelRadius = -1.0f;
	collisionRadius = -1.0f;
	collisionArrayRadius = -1.0f;
	hilightRadius = -1.0f;
	clickRadius = -1.0f;
	shadowArrayRadius = -1.0f;
}


bool TskmdViewer::DoMouseDown( XPoint pt, short )
{
	spinAnchor = pt;
	return true;
}


void TskmdViewer::DoMouseMove( XPoint pt, short a )
{
	if (!(a & KCapturedMouse)) return;
	XRect r = GetContentRect();
	
	xRot += (pt.v - spinAnchor.v) * 180.0f / (r.bottom - r.top);
	yRot += (pt.h - spinAnchor.h) * 180.0f / (r.right - r.left);
	//if (yRot > 180.0f) yRot -= 360.0f;
	//if (yRot < -180.0f) yRot += 360.0f;
	if (xRot < -90.0f) xRot = -90.0f;
	if (xRot > 90.0f) xRot = 90.0f;
	DoDrawView( r );
	spinAnchor = pt;
}


float TskmdViewer::GetHeight()
{
	return fabs(modelUpperBound - modelLowerBound);
}

