/* MolShape.m - Copyright 1993  Steve Ludtke */
/* This object does the actual molecule rendering (except for quick mode) */
/* ball and stick mode is still quite primitive */
/* I should probably change the flags from numbers to #defined strings ... */
#import "Mtypes.h"
#import "MolShape.h"
#import <ri/ri.h>
#import <math.h>

#define SC .05
#define SCP1 SC/1.732
#define SCP2 SC/.866
#define SCP3 SC/2.45
#define SCP4 SC/1.633-SCP3

@implementation MolShape:N3DShape
- renderSelf:(RtToken)context
{
int i,j,n,ln;
float x,y,z,r,d,lx,ly,lz;
/* a big square for a white background */
static RtPoint bsquare[4]= {{-200.0,-200.0,-40.0},{200.0,-200.0,-40.0},{200.0,200.0,-40.0},{-200.0,200.0,-40.0}};
static RtPoint square[4]= {{0.0,0.0,0.0},{1.0,0.0,0.0},{1.0,1.0,0.0},{0.0,1.0,0.0}};
static RtColor bgCol = {1.0,1.0,1.0};
static RtColor stCol = {.4,.4,.4};
static RtColor bCol = { 0,0,0 };
static RtColor dCol = { .95,.95,.95 };
static RtColor cCol;
static RtColor selCol = { 0.0,0.0,0.0 };
char *tmap = "/users/steve/grid.tex";

if (mode==4) return self;	/* quick mode, do nothing */
if (mode==12) mode=11;		/* quick mode, but we want to print, so render */

/* RiMakeTexture("/users/steve/grid.tiff","/users/steve/grid.tex", RI_PERIODIC,RI_PERIODIC,RiGaussianFilter,1,1,RI_NULL); */

RiDeclare("texname","uniform string");
RiColor(dCol);
/*
if (nmol!=0 && mol[0].numaa>2) {
	RiTransformBegin();
		RiTranslate(10.2,4.3,0.0);
		RiScale(10.0,10.0,1.0);
		RiSurface("texmap",(RtToken)"texname",(RtPointer)&tmap,RI_NULL);
		RiPolygon(4,RI_P,(RtPointer)square,RI_NULL);	
		RiSurface("constant",RI_NULL);
		RiColor(bCol);
		RiTranslate(mol[0].am[1].phi/(2.0*M_PI)+.5, 
			mol[0].am[1].psi/(2.0*M_PI)+.5,0.0);
		RiSphere(.05,-.05,.05,360.0,RI_NULL);
	RiTransformEnd();
}*/
RiSurface("constant",RI_NULL);
if (mode>=8) {
	RiColor(bgCol);
	RiPolygon(4,RI_P,(RtPointer)bsquare,RI_NULL);
}
RiRotate(chi,0,1.0,0);
RiRotate(theta,1.0,0,0.0);
RiRotate(phi,0,1.0,0);

/* metal is ok too ... */
RiSurface("plastic",RI_NULL);
RiColor(dCol);

/* stick mode */
if ((flags&3)==0) {
	RiColor(stCol);
	for (i=0; i<nmol; i++) {
		if (mol[i].numlb==0) continue;
/*		RiPointsLines(mol[i].numlb,mol[i].nverts,mol[i].verts
				,RI_P,mol[i].coord,RI_NULL); */
		for (j=0; j<mol[i].numlb; j++) {
			if (j%20==0) {
			    RiSynchronize( RI_FLUSH );
			    RiSynchronize( RI_WAIT );
			}
			n=mol[i].lb[j].n1;
			ln=mol[i].lb[j].n2;
			x=mol[i].coord[n][0];
			y=mol[i].coord[n][1];
			z=mol[i].coord[n][2];
			lx=mol[i].coord[ln][0]-x;
			ly=mol[i].coord[ln][1]-y;
			lz=mol[i].coord[ln][2]-z;
			r=sqrt(SQR(lx)+SQR(ly)+SQR(lz));
			d=acos(sqrt(SQR(lx)+SQR(ly))/r);
			if (lz<0.0) d*=-1.0;
			d=90.0-d/DRC;
			RiTransformBegin();
			RiTranslate(x,y,z);
			RiRotate(-d,ly,-lx,0.0);
/* cylinder 1 */
			if (mol[i].atom[n].sel) RiColor(selCol);	/* selected black */
			else if (flags&4) {
				d=mol[i].atom[n].charge;
				if (d<0.0) { cCol[2]=1.0; cCol[0]=cCol[1]=1.0+d; }
				if (d>=0.0) { cCol[0]=1.0; cCol[1]=cCol[2]=1.0-d; }
				RiColor(cCol);
			}
			else RiColor(elinfo[mol[i].atom[n].anum].color);
			RiCylinder(BSR,0.0,r/2.0,360.0,RI_NULL);
/* cylinder 2 */
			if (mol[i].atom[ln].sel) RiColor(selCol);	/* selected black */
			else if (flags&4) {
				d=mol[i].atom[ln].charge;
				if (d<0.0) { cCol[2]=1.0; cCol[0]=cCol[1]=1.0+d; }
				if (d>=0.0) { cCol[0]=1.0; cCol[1]=cCol[2]=1.0-d; }
				RiColor(cCol);
			}
			else RiColor(elinfo[mol[i].atom[ln].anum].color);
			RiCylinder(BSR,r/2.0,r,360.0,RI_NULL);

			RiTransformEnd();
		}
	}
}
/* ball and stick mode */
else if ((flags&3)==1) {
	for (i=0; i<nmol; i++) {
		if ((mode&3)>=2) RiColor(dCol);
		else RiColor(dCol);
		ln=-1;
/* no ellipticity info. Just spheres are faster */
		if (mol[i].ell==NULL) {
			for (j=0; j<mol[i].numa; j++) {
				if (j%20==0) {
					    RiSynchronize( RI_FLUSH );
					    RiSynchronize( RI_WAIT );
				}
				x=mol[i].coord[j][0];
				y=mol[i].coord[j][1];
				z=mol[i].coord[j][2];
				n=mol[i].atom[j].anum;
				r=elinfo[n].rad/BSS;
				if (flags&4) {
					d=mol[i].atom[j].charge;
					if (d<0.0) { cCol[2]=1.0; cCol[0]=cCol[1]=1.0+d; }
					if (d>=0.0) { cCol[0]=1.0; cCol[1]=cCol[2]=1.0-d; }
					RiColor(cCol);
				}
				else if (n!=ln) RiColor(elinfo[n].color);
				ln=n;
				if (mol[i].atom[j].sel) { RiColor(selCol); ln=-1; }
				RiTransformBegin();
				RiTranslate(x,y,z);
				RiSphere(r,-r,r,360.0,RI_NULL);
				RiTransformEnd();			 
			}
			RiColor(stCol);
	
			for (j=0; j<mol[i].numlb; j++) {
				if (j%20==0) {
				    RiSynchronize( RI_FLUSH );
				    RiSynchronize( RI_WAIT );
				}
				n=mol[i].lb[j].n1;
				ln=mol[i].lb[j].n2;
				x=mol[i].coord[n][0];
				y=mol[i].coord[n][1];
				z=mol[i].coord[n][2];
				lx=mol[i].coord[ln][0]-x;
				ly=mol[i].coord[ln][1]-y;
				lz=mol[i].coord[ln][2]-z;
				r=sqrt(SQR(lx)+SQR(ly)+SQR(lz));
				d=acos(sqrt(SQR(lx)+SQR(ly))/r);
				if (lz<0.0) d*=-1.0;
				d=90.0-d/DRC;
				RiTransformBegin();
				RiTranslate(x,y,z);
				RiRotate(-d,ly,-lx,0.0);
				RiCylinder(BSR,0.0,r,360.0,RI_NULL);
				RiTransformEnd();
			}
		}
/* Draw ellipsoids instead of spheres (otherwise identical) */
		else {
			for (j=0; j<mol[i].numa; j++) {
				if (j%20==0) {
					    RiSynchronize( RI_FLUSH );
					    RiSynchronize( RI_WAIT );
				}
				x=mol[i].coord[j][0];
				y=mol[i].coord[j][1];
				z=mol[i].coord[j][2];
				n=mol[i].atom[j].anum;
				if (flags&4) {
					d=mol[i].atom[j].charge;
					if (d<0.0) { cCol[2]=1.0; cCol[0]=cCol[1]=1.0+d; }
					if (d>=0.0) { cCol[0]=1.0; cCol[1]=cCol[2]=1.0-d; }
					RiColor(cCol);
				}
				else if (n!=ln) RiColor(elinfo[n].color);
				ln=n;
				if (mol[i].atom[j].sel) { RiColor(selCol); ln=-1; }
				RiTransformBegin();
				RiTranslate(x,y,z);
				RiRotate(mol[i].ell[j].dz,0.0,0.0,1.0);
				RiRotate(mol[i].ell[j].dx,1.0,0.0,0.0);
				RiRotate(mol[i].ell[j].dz2,0.0,0.0,1.0);
				RiScale(mol[i].ell[j].x/BSS,mol[i].ell[j].y/BSS, 
					mol[i].ell[j].z/BSS);
				RiSphere(1.0,-1.0,1.0,360.0,RI_NULL);
				RiTransformEnd();
			}
			RiColor(stCol);
	
			for (j=0; j<mol[i].numlb; j++) {
				if (j%20==0) {
				    RiSynchronize( RI_FLUSH );
				    RiSynchronize( RI_WAIT );
				}
				n=mol[i].lb[j].n1;
				ln=mol[i].lb[j].n2;
				x=mol[i].coord[n][0];
				y=mol[i].coord[n][1];
				z=mol[i].coord[n][2];
				lx=mol[i].coord[ln][0]-x;
				ly=mol[i].coord[ln][1]-y;
				lz=mol[i].coord[ln][2]-z;
				r=sqrt(SQR(lx)+SQR(ly)+SQR(lz));
				d=acos(sqrt(SQR(lx)+SQR(ly))/r);
				if (lz<0.0) d*=-1.0;
				d=90.0-d/DRC;
				RiTransformBegin();
				RiTranslate(x,y,z);
				RiRotate(-d,ly,-lx,0.0);
				RiCylinder(BSR,0.0,r,360.0,RI_NULL);
				RiTransformEnd();
			}
		}
	}
}
/* space filling mode */
else if ((flags&3)==2) {
	lx=ly=lz=0;
	for (i=0; i<nmol; i++) {
		if ((mode&3)>=2) RiColor(dCol);
		else RiColor(dCol);
		ln=-1;
/* no ellipsoids */
		if (mol[i].ell==NULL) {
			for (j=0; j<mol[i].numa; j++) {
				if (j%20==0) {
					    RiSynchronize( RI_FLUSH );
					    RiSynchronize( RI_WAIT );
				}
				x=mol[i].coord[j][0];
				y=mol[i].coord[j][1];
				z=mol[i].coord[j][2];
				n=mol[i].atom[j].anum;
				r=elinfo[n].rad;
				if (flags&4) {
					d=mol[i].atom[j].charge;
					if (d<0.0) { cCol[2]=1.0; cCol[0]=cCol[1]=1.0+d; }
					if (d>=0.0) { cCol[0]=1.0; cCol[1]=cCol[2]=1.0-d; }
					RiColor(cCol);
				}
				else if (n!=ln) RiColor(elinfo[n].color);
				ln=n;
				if (mol[i].atom[j].sel) { RiColor(selCol); ln=-1; }
				RiTranslate(x-lx,y-ly,z-lz);
				RiSphere(r,-r,r,360.0,RI_NULL);
				if (r==0.0) printf("%d %d  %f %f %f\n",j,n,x,y,z);
				lx=x; ly=y; lz=z;	 
			}
		}
/* Ellipsoids */
		else {
			for (j=0; j<mol[i].numa; j++) {
				if (j%20==0) {
					    RiSynchronize( RI_FLUSH );
					    RiSynchronize( RI_WAIT );
				}
				x=mol[i].coord[j][0];
				y=mol[i].coord[j][1];
				z=mol[i].coord[j][2];
				n=mol[i].atom[j].anum;
				r=elinfo[n].rad;
				if (flags&4) {
					d=mol[i].atom[j].charge;
					if (d<0.0) { cCol[2]=1.0; cCol[0]=cCol[1]=1.0+d; }
					if (d>=0.0) { cCol[0]=1.0; cCol[1]=cCol[2]=1.0-d; }
					RiColor(cCol);
				}
				else if (n!=ln) RiColor(elinfo[n].color);
				ln=n;
				if (mol[i].atom[j].sel) { RiColor(selCol); ln=-1; }
				RiTransformBegin();
				RiTranslate(x,y,z);
				RiRotate(mol[i].ell[j].dz,0.0,0.0,1.0);
				RiRotate(mol[i].ell[j].dx,1.0,0.0,0.0);
				RiRotate(mol[i].ell[j].dz2,0.0,0.0,1.0);
				RiScale(mol[i].ell[j].x,mol[i].ell[j].y,mol[i].ell[j].z);
				RiSphere(1.0,-1.0,1.0,360.0,RI_NULL);
				lx=x; ly=y; lz=z;	 
				RiTransformEnd();
			}
		}
	}
}
return self;
}

-setData:(Molecule *)Mol :(int)Nmol :(struct ELINFO *)Elinfo :(int)Mode :(int)Flags
{
mol=Mol;
nmol=Nmol;
elinfo=Elinfo;
mode=Mode;
flags=Flags;
return self;
}

-setAng:(float)Theta :(float)Chi :(float)Phi
{
theta=Theta/DRC;
chi=Chi/DRC;
phi=Phi/DRC;
return self;
}

- setSurfaceType:(N3DSurfaceType)st andDescendants:(BOOL)flag
{
[super setSurfaceType:st andDescendants:flag];
return self;
}

-setBSSR:(float)bss :(float)bsr
{
BSS=bss;
BSR=bsr;
if (BSS<=0.0) BSS=1.0;
if (BSR<=0.0) BSR=0.1;
return self;
}

@end
  
