/*
	Ray tracing program.
	by Oda Masahiro
	02/11/15
*/

import java.io.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.net.*;
import java.util.Vector;
import java.applet.*;


class st_xyz{
	float x,y,z;
	
	public void substitute(st_xyz vec){
		x=vec.x; y=vec.y; z=vec.z;
	}
	
	public void inverse(){
		x=-x; y=-y; z=-z;
	}
	
	public void normalize(){
		double size=Math.sqrt(x*x+y*y+z*z);
		x=x/(float)size;
		y=y/(float)size;
		z=z/(float)size;
	}
	
	public double getSize(){
		return Math.sqrt(x*x+y*y+z*z);
	}
}

class st_color{
	double r,g,b,a;
	
	public void substitute(st_color col){
		r=col.r; g=col.g; b=col.b; a=col.a;
	}
}

class st_uv{
	float u,v;
}

class Object3d{
	int type;	//1:球,2:楕円,5:楕円錐面,20:多面体
	
	//性質
	st_color col = new st_color();	//色
	
	int reflectdiffuse;		//1:拡散反射
	int reflectspecular;	//1:鏡面反射
	int refract;	//1:透明物
	
	double reflect_rate;	//反射係数（0〜1）
	int reflect_luster;		//光沢（1〜10くらい）
	double refract_rate;	//屈折率
	
	int texturemapped;	//1:テクスチャーマッピング
	Texture texture = new Texture();
	
	//球、楕円用データ
	st_xyz centersource = new st_xyz();	//球、楕円の中心座標元
	st_xyz axissource = new st_xyz();	//楕円の長軸短軸の長さ元
	st_xyz center = new st_xyz();	//球、楕円の中心座標（移動後）
	st_xyz axis = new st_xyz();		//楕円の長軸短軸の長さ（スケーリング後）
	float radius;	//球なら半径
	
	float ka,kb,kc,kd,ke,kf,kg,kh,ki,kj;
	
	//多面体用データ
	int surfacenumber;	//面数
	int svtotal[] = new int[100];	//面を構成する頂点数
	int svnumber[][] = new int[100][30];	//面を構成する頂点番号
	st_uv svtextureuv[][] = new st_uv[100][30];	//面を構成する頂点のテクスチャマッピング用uv座標
	
	int vertexnumber;		//頂点数
	st_xyz vsource[] = new st_xyz[100];	//頂点座標元
	st_xyz v[] = new st_xyz[100];	//頂点座標（アフィン変換後）
	
	//共通データ
	st_xyz vd = new st_xyz();	//移動量
	st_xyz scale = new st_xyz();//サイズ
	double rotx,roty,rotz;		//回転角度
	
	Object3d(){
		int i,j;
		scale.x=1; scale.y=1; scale.z=1;
		
		for(i=0;i<100;i++)
			for(j=0;j<30;j++)
				svtextureuv[i][j] = new st_uv();
		
		for(i=0;i<100;i++){
			vsource[i] = new st_xyz();
			v[i] = new st_xyz();
		}
	}
	
	//centersourceからcenterへコピー
	public void setCenter(){
		center.substitute(centersource);
		axis.substitute(axissource);
	}
	
	//vsourceからvへコピー
	public void setV(){
		for(int i=0;i<100;i++)
			v[i].substitute(vsource[i]);
	}
}

class Light{
	int type;	//1:点光源,2:面光源
	
	st_xyz pos = new st_xyz();	//点光源の位置
	
	//面光源用
	int surfacenumber;	//面数
	int svtotal[] = new int[100];	//面を構成する頂点数
	int svnumber[][] = new int[100][30];	//面を構成する頂点番号
	
	int vertexnumber;	//頂点数
	st_xyz vsource[] = new st_xyz[100];	//頂点座標元
	st_xyz v[] = new st_xyz[100];	//頂点座標（アフィン変換後）
	st_xyz vd = new st_xyz();	//変化量
	
	st_xyz scale = new st_xyz();	//サイズ
	
	double rotx,roty,rotz;	//回転角度
	
	st_color col = new st_color();	//光源の色
	
	int division;	//面光源を点光源に分割したときの分割数
	
	Light(){
		scale.x=1; scale.y=1; scale.z=1;
		
		division=1;
		
		for(int i=0;i<100;i++){
			vsource[i] = new st_xyz();
			v[i] = new st_xyz();
		}
	}
	
	//vsourceからvへコピー
	public void setV(){
		for(int i=0;i<100;i++)
			v[i].substitute(vsource[i]);
	}
}

class Raytrace{
	int lr;		//2分木の左か右か
	
	int reflectdiffuse;		//1:拡散反射
	int reflectspecular;	//1:鏡面反射
	int refract;		//1:屈折
	int reflect_checked,refract_checked;
	int reflect_end,refract_end;	//1:これ以上探索できないとき。2分木の葉まできた、交点がないとき。
	
	double reflect_rate;	//反射係数（0〜1）
	double reflect_luster;	//光沢値（1〜10くらい）
	double refract_rate;	//屈折率
	
	int objnumber;		//交点があった物体番号
	st_xyz cross = new st_xyz();	//交点座標
	st_xyz normal = new st_xyz();	//交点の面の法線ベクトル
	st_xyz reflect_vec = new st_xyz();	//反射方向
	st_xyz refract_vec = new st_xyz();	//屈折方向
	double reflect_dist;	//反射光の次の交点までの距離
	double refract_dist;	//屈折光の次の交点までの距離
	
	double theta;	//入射光と法線のなす角
	double gamma;	//反射光と視線方向のなす角
	
	double k;	//屈折せずに反射する光の割合
	
	st_color col = new st_color();	//光の色
	st_color objcol = new st_color();	//物体の色
	
	Raytrace(){
		reflectdiffuse=0; reflectspecular=0; refract=0;
		reflect_checked=0; refract_checked=0;
		reflect_end=0; refract_end=0;
		
		reflect_rate=0;
		reflect_luster=1;
		refract_rate=1;
		
		objnumber=-1;
		reflect_dist=10000; refract_dist=10000;
		
		k=1;
	}
}

class Refract_rate_list{
	private int OBJECT_NUMBER=7;
	private int top;
	private int index[] = new int[OBJECT_NUMBER];
	private double rate[] = new double[OBJECT_NUMBER];
	
	//コンストラクタ
	Refract_rate_list(){
		for(int i=0;i<OBJECT_NUMBER;i++){
			index[i]=-1;
			rate[i]=0;
		}
		
		top=1;
		rate[0]=1.0;
	}
	
	//リストに要素を追加する
	public void add(int number,double refractrate){
		if(top<=0 || top>=OBJECT_NUMBER)
			throw new InternalError("リストトップの位置が不適切です。");
		
		index[top]=number;
		rate[top]=refractrate;
		top++;
	}
	
	//リストから指定された番号の要素を削除する
	public int delete(int number){
		int i,j;
		
		if(top<=0 || top>=OBJECT_NUMBER)
			throw new InternalError("リストトップの位置が不適切です。");
		
		for(i=0;i<OBJECT_NUMBER;i++){
			if(index[i]==number){	//削除要求された要素が見つかった
				for(j=i;j<OBJECT_NUMBER-1;j++){	//後の要素を1つづつずらす
					index[j]=index[j+1];
					rate[j]=rate[j+1];
				}
				index[OBJECT_NUMBER-1]=-1;
				rate[OBJECT_NUMBER-1]=0;
				break;
			}
		}
		
		if(i<OBJECT_NUMBER){
			top--;
			return 1;	//削除できた
		}else
			return 0;	//削除要求された要素がない
	}
	
	//リスト中に指定された番号の要素があるか調べる
	public int check(int number){
		int i;
		
		for(i=0;i<OBJECT_NUMBER;i++){
			if(index[i]==number){	//指定された要素が見つかった
				return 1;
			}
		}
		
		return 0;	//指定された要素がない
	}
	
	//リストトップの値を取り出す
	public double findtop(){
		if(top<=0 || top>=OBJECT_NUMBER)
			throw new InternalError("リストトップの位置が不適切です。");
		
		return rate[top-1];
	}
}


class Texture extends Component implements Serializable, Cloneable{
	private Applet applet;
	private URL url;
	private String filename;
	private Image texture;
	private int[] texel;
	private int height,width;
	
	//コンストラクタ
	public Texture(Applet applet,URL base,String filename){
		this.applet = applet;
		try{
			this.url = new URL(base,filename);
		}catch(MalformedURLException e){}
		this.filename = new String(filename);
		this.texture = null;
		this.texel = null;
		this.width = this.height = 0;
	}
	
	public Texture(String filename){
		this.applet = null;
		this.url = null;
		this.filename = new String(filename);
		this.texture = null;
		this.texel = null;
		this.width = this.height = 0;
	}
	
	public Texture(){ this(""); }
	
	public Texture(Texture p){
		applet = p.applet;
		try{
			url = new URL(p.url,p.filename);
		}catch(MalformedURLException e){}
		filename = new String(p.filename);
		texture = p.texture;
		texel = p.texel;
		width = p.width; height=p.height;
	}
	
	//テクスチャファイルのロード
	public void loadImage(){
		MediaTracker mt = new MediaTracker(this);
		
		if(filename==null)
			throw new NullPointerException("テクスチャファイル名がありません。");
		
		if(applet==null && url==null)
			texture=this.getToolkit().getImage(filename);
		else
			texture=this.applet.getImage(url,filename);
		
		mt.addImage(texture,1);
		
		try{
			mt.waitForAll();
		}catch(InterruptedException e){}
		
		width=texture.getWidth(this);
		height=texture.getHeight(this);
		texel = new int[width*height];
		PixelGrabber pg = new PixelGrabber(texture,0,0,width,height,texel,0,width);
		
		try{
			pg.grabPixels();
		}catch(InterruptedException e){}
	}
	
	//ピクセルの色を得る。画像の左下が座標の原点
	public st_color getTexelColor(int i,int j){
		int value;
		st_color col = new st_color();
		
		if(i<0 || j<0 || i>width || j>height)
			throw new NullPointerException("テクスチャ座標の指定が不適切です。");
		
		value = texel[(height-j-1)*width+i];
		col.r = (value >> 16) & 0xff;
		col.g = (value >> 8) & 0xff;
		col.b = (value) & 0xff;
		
		return col;
	}
	
	//GIF画像の場合、透過情報を得る
	public int getTexelOpacity(int i,int j){
		int value;
		
		value = texel[(height-j-1)*width+i];
		value = (value >> 24) & 0xff;
		
		return value;
	}
	
	public int getWidth(){ return width; }
	public int getHeight(){ return height; }
}



public class Applet1 extends Applet
	implements MouseListener,MouseMotionListener,
	ActionListener,ItemListener,AdjustmentListener,Runnable
{
	Thread th=null;
	Image doubleBuf;
	int bufLen=400;
	Graphics gg;
	Button renderButton,stopButton,clearButton;
	Choice moverotChoice;
	Scrollbar colrScr,colgScr,colbScr;
	TextField colrText,colgText,colbText;
	Checkbox diffuseCheck,specularCheck,transparentCheck;
	Scrollbar reflectScr,lusterScr,refractScr;
	TextField reflectText,lusterText,refractText;
	st_xyz mouseclick = new st_xyz();
	st_xyz mousedrag = new st_xyz();
	int rendering=0,renderstop=0,rendx=0,rendy=0,selectobject=-1,moverot=0,changecol=0;
	
	//定数
	final double ToRAD=Math.PI/180.0;
	final double Dec=0;	//光減衰率
	final double DISTANCE_MIN=0.1;
	
	//レイトレースデータ用定数
	int TRACE_TIMES=4;		//光の反射・屈折を追跡する回数
	int TREEDATA_NUMBER=(int)Math.pow(2,TRACE_TIMES);	//2のTRACE_TIMES乗
	
	//オブジェクトデータ
	int OBJECT_NUMBER=7;
	Object3d object[] = new Object3d[OBJECT_NUMBER];
	
	//光源データ
	int LIGHT_NUMBER=3;
	Light lightsource[] = new Light[LIGHT_NUMBER];	//光源データ元
	Vector light = new Vector();	//光源データ元を点光源に変換した後代入
	
	//視点位置
	st_xyz eyept = new st_xyz();
	st_xyz eyeptrot = new st_xyz();	//視野変換用
	
	//環境光
	st_color envlight = new st_color();
	
	
	//値初期化
	public void init()
	{
		this.setBackground(Color.white);
		this.setForeground(Color.black);
		
		setLayout(new BorderLayout());
		Panel p = new Panel();
		//p.setLayout(new GridLayout(18,1,5,5));	//行数,列数,横間隔,縦間隔
		GridBagLayout gb = new GridBagLayout();
		p.setLayout(gb);
		GridBagConstraints gbc = new GridBagConstraints();
		
		//ボタン、チョイス、スクロールバー、チェックボックス、マウスリスナー、テキストフィールド初期化
		renderButton = new Button("Rendering Start");
		renderButton.addActionListener(this);
		stopButton = new Button("Rendering Stop");
		stopButton.addActionListener(this);
		clearButton = new Button("Clear Screen");
		clearButton.addActionListener(this);
		
		moverotChoice=new Choice();
		moverotChoice.addItem("Move");
		moverotChoice.addItem("Rotate");
		moverotChoice.addItemListener(this);
		
		colrScr = new Scrollbar(Scrollbar.HORIZONTAL,125,75,0,330);
		colgScr = new Scrollbar(Scrollbar.HORIZONTAL,125,75,0,330);
		colbScr = new Scrollbar(Scrollbar.HORIZONTAL,125,75,0,330);
		colrScr.setUnitIncrement(1);
		colgScr.setUnitIncrement(1);
		colbScr.setUnitIncrement(1);
		colrScr.setBlockIncrement(30);
		colgScr.setBlockIncrement(30);
		colbScr.setBlockIncrement(30);
		colrScr.addAdjustmentListener(this);
		colgScr.addAdjustmentListener(this);
		colbScr.addAdjustmentListener(this);
		
		colrText = new TextField(3);
		colgText = new TextField(3);
		colbText = new TextField(3);
		colrText.addActionListener(this);
		colgText.addActionListener(this);
		colbText.addActionListener(this);
		
		reflectScr = new Scrollbar(Scrollbar.HORIZONTAL,100,20,0,120);
		lusterScr = new Scrollbar(Scrollbar.HORIZONTAL,1,2,1,12);
		refractScr = new Scrollbar(Scrollbar.HORIZONTAL,133,50,100,350);
		reflectScr.setUnitIncrement(1);
		lusterScr.setUnitIncrement(1);
		refractScr.setUnitIncrement(1);
		reflectScr.setBlockIncrement(10);
		lusterScr.setBlockIncrement(2);
		refractScr.setBlockIncrement(10);
		reflectScr.addAdjustmentListener(this);
		lusterScr.addAdjustmentListener(this);
		refractScr.addAdjustmentListener(this);
		
		diffuseCheck = new Checkbox("Diffuse");
		specularCheck = new Checkbox("Specular");
		transparentCheck = new Checkbox("Transparent");
		diffuseCheck.addItemListener(this);
		specularCheck.addItemListener(this);
		transparentCheck.addItemListener(this);
		
		reflectText = new TextField(3);
		lusterText = new TextField(3);
		refractText = new TextField(3);
		reflectText.addActionListener(this);
		lusterText.addActionListener(this);
		refractText.addActionListener(this);
		
		
		//Label blankLabel = new Label("");
		
		//ボタンなど配置
		Label controlLabel = new Label("Mouse operation");
		gbc.gridx=0; gbc.gridy=0;	//配置する位置
		gbc.gridwidth=1; gbc.gridheight=1;	//配置する幅、高さ
		gbc.insets = new Insets(2,0,4,2);	//下,左,右,上の余白
		gbc.fill=gbc.HORIZONTAL;	//幅いっぱいにリサイズ
		gbc.anchor=gbc.WEST;	//左寄せ
		gb.setConstraints(controlLabel,gbc);
		p.add(controlLabel);
		
		gbc.gridx=0; gbc.gridy=1;
		gbc.gridwidth=1; gbc.gridheight=1;
		gb.setConstraints(moverotChoice,gbc);
		p.add(moverotChoice);
		
		//Color
		Label colLabel = new Label("Color(R,G,B)");
		gbc.gridx=0; gbc.gridy=3;
		gbc.gridwidth=1; gbc.gridheight=1;
		gb.setConstraints(colLabel,gbc);
		p.add(colLabel);
		
		gbc.gridx=0; gbc.gridy=4;
		gbc.gridwidth=1; gbc.gridheight=1;
		gb.setConstraints(colrScr,gbc);
		p.add(colrScr);
		
		gbc.gridx=1; gbc.gridy=4;
		gbc.gridwidth=1; gbc.gridheight=1;
		gbc.fill=gbc.NONE;
		gb.setConstraints(colrText,gbc);
		p.add(colrText);
		
		gbc.gridx=0; gbc.gridy=5;
		gbc.gridwidth=1; gbc.gridheight=1;
		gbc.fill=gbc.HORIZONTAL;
		gb.setConstraints(colgScr,gbc);
		p.add(colgScr);
		
		gbc.gridx=1; gbc.gridy=5;
		gbc.gridwidth=1; gbc.gridheight=1;
		gbc.fill=gbc.NONE;
		gb.setConstraints(colgText,gbc);
		p.add(colgText);
		
		gbc.gridx=0; gbc.gridy=6;
		gbc.gridwidth=1; gbc.gridheight=1;
		gbc.fill=gbc.HORIZONTAL;
		gb.setConstraints(colbScr,gbc);
		p.add(colbScr);
		
		gbc.gridx=1; gbc.gridy=6;
		gbc.gridwidth=1; gbc.gridheight=1;
		gbc.fill=gbc.NONE;
		gb.setConstraints(colbText,gbc);
		p.add(colbText);
		
		//性質設定
		gbc.gridx=0; gbc.gridy=7;
		gbc.gridwidth=1; gbc.gridheight=1;
		gbc.fill=gbc.HORIZONTAL;
		gb.setConstraints(diffuseCheck,gbc);
		p.add(diffuseCheck);
		
		Label reflectLabel = new Label("Reflect rate (0...1)");
		gbc.gridx=0; gbc.gridy=8;
		gbc.gridwidth=1; gbc.gridheight=1;
		gb.setConstraints(reflectLabel,gbc);
		p.add(reflectLabel);
		
		gbc.gridx=0; gbc.gridy=9;
		gbc.gridwidth=1; gbc.gridheight=1;
		gb.setConstraints(reflectScr,gbc);
		p.add(reflectScr);
		
		gbc.gridx=1; gbc.gridy=9;
		gbc.gridwidth=1; gbc.gridheight=1;
		gbc.fill=gbc.NONE;
		gb.setConstraints(reflectText,gbc);
		p.add(reflectText);
		
		
		gbc.gridx=0; gbc.gridy=10;
		gbc.gridwidth=1; gbc.gridheight=1;
		gbc.fill=gbc.HORIZONTAL;
		gb.setConstraints(specularCheck,gbc);
		p.add(specularCheck);
		
		Label specularLabel = new Label("Luster (1...10)");
		gbc.gridx=0; gbc.gridy=11;
		gbc.gridwidth=1; gbc.gridheight=1;
		gb.setConstraints(specularLabel,gbc);
		p.add(specularLabel);
		
		gbc.gridx=0; gbc.gridy=12;
		gbc.gridwidth=1; gbc.gridheight=1;
		gb.setConstraints(lusterScr,gbc);
		p.add(lusterScr);
		
		gbc.gridx=1; gbc.gridy=12;
		gbc.gridwidth=1; gbc.gridheight=1;
		gbc.fill=gbc.NONE;
		gb.setConstraints(lusterText,gbc);
		p.add(lusterText);
		
		
		gbc.gridx=0; gbc.gridy=13;
		gbc.gridwidth=1; gbc.gridheight=1;
		gbc.fill=gbc.HORIZONTAL;
		gb.setConstraints(transparentCheck,gbc);
		p.add(transparentCheck);
		
		Label refractLabel = new Label("Refract rate (1...3)");
		gbc.gridx=0; gbc.gridy=14;
		gbc.gridwidth=1; gbc.gridheight=1;
		gb.setConstraints(refractLabel,gbc);
		p.add(refractLabel);
		
		gbc.gridx=0; gbc.gridy=15;
		gbc.gridwidth=1; gbc.gridheight=1;
		gb.setConstraints(refractScr,gbc);
		p.add(refractScr);
		
		gbc.gridx=1; gbc.gridy=15;
		gbc.gridwidth=1; gbc.gridheight=1;
		gbc.fill=gbc.NONE;
		gb.setConstraints(refractText,gbc);
		p.add(refractText);
		
		//Rendering
		Label renderingLabel = new Label("Rendering");
		gbc.gridx=0; gbc.gridy=16;
		gbc.gridwidth=1; gbc.gridheight=1;
		gbc.fill=gbc.HORIZONTAL;
		gb.setConstraints(renderingLabel,gbc);
		p.add(renderingLabel);
		
		gbc.gridx=0; gbc.gridy=17;
		gbc.gridwidth=1; gbc.gridheight=1;
		gb.setConstraints(renderButton,gbc);
		p.add(renderButton);
		
		gbc.gridx=1; gbc.gridy=17;
		gbc.gridwidth=1; gbc.gridheight=1;
		gb.setConstraints(stopButton,gbc);
		p.add(stopButton);
		
		gbc.gridx=1; gbc.gridy=18;
		gbc.gridwidth=1; gbc.gridheight=1;
		gb.setConstraints(clearButton,gbc);
		p.add(clearButton);
		
		add(p,"East");
		
		addMouseListener(this);
		addMouseMotionListener(this);
		
		
		doubleBuf=createImage(bufLen,bufLen);	//ダブルバッファ
		gg=doubleBuf.getGraphics();
		
		int i,j;
		
		//オブジェクトを配列に代入
		for(i=0;i<OBJECT_NUMBER;i++){
			object[i] = new Object3d();
		}
		for(i=0;i<LIGHT_NUMBER;i++){
			lightsource[i] = new Light();
		}
		
		
		//視点の位置、視点の回転量
		eyept.x=0; eyept.y=0; eyept.z=500;
		eyeptrot.x=20; eyeptrot.y=0; eyeptrot.z=0;
		
		//環境光
		envlight.r=50; envlight.g=50; envlight.b=50;
		
		//物体の定義
		defineObject();
		
		for(i=0;i<OBJECT_NUMBER;i++){
			object[i].setCenter();
			object[i].setV();
			calculateCoefficient(object[i]);
		}
		
		for(i=0;i<LIGHT_NUMBER;i++){
			lightsource[i].setV();
		}
	}
	
	public void defineObject(){
		int i,j;
		
		//オブジェクトデータ初期化
		//空
		object[0].type=1;
		object[0].reflectdiffuse=1;
		object[0].reflectspecular=0;
		object[0].refract=0;
		object[0].reflect_rate=1;
		object[0].reflect_luster=3;
		object[0].refract_rate=1;
		object[0].radius=700;
		object[0].centersource.x=0; object[0].centersource.y=0; object[0].centersource.z=0;
		object[0].col.r=0; object[0].col.g=255; object[0].col.b=255;
		object[0].texturemapped=0;
	//	object[0].texture=image2;
	//	object[0].scale.x=100; object[0].scale.y=100; object[0].scale.z=100;
		object[0].vd.x=0; object[0].vd.y=0; object[0].vd.z=0;
		object[0].rotx=0; object[0].roty=0; object[0].rotz=0;
		
		//地面
		object[1].type=20;
		object[1].reflectdiffuse=1;
		object[1].reflectspecular=0;
		object[1].refract=0;
		object[1].reflect_rate=1;
		object[1].reflect_luster=5;
		object[1].refract_rate=1.1;
		object[1].col.r=100; object[1].col.g=100; object[1].col.b=100;
		object[1].texturemapped=1;
		object[1].texture = new Texture(this,getDocumentBase(),"ichimatsu1.gif");
		object[1].texture.loadImage();
		object[1].scale.x=500; object[1].scale.y=1; object[1].scale.z=500;
		object[1].vd.x=0; object[1].vd.y=0; object[1].vd.z=0;
		object[1].rotx=0; object[1].roty=0; object[1].rotz=0;
		object[1].surfacenumber=1;
		object[1].svtotal[0]=4;
		object[1].svnumber[0][0]=0; object[1].svnumber[0][1]=1; object[1].svnumber[0][2]=2; object[1].svnumber[0][3]=3;
		object[1].svtextureuv[0][0].u=15; object[1].svtextureuv[0][0].v=15;
		object[1].svtextureuv[0][1].u=0; object[1].svtextureuv[0][1].v=15;
		object[1].svtextureuv[0][2].u=0; object[1].svtextureuv[0][2].v=0;
		object[1].svtextureuv[0][3].u=15; object[1].svtextureuv[0][3].v=0;
		object[1].vertexnumber=4;
		object[1].vsource[0].x=-1; object[1].vsource[0].y=0;  object[1].vsource[0].z=1;
		object[1].vsource[1].x=1;  object[1].vsource[1].y=0;  object[1].vsource[1].z=1;
		object[1].vsource[2].x=1;  object[1].vsource[2].y=0;  object[1].vsource[2].z=-1;
		object[1].vsource[3].x=-1; object[1].vsource[3].y=0;  object[1].vsource[3].z=-1;
		
		
		object[2].type=2;
		object[2].reflectdiffuse=0;
		object[2].reflectspecular=1;
		object[2].refract=0;
		object[2].reflect_rate=1;
		object[2].reflect_luster=5;
		object[2].refract_rate=1.1;
		object[2].centersource.x=0; object[2].centersource.y=0; object[2].centersource.z=0;
		object[2].axissource.x=1; object[2].axissource.y=0.5f; object[2].axissource.z=0.5f;
		object[2].col.r=0; object[2].col.g=255; object[2].col.b=0;
		object[2].texturemapped=0;
		object[2].scale.x=100; object[2].scale.y=100; object[2].scale.z=100;
		object[2].vd.x=110; object[2].vd.y=70; object[2].vd.z=50;
		object[2].rotx=0; object[2].roty=0; object[2].rotz=0;
		
		object[3].type=1;
		object[3].reflectdiffuse=0;
		object[3].reflectspecular=1;
		object[3].refract=1;
		object[3].reflect_rate=1;
		object[3].reflect_luster=3;
		object[3].refract_rate=1.5;
		object[3].radius=60;
		object[3].centersource.x=0; object[3].centersource.y=0; object[3].centersource.z=0;
		object[3].col.r=255; object[3].col.g=100; object[3].col.b=100;
		object[3].texturemapped=0;
	//	object[3].scale.x=60; object[3].scale.y=60; object[3].scale.z=60;
		object[3].vd.x=-60; object[3].vd.y=80; object[3].vd.z=50;
		object[3].rotx=0; object[3].roty=0; object[3].rotz=0;
		
		for(i=4;i<OBJECT_NUMBER;i++){
			object[i].type=20;
			object[i].reflectdiffuse=1;
			object[i].reflectspecular=0;
			object[i].refract=0;
			object[i].reflect_rate=0.7;
			object[i].reflect_luster=1;
			object[i].refract_rate=1.5;
			object[i].texturemapped=0;
		
			object[i].surfacenumber=6;
			object[i].svtotal[0]=4;
			object[i].svtotal[1]=4;
			object[i].svtotal[2]=4;
			object[i].svtotal[3]=4;
			object[i].svtotal[4]=4;
			object[i].svtotal[5]=4;
			object[i].svnumber[0][0]=4; object[i].svnumber[0][1]=5; object[i].svnumber[0][2]=7; object[i].svnumber[0][3]=6;
			object[i].svnumber[1][0]=5; object[i].svnumber[1][1]=1; object[i].svnumber[1][2]=3; object[i].svnumber[1][3]=7;
			object[i].svnumber[2][0]=0; object[i].svnumber[2][1]=1; object[i].svnumber[2][2]=5; object[i].svnumber[2][3]=4;
			object[i].svnumber[3][0]=0; object[i].svnumber[3][1]=4; object[i].svnumber[3][2]=6; object[i].svnumber[3][3]=2;
			object[i].svnumber[4][0]=3; object[i].svnumber[4][1]=2; object[i].svnumber[4][2]=6; object[i].svnumber[4][3]=7;
			object[i].svnumber[5][0]=1; object[i].svnumber[5][1]=0; object[i].svnumber[5][2]=2; object[i].svnumber[5][3]=3;
			for(j=0;j<object[i].surfacenumber;j++){
				object[i].svtextureuv[j][0].u=1; object[i].svtextureuv[j][0].v=1;
				object[i].svtextureuv[j][1].u=0; object[i].svtextureuv[j][1].v=1;
				object[i].svtextureuv[j][2].u=0; object[i].svtextureuv[j][2].v=0;
				object[i].svtextureuv[j][3].u=1; object[i].svtextureuv[j][3].v=0;
			}
		
			object[i].vertexnumber=8;
			object[i].vsource[0].x=-1; object[i].vsource[0].y=1;  object[i].vsource[0].z=1;
			object[i].vsource[1].x=1;  object[i].vsource[1].y=1;  object[i].vsource[1].z=1;
			object[i].vsource[2].x=-1; object[i].vsource[2].y=-1; object[i].vsource[2].z=1;
			object[i].vsource[3].x=1;  object[i].vsource[3].y=-1; object[i].vsource[3].z=1;
			object[i].vsource[4].x=-1; object[i].vsource[4].y=1;  object[i].vsource[4].z=-1;
			object[i].vsource[5].x=1;  object[i].vsource[5].y=1;  object[i].vsource[5].z=-1;
			object[i].vsource[6].x=-1; object[i].vsource[6].y=-1; object[i].vsource[6].z=-1;
			object[i].vsource[7].x=1;  object[i].vsource[7].y=-1; object[i].vsource[7].z=-1;
		}
		
		object[4].col.r=255; object[4].col.g=255; object[4].col.b=0;
		object[4].texturemapped=0;
		//object[4].texture=image2;
		object[4].scale.x=30; object[4].scale.y=30; object[4].scale.z=30;
		object[4].vd.x=100; object[4].vd.y=30; object[4].vd.z=170;
		object[4].rotx=0; object[4].roty=0; object[4].rotz=0;
		
		object[5].col.r=100; object[5].col.g=100; object[5].col.b=255;
		object[5].texturemapped=0;
		//object[5].texture=image2;
		object[5].scale.x=30; object[5].scale.y=30; object[5].scale.z=30;
		object[5].vd.x=0; object[5].vd.y=30; object[5].vd.z=-200;
		object[5].rotx=0; object[5].roty=0; object[5].rotz=0;
		
		object[6].col.r=150; object[6].col.g=150; object[6].col.b=150;
		object[6].texturemapped=1;
		object[6].texture = new Texture(this,getDocumentBase(),"pika1.jpg");
		object[6].texture.loadImage();
		object[6].scale.x=30; object[6].scale.y=30; object[6].scale.z=30;
		object[6].vd.x=-110; object[6].vd.y=50; object[6].vd.z=150;
		object[6].rotx=0; object[6].roty=0; object[6].rotz=0;
		
		
		//光源データ初期化
		lightsource[0].type=1;
		lightsource[0].pos.x=0; lightsource[0].pos.y=150; lightsource[0].pos.z=150;
		lightsource[0].col.r=255; lightsource[0].col.g=255; lightsource[0].col.b=255;
		
		lightsource[1].type=0;
		lightsource[1].scale.x=20; lightsource[1].scale.y=1; lightsource[1].scale.z=40;
		lightsource[1].vd.x=100; lightsource[1].vd.y=150; lightsource[1].vd.z=0;
		lightsource[1].col.r=18.2; lightsource[1].col.g=18.2; lightsource[1].col.b=18.2;
		lightsource[1].surfacenumber=1;
		lightsource[1].svtotal[0]=4;
		lightsource[1].svnumber[0][0]=0; lightsource[1].svnumber[0][1]=1; lightsource[1].svnumber[0][2]=2; lightsource[1].svnumber[0][3]=3;
		lightsource[1].vertexnumber=4;
		lightsource[1].vsource[0].x=1;	lightsource[1].vsource[0].y=0;	lightsource[1].vsource[0].z=-1;
		lightsource[1].vsource[1].x=1;	lightsource[1].vsource[1].y=0;	lightsource[1].vsource[1].z=1;
		lightsource[1].vsource[2].x=-1;	lightsource[1].vsource[2].y=0;	lightsource[1].vsource[2].z=1;
		lightsource[1].vsource[3].x=-1;	lightsource[1].vsource[3].y=0;	lightsource[1].vsource[3].z=-1;
		
		lightsource[2].type=1;
		lightsource[2].pos.x=-50; lightsource[2].pos.y=200; lightsource[2].pos.z=-150;
		lightsource[2].col.r=255; lightsource[2].col.g=0; lightsource[2].col.b=0;
	}
	
	//2次曲面の式の係数を求める
	public void calculateCoefficient(Object3d object){
		float a,b,c,d,e,f,g,h,i,j;
		switch(object.type){
		case 1:
			a=object.center.x; b=object.center.y; c=object.center.z;
			//球の式の係数計算
			object.ka=1; object.kb=1; object.kc=1;
			object.kd=0; object.ke=0; object.kf=0;
			object.kg=-2*a;
			object.kh=-2*b;
			object.ki=-2*c;
			object.kj=a*a + b*b + c*c - object.radius*object.radius;
			break;
		case 2:
			a=object.center.x; b=object.center.y; c=object.center.z;
			d=object.axis.x; e=object.axis.y; f=object.axis.z;
			//楕円の式の係数計算
			object.ka=e*e*f*f;
			object.kb=d*d*f*f;
			object.kc=d*d*e*e;
			object.kd=0; object.ke=0; object.kf=0;
			object.kg=-2*a*e*e*f*f;
			object.kh=-2*b*d*d*f*f;
			object.ki=-2*c*d*d*e*e;
			object.kj=a*a*e*e*f*f + b*b*d*d*f*f + c*c*d*d*e*e - d*d*e*e*f*f;
			break;
		case 5:
			a=object.center.x; b=object.center.y; c=object.center.z;
			d=object.axis.x; e=object.axis.y; f=object.axis.z;
			//楕円錐面の式の係数計算
			object.ka=e*e*f*f;
			object.kb=-d*d*f*f;
			object.kc=d*d*e*e;
			object.kd=0; object.ke=0; object.kf=0;
			object.kg=-2*a*e*e*f*f;
			object.kh=2*b*d*d*f*f;
			object.ki=-2*c*d*d*e*e;
			object.kj=a*a*e*e*f*f - b*b*d*d*f*f + c*c*d*d*e*e;
			break;
		case 20:
			break;
		}
	}
	
	//ボタン、テキストフィールド
	public void actionPerformed(ActionEvent e){
		double value;
		//ボタン
		if(e.getSource()==renderButton){
			if(rendering==0){
				rendering=1;
				renderstop=0;
				rendx=0;
				rendy=0;
			}else if(rendering==1){
				renderstop=0;
				th.resume();
			}
		}else if(e.getSource()==stopButton){
			if(rendering==1){
				renderstop=1;
				th.suspend();
			}
		}else if(e.getSource()==clearButton){
			rendering=0;
			renderstop=0;
			rendx=0;
			rendy=0;
			th.resume();
		}
		//色テキストフィールド
		else if(e.getSource()==colrText){
			value=Double.valueOf(colrText.getText()).doubleValue();
			if(Double.isNaN(value)==false && value>=0 && value<=255){
				object[selectobject].col.r=value;
				changecol=1;
			}
			colrText.setText(Integer.toString((int)object[selectobject].col.r));
			colrScr.setValue((int)object[selectobject].col.r);
		}else if(e.getSource()==colgText){
			value=Double.valueOf(colgText.getText()).doubleValue();
			if(Double.isNaN(value)==false && value>=0 && value<=255){
				object[selectobject].col.g=value;
				changecol=1;
			}
			colgText.setText(Integer.toString((int)object[selectobject].col.g));
			colgScr.setValue((int)object[selectobject].col.g);
		}else if(e.getSource()==colbText){
			value=Double.valueOf(colbText.getText()).doubleValue();
			if(Double.isNaN(value)==false && value>=0 && value<=255){
				object[selectobject].col.b=value;
				changecol=1;
			}
			colbText.setText(Integer.toString((int)object[selectobject].col.b));
			colbScr.setValue((int)object[selectobject].col.b);
		}
		//性質テキストフィールド
		else if(e.getSource()==reflectText){
			value=Double.valueOf(reflectText.getText()).doubleValue();
			if(Double.isNaN(value)==false && value>=0 && value<=1){
				object[selectobject].reflect_rate=value;
			}
			reflectText.setText(Double.toString(object[selectobject].reflect_rate));
			reflectScr.setValue((int)(object[selectobject].reflect_rate*100));
		}else if(e.getSource()==lusterText){
			value=Double.valueOf(lusterText.getText()).doubleValue();
			if(Double.isNaN(value)==false && value>=1 && value<=10){
				object[selectobject].reflect_luster=(int)value;
			}
			lusterText.setText(Integer.toString(object[selectobject].reflect_luster));
			lusterScr.setValue(object[selectobject].reflect_luster);
		}else if(e.getSource()==refractText){
			value=Double.valueOf(refractText.getText()).doubleValue();
			if(Double.isNaN(value)==false && value>=1 && value<=3){
				object[selectobject].refract_rate=value;
			}
			refractText.setText(Double.toString(object[selectobject].refract_rate));
			refractScr.setValue((int)(object[selectobject].refract_rate*100));
		}
	}
	
	//チョイス、チェックボックス
	public void itemStateChanged(ItemEvent e){
		if(e.getSource()==moverotChoice){
			moverot=moverotChoice.getSelectedIndex();
		}
		
		if(selectobject==-1) return;
		if(rendering==1) return;
		
		if(e.getSource()==diffuseCheck){
			if(e.getStateChange()==e.SELECTED)
				object[selectobject].reflectdiffuse=1;
			else
				object[selectobject].reflectdiffuse=0;
		}else if(e.getSource()==specularCheck){
			if(e.getStateChange()==e.SELECTED)
				object[selectobject].reflectspecular=1;
			else
				object[selectobject].reflectspecular=0;
		}else if(e.getSource()==transparentCheck){
			if(e.getStateChange()==e.SELECTED)
				object[selectobject].refract=1;
			else
				object[selectobject].refract=0;
		}
	}
	
	//スクロールバー
	public void adjustmentValueChanged(AdjustmentEvent e){
		if(selectobject==-1) return;
		if(rendering==1) return;
		
		//色
		if(e.getSource()==colrScr){
			object[selectobject].col.r=colrScr.getValue();
			colrText.setText(Integer.toString((int)object[selectobject].col.r));
			changecol=1;
		}else if(e.getSource()==colgScr){
			object[selectobject].col.g=colgScr.getValue();
			colgText.setText(Integer.toString((int)object[selectobject].col.g));
			changecol=1;
		}else if(e.getSource()==colbScr){
			object[selectobject].col.b=colbScr.getValue();
			colbText.setText(Integer.toString((int)object[selectobject].col.b));
			changecol=1;
		}
		//性質
		else if(e.getSource()==reflectScr){
			object[selectobject].reflect_rate=reflectScr.getValue()/100.0;
			reflectText.setText(Double.toString(object[selectobject].reflect_rate));
		}else if(e.getSource()==lusterScr){
			object[selectobject].reflect_luster=lusterScr.getValue();
			lusterText.setText(Integer.toString(object[selectobject].reflect_luster));
		}else if(e.getSource()==refractScr){
			object[selectobject].refract_rate=refractScr.getValue()/100.0;
			refractText.setText(Double.toString(object[selectobject].refract_rate));
		}
	}
	
	//マウス押し
	public void mousePressed(MouseEvent e){
		if(rendering==1) return;
		
		mouseclick.x=e.getX();
		mouseclick.y=e.getY();
		mousedrag.x=0;
		mousedrag.y=0;
		
		st_xyz p[] = new st_xyz[2];
		p[0] = new st_xyz(); p[1] = new st_xyz();
		
		p[0].substitute(eyept);
		p[1].x=mouseclick.x-bufLen/2;
		p[1].y=bufLen/2-mouseclick.y;
		p[1].z=100;
		
	/*	Rotation(p,2,-eyeptrot.x,-eyeptrot.y,-eyeptrot.z);
		Translation(p,2,0,0,0);*/
		
		selectobject=FirstHit(p[0],p[1]);
		
		if(selectobject<2) selectobject=-1;	//空と地面は選択しない
		
		if(selectobject>-1){
			//値設定
			//色スクロールバー
			colrScr.setValue((int)object[selectobject].col.r);
			colgScr.setValue((int)object[selectobject].col.g);
			colbScr.setValue((int)object[selectobject].col.b);
			//色テキストフィールド
			colrText.setText(Integer.toString((int)object[selectobject].col.r));
			colgText.setText(Integer.toString((int)object[selectobject].col.g));
			colbText.setText(Integer.toString((int)object[selectobject].col.b));
			
			//チェックボックス
			if(object[selectobject].reflectdiffuse==1) diffuseCheck.setState(true);
			else diffuseCheck.setState(false);
			if(object[selectobject].reflectspecular==1) specularCheck.setState(true);
			else specularCheck.setState(false);
			if(object[selectobject].refract==1) transparentCheck.setState(true);
			else transparentCheck.setState(false);
			
			//性質スクロールバー
			reflectScr.setValue((int)(object[selectobject].reflect_rate*100));
			lusterScr.setValue(object[selectobject].reflect_luster);
			refractScr.setValue((int)(object[selectobject].refract_rate*100));
			//性質テキストフィールド
			reflectText.setText(Double.toString(object[selectobject].reflect_rate));
			lusterText.setText(Integer.toString(object[selectobject].reflect_luster));
			refractText.setText(Double.toString(object[selectobject].refract_rate));
		}
		
		changecol=0;
	}
	
	//マウスドラッグ
	public void mouseDragged(MouseEvent e){
		if(rendering==1 || selectobject<0) return;
		
		mousedrag.x=mouseclick.x-e.getX();
		mousedrag.y=mouseclick.y-e.getY();
		
		switch(moverot){
		case 0:
			object[selectobject].vd.x-=mousedrag.x;
			object[selectobject].vd.z-=mousedrag.y;
			break;
		case 1:
			object[selectobject].roty-=mousedrag.x;
			object[selectobject].rotx-=mousedrag.y;
			break;
		}
		
		mouseclick.x=e.getX();
		mouseclick.y=e.getY();
		
		changecol=0;
	}
	
	//マウス放し
	public void mouseReleased(MouseEvent e){}
	//マウスその他
	public void mouseClicked(MouseEvent e){}
	public void mouseEntered(MouseEvent e){}
	public void mouseExited(MouseEvent e){}
	public void mouseMoved(MouseEvent e){}
	
	
	//開始
	public void start(){
		if(th==null){
			th=new Thread(this);
			th.start();
		}
	}
	
	//実行
	public void run(){
		while(true){
			try{
				repaint();
				th.sleep(10);
			}catch(InterruptedException e){}
		}
	}
	
	//停止
	public void stop(){
		if(th!=null){
			th.stop();
			th=null;
		}
	}
	
	public void update(Graphics g){
		paint(g);
	}

	
	//メイン、描画
	public void paint(Graphics g){
		int i;
		
		//アフィン変換
		for(i=0;i<LIGHT_NUMBER;i++){
			lightsource[i].setV();
			
			Scaling(lightsource[i].v,lightsource[i].vertexnumber,lightsource[i].scale.x,lightsource[i].scale.y,lightsource[i].scale.z);
			Rotation(lightsource[i].v,lightsource[i].vertexnumber,lightsource[i].rotx,lightsource[i].roty,lightsource[i].rotz);
			Translation(lightsource[i].v,lightsource[i].vertexnumber,lightsource[i].vd.x,lightsource[i].vd.y,lightsource[i].vd.z);
		}
		
		for(i=0;i<OBJECT_NUMBER;i++){
			object[i].setCenter();
			object[i].setV();
			
			switch(object[i].type){
			case 1:
			case 2:
			case 5:	//2次曲面
				Scaling(object[i].axis,object[i].scale.x,object[i].scale.y,object[i].scale.z);
				Rotation(object[i].center,object[i].rotx,object[i].roty,object[i].rotz);
				Translation(object[i].center,object[i].vd.x,object[i].vd.y,object[i].vd.z);
				calculateCoefficient(object[i]);
				break;
			case 20:	//多面体
				Scaling(object[i].v,object[i].vertexnumber,object[i].scale.x,object[i].scale.y,object[i].scale.z);
				Rotation(object[i].v,object[i].vertexnumber,object[i].rotx,object[i].roty,object[i].rotz);
				Translation(object[i].v,object[i].vertexnumber,object[i].vd.x,object[i].vd.y,object[i].vd.z);
				break;
			}
		}
		
		if(selectobject==-1 || rendering==1){
			colrScr.setEnabled(false);
			colgScr.setEnabled(false);
			colbScr.setEnabled(false);
			colrText.setEnabled(false);
			colgText.setEnabled(false);
			colbText.setEnabled(false);
			diffuseCheck.setEnabled(false);
			specularCheck.setEnabled(false);
			transparentCheck.setEnabled(false);
			reflectScr.setEnabled(false);
			lusterScr.setEnabled(false);
			refractScr.setEnabled(false);
			reflectText.setEnabled(false);
			lusterText.setEnabled(false);
			refractText.setEnabled(false);
		}else{
			colrScr.setEnabled(true);
			colgScr.setEnabled(true);
			colbScr.setEnabled(true);
			colrText.setEnabled(true);
			colgText.setEnabled(true);
			colbText.setEnabled(true);
			diffuseCheck.setEnabled(true);
			specularCheck.setEnabled(true);
			transparentCheck.setEnabled(true);
			
			reflectScr.setEnabled(true);
			reflectText.setEnabled(true);
			if(specularCheck.getState()==true){
				lusterScr.setEnabled(true);
				lusterText.setEnabled(true);
			}else{
				lusterScr.setEnabled(false);
				lusterText.setEnabled(false);
			}
			if(transparentCheck.getState()==true){
				refractScr.setEnabled(true);
				refractText.setEnabled(true);
			}else{
				refractScr.setEnabled(false);
				refractText.setEnabled(false);
			}
		}
		
		if(rendering==0){	//ワイヤーフレーム
			st_xyz p[] = new st_xyz[2];
			p[0] = new st_xyz(); p[1] = new st_xyz();
			st_xyz center[] = new st_xyz[1];
			center[0] = new st_xyz();
			
			p[0].substitute(eyept);
			
			Rotation(p,2,eyeptrot.x,eyeptrot.y,eyeptrot.z);
			Translation(p,2,0,0,0);
			
			for(i=0;i<OBJECT_NUMBER;i++){	//全ての物体を視野変換
				ViewpointTrans(object[i].v,object[i].vertexnumber,p[0],p[1]);
				
				center[0].substitute(object[i].center);
				ViewpointTrans(center,1,p[0],p[1]);
				object[i].center.substitute(center[0]);
			}
			
			gg.clearRect(0,0,bufLen+100,bufLen);
			wireframeImage(gg);
			g.drawImage(doubleBuf,0,0,this);
			
		}else{	//レイトレーシング
			if(rendy<=bufLen){
				
				for(i=0;i<LIGHT_NUMBER;i++){
					toPointLight(lightsource[i]);
				}
				
				//処理
				renderImage(g,gg);
				rendy++;
				
				//バックバッファの画像を描画
				g.drawImage(doubleBuf,0,0,this);
				//文字描画
				g.setColor(Color.red);
				g.drawString("Now Rendering...",5,bufLen-5);
				
				light.removeAllElements();
				
			}else{
				g.drawImage(doubleBuf,0,0,this);
				
				g.setColor(Color.red);
				g.drawString("Rendering Finished.",5,bufLen-5);
			}
		}
	}
	
	public void wireframeImage(Graphics g){
		int i,j,k,vnum;
		float s,d;
		s=eyept.z-100;
		d=eyept.z;
		int x,y,width,height;
		
		//物体描画
		for(i=0;i<OBJECT_NUMBER;i++){
			if(i==selectobject){
				g.setColor(Color.red);
			}else{
				if(object[i].reflectdiffuse==1)
					g.setColor(new Color((int)object[i].col.r,(int)object[i].col.g,(int)object[i].col.b));
				else
					g.setColor(Color.black);
			}
			switch(object[i].type){
			case 1:	//球
				x=(int)( object[i].center.x-object[i].radius );
				y=(int)( object[i].center.y+object[i].radius );
				width=height=(int)( 2.0*object[i].radius );
				x=(int)( s/(d-object[i].center.z)*x );	//透視投影
				y=(int)( s/(d-object[i].center.z)*y );
				width=height=(int)( s/(d-object[i].center.z)*width );
				x=bufLen/2+(int)Math.rint(x);
				y=bufLen/2-(int)Math.rint(y);
				if(changecol==1 && i==selectobject){
					g.setColor(new Color((int)object[i].col.r,(int)object[i].col.g,(int)object[i].col.b));
					g.fillOval(x,y,width,height);
				}else{
					g.drawOval(x,y,width,height);
				}
				break;
			case 2:	//楕円
				x=(int)( object[i].center.x-object[i].axis.x );
				y=(int)( object[i].center.y+object[i].axis.y );
				width=(int)( 2.0*object[i].axis.x );
				height=(int)( 2.0*object[i].axis.y );
				x=(int)( s/(d-object[i].center.z)*x );	//透視投影
				y=(int)( s/(d-object[i].center.z)*y );
				width=(int)( s/(d-object[i].center.z)*width );
				height=(int)( s/(d-object[i].center.z)*height );
				x=bufLen/2+(int)Math.rint(x);
				y=bufLen/2-(int)Math.rint(y);
				if(changecol==1 && i==selectobject){
					g.setColor(new Color((int)object[i].col.r,(int)object[i].col.g,(int)object[i].col.b));
					g.fillOval(x,y,width,height);
				}else{
					g.drawOval(x,y,width,height);
				}
				break;
			case 20:	//多面体
				for(j=0;j<object[i].surfacenumber;j++){
					vnum=object[i].svtotal[j];
					int xx[] = new int[vnum];
					int yy[] = new int[vnum];
					int zz[] = new int[vnum];
					for(k=0;k<vnum;k++){
						xx[k]=(int)object[i].v[ object[i].svnumber[j][k] ].x;
						yy[k]=(int)object[i].v[ object[i].svnumber[j][k] ].y;
						zz[k]=(int)object[i].v[ object[i].svnumber[j][k] ].z;
						xx[k]=(int)( s/(d-zz[k])*xx[k] );	//透視投影
						yy[k]=(int)( s/(d-zz[k])*yy[k] );
						xx[k]=bufLen/2+(int)Math.rint(xx[k]);
						yy[k]=bufLen/2-(int)Math.rint(yy[k]);
					}
					if(changecol==1 && i==selectobject){
						g.setColor(new Color((int)object[i].col.r,(int)object[i].col.g,(int)object[i].col.b));
						g.fillPolygon(xx,yy,vnum);
					}else{
						g.drawPolygon(xx,yy,vnum);
					}
				}
				break;
			}
		}
		
		//光源描画
		for(i=0;i<LIGHT_NUMBER;i++){
			g.setColor(Color.magenta);
			switch(lightsource[i].type){
			case 1:	//点光源
				x=(int)( lightsource[i].pos.x-5 );
				y=(int)( lightsource[i].pos.y-5 );
				width=height=10;
				x=(int)( s/(d-lightsource[i].pos.z)*x );	//透視投影
				y=(int)( s/(d-lightsource[i].pos.z)*y );
				width=height=(int)( s/(d-lightsource[i].pos.z)*width );
				x=bufLen/2+(int)Math.rint(x);
				y=bufLen/2-(int)Math.rint(y);
				g.drawOval(x,y,width,height);
				break;
			case 2:	//面光源
				for(j=0;j<lightsource[i].surfacenumber;j++){
					vnum=lightsource[i].svtotal[j];
					int xx[] = new int[vnum];
					int yy[] = new int[vnum];
					int zz[] = new int[vnum];
					for(k=0;k<vnum;k++){
						xx[k]=(int)lightsource[i].v[ lightsource[i].svnumber[j][k] ].x;
						yy[k]=(int)lightsource[i].v[ lightsource[i].svnumber[j][k] ].y;
						zz[k]=(int)lightsource[i].v[ lightsource[i].svnumber[j][k] ].z;
						xx[k]=(int)( s/(d-zz[k])*xx[k] );	//透視投影
						yy[k]=(int)( s/(d-zz[k])*yy[k] );
						xx[k]=bufLen/2+(int)Math.rint(xx[k]);
						yy[k]=bufLen/2-(int)Math.rint(yy[k]);
					}
					g.drawPolygon(xx,yy,vnum);
				}
				break;
			}
		}
	}
	
	public void renderImage(Graphics g,Graphics gg){
		
		st_xyz p[] = new st_xyz[2];
		p[0] = new st_xyz(); p[1] = new st_xyz();
		st_color col = new st_color();
		
	//	for(rendy=0;rendy<=bufLen;rendy++){
			for(rendx=0;rendx<=bufLen;rendx++){
				p[0].substitute(eyept);
				//スクリーン上の座標 x,y
				//投影面 x=x-bufLen/2, y=bufLen/2-y, z=100
				p[1].x=rendx-bufLen/2;
				p[1].y=bufLen/2-rendy;
				p[1].z=100;
				
				Rotation(p,2,-eyeptrot.x,-eyeptrot.y,-eyeptrot.z);
				Translation(p,2,0,0,0);
				
				col=calculate_pixel_value( p[0],p[1] );	/* i,jにおける輝度値の計算*/ 
				
				gg.setColor(new Color((int)col.r,(int)col.g,(int)col.b));
				gg.drawLine(rendx,rendy,rendx,rendy);
			}
	//	} 
	}
	
	int Surface;	//CrosspointPlaneで当たった面の番号を入れる
	
	/* レイトレーシング。視点fromから座標toへ光線を追跡する。 */
	public st_color calculate_pixel_value(st_xyz from,st_xyz to){
		int ii,i,j,k,hit,findcrossp,node,nodenext=0,nodeparent=0,nodechild,depth;
		double distance,distancetemp,costheta,cosgamma,keisuu=0;
		
		int objnumber=0,surface=0;
		
		//反射する光の割合を求めるのに使用
		double costheta1,sintheta2,theta1,theta2,n1,n2;
		
		st_xyz p1 = new st_xyz();
		st_xyz p2 = new st_xyz();
		st_xyz crossp = new st_xyz();
		st_xyz crosstemp = new st_xyz();
		st_xyz normal = new st_xyz();
		st_xyz normaltemp = new st_xyz();
		st_xyz in = new st_xyz();
		st_xyz reflect_vec = new st_xyz();
		st_xyz refract_vec = new st_xyz();
		
		Refract_rate_list refr_list = new Refract_rate_list();	//屈折率管理リスト
		refr_list.add(0,object[0].refract_rate);
		
		Raytrace ray[] = new Raytrace[TREEDATA_NUMBER];	//光線オブジェクト
		for(i=0;i<TREEDATA_NUMBER;i++){
			ray[i] = new Raytrace();
		}
		
		Light lighttemp = new Light();
		
		st_color col_return = new st_color();
		
		ray[0].cross.substitute(from);	//鏡面反射のため
		
		ray[0].lr=1;
		ray[1].lr=1;
		
		p1.substitute(from);
		p2.substitute(to);
		
		//視点から最初の物体までの処理
		distance=10000;
		findcrossp=0;
		for(ii=0;ii<OBJECT_NUMBER;ii++){
			hit=0;
			
			switch(object[ii].type){
			case 1:
			case 2:
			case 5:
				hit=CrosspointSphere(object[ii],p1,p2,crosstemp,normaltemp);
				break;
			case 20:
				hit=CrosspointPlane(object[ii],p1,p2,crosstemp,normaltemp);
				break;
			}
			
			if(hit==1){	//交点あり
				distancetemp=DistancePointPoint(p1,crosstemp);
				
				if(distancetemp<=distance){
					findcrossp=1;
					
					distance=distancetemp;
					objnumber=ii;
					crossp.substitute(crosstemp);
					normal.substitute(normaltemp);
					surface=Surface;
				}
			}
		}
		
		if(findcrossp==1){	//交点あり
			ray[0].reflect_dist=distance;
			ray[1].objnumber=objnumber;
			ray[1].cross.substitute(crossp);
			ray[1].normal.substitute(normal);
			ray[1].objcol.substitute(object[objnumber].col);
			ray[1].reflectdiffuse=object[objnumber].reflectdiffuse; ray[1].reflectspecular=object[objnumber].reflectspecular;
			ray[1].refract=object[objnumber].refract;
			ray[1].reflect_rate=object[objnumber].reflect_rate; ray[1].reflect_luster=object[objnumber].reflect_luster;
			ray[1].refract_rate=object[objnumber].refract_rate;
			ray[1].reflect_checked=0; ray[1].refract_checked=0;
			
			//テクスチャーマッピングされていればテクスチャーの色を得る
			if(object[objnumber].texturemapped==1)
				ray[1].objcol=TextureColor(object[objnumber],crossp,surface);
			
			//入射光の単位ベクトルを求める
			in=subVector(crossp,p1);
			in.normalize();
			
			if(ray[1].reflectspecular==1){	//反射方向ベクトルを求める
				reflect_vec=ReflectVector(in,normal);
				ray[1].reflect_vec.substitute(reflect_vec);
			}
			
			if(ray[1].refract==1){
				n1=refr_list.findtop(); n2=ray[1].refract_rate;
				
				//屈折方向ベクトルを求める
				refract_vec=RefractVector(in, normal, n1, n2);
				refr_list.add(objnumber,ray[1].refract_rate);
				
				ray[1].refract_vec.substitute(refract_vec);
				
				//屈折せずに反射する光の割合を求める
				costheta1=VectorAngle(in,normal);
				if(costheta1<0) costheta1=-costheta1;
				sintheta2=n1/n2*Math.sqrt(1-costheta1*costheta1);
				theta1=Math.acos(costheta1);
				theta2=Math.asin(sintheta2);
				
				ray[1].k=( (Math.sin(theta1-theta2)*Math.sin(theta1-theta2))/(Math.sin(theta1+theta2)*Math.sin(theta1+theta2)) +
						   (Math.tan(theta1-theta2)*Math.tan(theta1-theta2))/(Math.tan(theta1+theta2)*Math.tan(theta1+theta2)) )/2;
			}
			
		}else{	//交点なし
			col_return.r=0; col_return.g=0; col_return.b=0;
			return col_return;
		}
		
		
		//それ以降
		node=1;
		depth=1;
		while(depth>0){
			
			//左の節（反射）が未チェック。反射光の追跡。
			if(ray[node].reflectspecular>0 && ray[node].reflect_checked==0){
				
				if(depth>=TRACE_TIMES){		//葉まできた
					ray[node].reflect_end=1;
					ray[node].reflect_checked=1;
					ray[node].reflect_dist=10000;
					continue;	//同じnodeをもう一度やり直す
				}
				
				p1.substitute(ray[node].cross);
				p2=addVector(ray[node].cross,ray[node].reflect_vec);
				
				distance=10000;
				findcrossp=0;
				for(ii=0;ii<OBJECT_NUMBER;ii++){
					hit=0;
					
					switch(object[ii].type){
					case 1:
					case 2:
					case 5:
						hit=CrosspointSphere(object[ii],p1,p2,crosstemp,normaltemp);
						break;
					case 20:
						hit=CrosspointPlane(object[ii],p1,p2,crosstemp,normaltemp);
						break;
					}
					
					if(hit==1){	//交点あり
						distancetemp=DistancePointPoint(p1,crosstemp);
						
						if(distancetemp<=distance){
							findcrossp=1;
							
							distance=distancetemp;
							objnumber=ii;
							crossp.substitute(crosstemp);
							normal.substitute(normaltemp);
							surface=Surface;
						}
					}
				}
				
				if(findcrossp==1){	//交点あり
					nodenext=node*2;
					depth++;
					
					//光線が物体内にあれば、法線ベクトルを逆にする
					if(refr_list.check(objnumber)==1)
						normal.inverse();
					
					ray[node].reflect_dist=distance;
					ray[nodenext].objnumber=objnumber;
					ray[nodenext].cross.substitute(crossp);
					ray[nodenext].normal.substitute(normal);
					ray[nodenext].objcol.substitute(object[objnumber].col);
					ray[nodenext].reflectdiffuse=object[objnumber].reflectdiffuse; ray[nodenext].reflectspecular=object[objnumber].reflectspecular;
					ray[nodenext].refract=object[objnumber].refract;
					ray[nodenext].reflect_rate=object[objnumber].reflect_rate; ray[nodenext].reflect_luster=object[objnumber].reflect_luster;
					ray[nodenext].refract_rate=object[objnumber].refract_rate;
					ray[nodenext].reflect_checked=0; ray[nodenext].refract_checked=0;
					
					//テクスチャーマッピングされていればテクスチャーの色を得る
					if(object[objnumber].texturemapped==1)
						ray[nodenext].objcol=TextureColor(object[objnumber],crossp,surface);
					
					//入射光の単位ベクトルを求める。求めずにin.x=ray[node].reflect_vec.xとしてもいい
					in=subVector(crossp,p1);
					in.normalize();
					
					if(ray[nodenext].reflectspecular==1){	//反射方向ベクトルを求める
						reflect_vec=ReflectVector(in,normal);
						ray[nodenext].reflect_vec.substitute(reflect_vec);
					}
					
					if(ray[nodenext].refract==1){
						//屈折方向ベクトルを求める
						if(refr_list.delete(objnumber)==0){	//物体内に光線が入る
							n1=refr_list.findtop(); n2=ray[nodenext].refract_rate;
							
							refract_vec=RefractVector(in, normal, n1, n2);
							refr_list.add(objnumber,ray[nodenext].refract_rate);
						}else{	//物体内から光線が出る
							n1=ray[nodenext].refract_rate; n2=refr_list.findtop();
							
							refract_vec=RefractVector(in, normal, n1, n2);
						}
						
						ray[nodenext].refract_vec.substitute(refract_vec);
						
						//屈折せずに反射する光の割合を求める
						costheta1=VectorAngle(in,normal);
						if(costheta1<0) costheta1=-costheta1;
						sintheta2=n1/n2*Math.sqrt(1-costheta1*costheta1);
						theta1=Math.acos(costheta1);
						theta2=Math.asin(sintheta2);
				
						ray[nodenext].k=( (Math.sin(theta1-theta2)*Math.sin(theta1-theta2))/(Math.sin(theta1+theta2)*Math.sin(theta1+theta2)) +
										  (Math.tan(theta1-theta2)*Math.tan(theta1-theta2))/(Math.tan(theta1+theta2)*Math.tan(theta1+theta2)) )/2;
					}
					
					ray[node].reflect_checked=1;
					ray[nodenext].lr=1;
					
				}else{	//交点なし
					ray[node].reflect_dist=10000;
					
					ray[node].reflect_checked=1;
					ray[node].reflect_end=1;
					continue;	//同じnodeをもう一度やり直す
				}
				
				
			//右の節（屈折）が未チェック。屈折光の追跡。
			}else if(ray[node].refract>0 && ray[node].refract_checked==0){
				
				if(depth>=TRACE_TIMES){		//葉まできた
					ray[node].refract_end=1;
					ray[node].refract_checked=1;
					ray[node].refract_dist=10000;
					continue;
				}
				
				p1.substitute(ray[node].cross);
				p2=addVector(ray[node].cross,ray[node].refract_vec);
				
				distance=10000;
				findcrossp=0;
				for(ii=0;ii<OBJECT_NUMBER;ii++){
					hit=0;
					
					switch(object[ii].type){
					case 1:
					case 2:
					case 5:
						hit=CrosspointSphere(object[ii],p1,p2,crosstemp,normaltemp);
						break;
					case 20:
						hit=CrosspointPlane(object[ii],p1,p2,crosstemp,normaltemp);
						break;
					}
					
					if(hit==1){	//交点あり
						distancetemp=DistancePointPoint(p1,crosstemp);
						
						if(distancetemp<=distance){
							findcrossp=1;
							
							distance=distancetemp;
							objnumber=ii;
							crossp.substitute(crosstemp);
							normal.substitute(normaltemp);
							surface=Surface;
						}
					}
				}
				
				if(findcrossp==1){	//交点あり
					nodenext=node*2+1;
					depth++;
					
					//光線が物体内にあれば、法線ベクトルを逆にする
					if(refr_list.check(objnumber)==1)
						normal.inverse();
					
					ray[node].refract_dist=distance;
					ray[nodenext].objnumber=objnumber;
					ray[nodenext].cross.substitute(crossp);
					ray[nodenext].normal.substitute(normal);
					ray[nodenext].objcol.substitute(object[objnumber].col);
					ray[nodenext].reflectdiffuse=object[objnumber].reflectdiffuse; ray[nodenext].reflectspecular=object[objnumber].reflectspecular;
					ray[nodenext].refract=object[objnumber].refract;
					ray[nodenext].reflect_rate=object[objnumber].reflect_rate; ray[nodenext].reflect_luster=object[objnumber].reflect_luster;
					ray[nodenext].refract_rate=object[objnumber].refract_rate;
					ray[nodenext].reflect_checked=0; ray[nodenext].refract_checked=0;
					
					//テクスチャーマッピングされていればテクスチャーの色を得る
					if(object[objnumber].texturemapped==1)
						ray[nodenext].objcol=TextureColor(object[objnumber],crossp,surface);
					
					//入射光の単位ベクトルを求める。求めずにin.x=ray[node].refract_vec.xとしてもいい
					in=subVector(crossp,p1);
					in.normalize();
					
					if(ray[nodenext].reflectspecular==1){	//反射方向ベクトルを求める
						reflect_vec=ReflectVector(in,normal);
						ray[nodenext].reflect_vec.substitute(reflect_vec);
					}
					
					if(ray[nodenext].refract==1){
						//屈折方向ベクトルを求める
						if(refr_list.delete(objnumber)==0){	//物体内に光線が入る
							n1=refr_list.findtop(); n2=ray[nodenext].refract_rate;
							
							refract_vec=RefractVector(in, normal, n1, n2);
							refr_list.add(objnumber,ray[nodenext].refract_rate);
						}else{	//物体内から光線が出る
							n1=ray[nodenext].refract_rate; n2=refr_list.findtop();
							
							refract_vec=RefractVector(in, normal, n1, n2);
						}
						
						ray[nodenext].refract_vec.substitute(refract_vec);
						
						//屈折せずに反射する光の割合を求める
						costheta1=VectorAngle(in,normal);
						if(costheta1<0) costheta1=-costheta1;
						sintheta2=n1/n2*Math.sqrt(1-costheta1*costheta1);
						theta1=Math.acos(costheta1);
						theta2=Math.asin(sintheta2);
				
						ray[nodenext].k=( (Math.sin(theta1-theta2)*Math.sin(theta1-theta2))/(Math.sin(theta1+theta2)*Math.sin(theta1+theta2)) +
										  (Math.tan(theta1-theta2)*Math.tan(theta1-theta2))/(Math.tan(theta1+theta2)*Math.tan(theta1+theta2)) )/2;
					}
					
					ray[node].refract_checked=1;
					ray[nodenext].lr=2;
					
				}else{	//交点なし
					ray[node].refract_dist=10000;
					
					ray[node].refract_checked=1;
					ray[node].refract_end=1;
					continue;
				}
				
				
			//両方の子チェック済み。光の色の計算。
			}else{
				if(ray[node].lr==1) nodenext=node/2;
				else if(ray[node].lr==2) nodenext=(node-1)/2;
				if(node==1) nodenext=0;
				
				
				if(ray[node].reflectdiffuse==1){	//拡散反射
					
					//光源からの光
					for(i=0;i<light.size();i++){
						lighttemp=(Light)light.elementAt(i);
						if(lighttemp.type!=1)
							continue;	//点光源のみ
						
						//光源からの光が物体に当たっているか調べる
						//まず光線と交差する物体の中で最も光源に近いものを調べる
						p1.substitute(lighttemp.pos);
						p2.substitute(ray[node].cross);
						
						objnumber=FirstHit(p1,p2);
						
						//光源と交差する物体で最も近いものが注目している物体
						//光源からの光が物体に当たっていた
						if(objnumber==ray[node].objnumber){
							
							//光からの入射光と反射面の法線ベクトルを求める
							in=subVector(lighttemp.pos,ray[node].cross);
							normal.substitute(ray[node].normal);
							costheta=VectorAngle(in,normal);	//入射光と法線のなす角
							if(costheta<0) costheta=0;
							distance=in.getSize();	//交点から光源までの距離
							
							keisuu=lightDecreaseRate(distance)*ray[node].reflect_rate*costheta;
							
						}else{	//光が物体に当たっていない
							keisuu=0;
						}
						
						ray[node].col.r+=keisuu*(lighttemp.col.r/2+ray[node].objcol.r)/lighttemp.division;
						ray[node].col.g+=keisuu*(lighttemp.col.g/2+ray[node].objcol.g)/lighttemp.division;
						ray[node].col.b+=keisuu*(lighttemp.col.b/2+ray[node].objcol.b)/lighttemp.division;
					}
				}
				
				
				if(ray[node].reflectspecular==1){	//鏡面反射
					
					//光源からの光
					for(i=0;i<light.size();i++){
						lighttemp=(Light)light.elementAt(i);
						if(lighttemp.type!=1)
							continue;	//点光源のみ
						
						//光源からの光が物体に当たっているか調べる
						//まず光線と交差する物体の中で最も光源に近いものを調べる
						p1.substitute(lighttemp.pos);
						p2.substitute(ray[node].cross);
						
						objnumber=FirstHit(p1,p2);
						
						//光源と交差する物体で最も近いものが注目している物体
						//光源からの光が物体に当たっていた
						if(objnumber==ray[node].objnumber){
							
							//光からの入射光と反射面の法線ベクトルを求める
							in=subVector(lighttemp.pos,ray[node].cross);
							normal.substitute(ray[node].normal);
							costheta=VectorAngle(in,normal);	//入射光と法線のなす角
							if(costheta<0) costheta=0;
							distance=in.getSize();	//交点から光源までの距離
							
							if(ray[node].lr==1) nodeparent=node/2;//nodeparent使わずにnodenextでいいかも
							else if(ray[node].lr==2) nodeparent=(node-1)/2;
							if(node==1) nodeparent=0;
							//入射光の単位ベクトルを求める
							in=subVector(ray[node].cross,lighttemp.pos);
							in.normalize();
							normal.substitute(ray[node].normal);
							//反射光ベクトルを求める
							reflect_vec=ReflectVector(in,normal);
							//視線方向ベクトル
							p1=subVector(ray[nodeparent].cross,ray[node].cross);
							//反射光と視線方向のなす角
							cosgamma=VectorAngle(reflect_vec,p1);
							if(cosgamma<0) cosgamma=0;
							keisuu=lightDecreaseRate(distance)*Math.pow(cosgamma,ray[node].reflect_luster);
						}else{
							keisuu=0;
						}
						
						ray[node].col.r+=ray[node].k*keisuu*lighttemp.col.r/lighttemp.division;
						ray[node].col.g+=ray[node].k*keisuu*lighttemp.col.g/lighttemp.division;
						ray[node].col.b+=ray[node].k*keisuu*lighttemp.col.b/lighttemp.division;
					}
					
					if(ray[node].reflect_end==0){	//探索の末端ではない
						//反射先の物体からの光
						nodechild=node*2;
						//入射光と法線のなす角
						in=subVector(ray[nodechild].cross,ray[node].cross);
						normal.substitute(ray[node].normal);
						costheta=VectorAngle(in,normal);
						if(costheta<0) costheta=0;
						
						if(ray[node].lr==1) nodeparent=node/2;
						else if(ray[node].lr==2) nodeparent=(node-1)/2;
						if(node==1) nodeparent=0;
						//入射光の単位ベクトルを求める
						in=subVector(ray[node].cross,ray[nodechild].cross);
						in.normalize();
						normal.substitute(ray[node].normal);
						//反射光ベクトルを求める
						reflect_vec=ReflectVector(in,normal);
						//視線方向ベクトル
						p1=subVector(ray[nodeparent].cross,ray[node].cross);
						//反射光と視線方向のなす角
						cosgamma=VectorAngle(reflect_vec,p1);
						if(cosgamma<0) cosgamma=0;
						keisuu=lightDecreaseRate(ray[node].reflect_dist)*Math.pow(cosgamma,ray[node].reflect_luster);
						
						/*keisuu=(1-Dec)// /(ray[node].reflect_dist*ray[node].reflect_dist/30000)
							   *ray[node].reflect_rate;*/
						
						ray[node].col.r+=ray[node].k*keisuu*ray[nodechild].col.r;
						ray[node].col.g+=ray[node].k*keisuu*ray[nodechild].col.g;
						ray[node].col.b+=ray[node].k*keisuu*ray[nodechild].col.b;
					}
				}
				
				
				if(ray[node].refract==1){	//屈折
					if(ray[node].refract_end==0){	//探索の末端ではない
						nodechild=node*2+1;
						
						keisuu=lightDecreaseRate(ray[node].refract_dist);
						
						ray[node].col.r+=(1-ray[node].k)*keisuu*ray[nodechild].col.r;
						ray[node].col.g+=(1-ray[node].k)*keisuu*ray[nodechild].col.g;
						ray[node].col.b+=(1-ray[node].k)*keisuu*ray[nodechild].col.b;
					}
				}
				
				
				//環境光
				if(ray[node].reflectdiffuse==1){	//拡散反射
					ray[node].col.r+=ray[node].reflect_rate*(envlight.r/2+ray[node].objcol.r)/5;
					ray[node].col.g+=ray[node].reflect_rate*(envlight.g/2+ray[node].objcol.g)/5;
					ray[node].col.b+=ray[node].reflect_rate*(envlight.b/2+ray[node].objcol.b)/5;
				}else{	//鏡面反射
					ray[node].col.r+=ray[node].reflect_rate*envlight.r/5;
					ray[node].col.g+=ray[node].reflect_rate*envlight.g/5;
					ray[node].col.b+=ray[node].reflect_rate*envlight.b/5;
				}
				
				if(ray[node].col.r>255) ray[node].col.r=255;
				if(ray[node].col.g>255) ray[node].col.g=255;
				if(ray[node].col.b>255) ray[node].col.b=255;
					
				depth--;
			}
			
			node=nodenext;
		}
		
		col_return=ray[1].col;
		return col_return;
	}
	
	
	/* アフィン変換:回転 */
	public void Rotation(st_xyz v[],int vertexnumber,double rotx,double roty,double rotz){
		float x,y,z,sinX,cosX,sinY,cosY,sinZ,cosZ;
		sinX=(float)Math.sin(rotx*ToRAD); cosX=(float)Math.cos(rotx*ToRAD);
		sinY=(float)Math.sin(roty*ToRAD); cosY=(float)Math.cos(roty*ToRAD);
		sinZ=(float)Math.sin(rotz*ToRAD); cosZ=(float)Math.cos(rotz*ToRAD);

		for(int i=0;i<vertexnumber;i++){
			//x軸方向回転
			y=v[i].y*cosX - v[i].z*sinX;
			z=v[i].y*sinX + v[i].z*cosX;
			v[i].y=y; v[i].z=z;

			//y軸方向回転
			x=v[i].x*cosY + v[i].z*sinY;
			z=-v[i].x*sinY + v[i].z*cosY;
			v[i].x=x; v[i].z=z;

			//z軸方向回転
			x=v[i].x*cosZ - v[i].y*sinZ;
			y=v[i].x*sinZ + v[i].y*cosZ;
			v[i].x=x; v[i].y=y; v[i].z=z;
		}
	}
	
	public void Rotation(st_xyz pos,double rotx,double roty,double rotz){
		float x,y,z,sinX,cosX,sinY,cosY,sinZ,cosZ;
		sinX=(float)Math.sin(rotx*ToRAD); cosX=(float)Math.cos(rotx*ToRAD);
		sinY=(float)Math.sin(roty*ToRAD); cosY=(float)Math.cos(roty*ToRAD);
		sinZ=(float)Math.sin(rotz*ToRAD); cosZ=(float)Math.cos(rotz*ToRAD);

		//x軸方向回転
		y=pos.y*cosX - pos.z*sinX;
		z=pos.y*sinX + pos.z*cosX;
		pos.y=y; pos.z=z;

		//y軸方向回転
		x=pos.x*cosY + pos.z*sinY;
		z=-pos.x*sinY + pos.z*cosY;
		pos.x=x; pos.z=z;

		//z軸方向回転
		x=pos.x*cosZ - pos.y*sinZ;
		y=pos.x*sinZ + pos.y*cosZ;
		pos.x=x; pos.y=y; pos.z=z;
	}
	
	/* アフィン変換:移動 */
	public void Translation(st_xyz v[],int vertexnumber,float tx,float ty,float tz){
		for(int i=0;i<vertexnumber;i++){
			v[i].x=v[i].x+tx;
			v[i].y=v[i].y+ty;
			v[i].z=v[i].z+tz;
		}
	}
	
	public void Translation(st_xyz pos,float tx,float ty,float tz){
		pos.x=pos.x+tx;
		pos.y=pos.y+ty;
		pos.z=pos.z+tz;
	}
	
	/* アフィン変換:拡大縮小 */
	public void Scaling(st_xyz v[],int vertexnumber,float sx,float sy,float sz){
		for(int i=0;i<vertexnumber;i++){
			v[i].x=v[i].x*sx;
			v[i].y=v[i].y*sy;
			v[i].z=v[i].z*sz;
		}
	}
	
	public void Scaling(st_xyz pos,float sx,float sy,float sz){
		pos.x=pos.x*sx;
		pos.y=pos.y*sy;
		pos.z=pos.z*sz;
	}
	
	/* 視野変換。ワイヤーフレーム表示用 */
	public void ViewpointTrans(st_xyz v[],int vertexnumber,st_xyz pe,st_xyz p0){
		float x,y,z;
		
		float h=(float)Math.sqrt((p0.x-pe.x)*(p0.x-pe.x)+(p0.y-pe.y)*(p0.y-pe.y)+(p0.z-pe.z)*(p0.z-pe.z));
		float l=(pe.x-p0.x)/h, m=(pe.y-p0.y)/h, n=(pe.z-p0.z)/h;
		
		float sinA=-m/(float)Math.sqrt(l*l+m*m+n*n);
		float cosA=(float)Math.sqrt(l*l+n*n)/(float)Math.sqrt(l*l+m*m+n*n);
		float sinB=l/(float)Math.sqrt(l*l+n*n);
		float cosB=n/(float)Math.sqrt(l*l+n*n);
		
		for(int i=0;i<vertexnumber;i++){
			x=(v[i].x-p0.x)*cosB+(v[i].z-p0.z)*sinB;
			y=(v[i].x-p0.x)*sinA*sinB+(v[i].y-p0.y)*cosA-(v[i].z-p0.z)*sinA*cosB;
			z=-(v[i].x-p0.x)*cosA*sinB+(v[i].y-p0.y)*sinA+(v[i].z-p0.z)*cosA*cosB;
			v[i].x=x; v[i].y=y; v[i].z=z;
		}
	}
	
	
	/* 線と2次曲面の交点を求める関数。交点あれば1、なければ0を返す。 */
	public int CrosspointSphere(Object3d object,st_xyz p1,st_xyz p2,st_xyz cross,st_xyz normal){
		
		float A,B,C,D,t1,t2;
		double distance1,distance2;		//物体の表面と投影面間の距離
		st_xyz cross1 = new st_xyz();	//物体と光線の交点の座標
		st_xyz cross2 = new st_xyz();
		
		A=object.ka*(p2.x-p1.x)*(p2.x-p1.x) +
		  object.kb*(p2.y-p1.y)*(p2.y-p1.y) +
		  object.kc*(p2.z-p1.z)*(p2.z-p1.z) +
		  object.kd*(p2.x-p1.x)*(p2.y-p1.y) +
		  object.ke*(p2.y-p1.y)*(p2.z-p1.z) +
		  object.kf*(p2.z-p1.z)*(p2.x-p1.x);
		B=2*( object.ka*p1.x*(p2.x-p1.x)+object.kb*p1.y*(p2.y-p1.y)+object.kc*p1.z*(p2.z-p1.z) ) +
		  object.kd*( p1.y*(p2.x-p1.x)+p1.x*(p2.y-p1.y) ) +
		  object.ke*( p1.z*(p2.y-p1.y)+p1.y*(p2.z-p1.z) ) +
		  object.kf*( p1.x*(p2.z-p1.z)+p1.z*(p2.x-p1.x) ) +
		  object.kg*(p2.x-p1.x) + object.kh*(p2.y-p1.y) + object.ki*(p2.z-p1.z);
		C=object.ka*p1.x*p1.x + object.kb*p1.y*p1.y + object.kc*p1.z*p1.z +
		  object.kd*p1.x*p1.y + object.ke*p1.y*p1.z + object.kf*p1.z*p1.x +
		  object.kg*p1.x + object.kh*p1.y + object.ki*p1.z + object.kj;
		D=B*B-4*A*C;
		
		if(D>0){	//交点2個
			//1つ目の交点を求める（近い方）
			t1=(-B-(float)Math.sqrt(D))/(2*A);
			cross1.x=p1.x+(p2.x-p1.x)*t1;
			cross1.y=p1.y+(p2.y-p1.y)*t1;
			cross1.z=p1.z+(p2.z-p1.z)*t1;
			distance1=DistancePointPoint(p1,cross1);
			
			//2つ目の交点を求める（遠い方）
			t2=(-B+(float)Math.sqrt(D))/(2*A);
			cross2.x=p1.x+(p2.x-p1.x)*t2;
			cross2.y=p1.y+(p2.y-p1.y)*t2;
			cross2.z=p1.z+(p2.z-p1.z)*t2;
			distance2=DistancePointPoint(p1,cross2);
			
			//交点がベクトル(p2-p1)の前方にあり、p1からある程度離れていれば交点採用
			if((t1>0 && distance1>=DISTANCE_MIN) && 
			   (t2>0 && distance2>=DISTANCE_MIN)){
				//交点が2つあれば近い方を採用
				if(t1<t2){
					cross.substitute(cross1);
				}else{
					cross.substitute(cross2);
				}
			}else if((t1>0 && distance1>=DISTANCE_MIN) && 
					 (t2<=0 || distance2<DISTANCE_MIN)){
				cross.substitute(cross1);
			}else if((t1<=0 || distance1<DISTANCE_MIN) && 
					 (t2>0 && distance2>=DISTANCE_MIN)){
				cross.substitute(cross2);
			}else{
				return 0;
			}
			
			//法線ベクトル計算
			normal.x=2*object.ka*cross.x+object.kd*cross.y+object.kf*cross.z+object.kg;
			normal.y=2*object.kb*cross.y+object.kd*cross.x+object.ke*cross.z+object.kh;
			normal.z=2*object.kc*cross.z+object.ke*cross.y+object.kf*cross.x+object.ki;
			//単位法線ベクトルにする
			normal.normalize();
			
			return 1;
			
		}else if(D==0){	//交点1個
			t1=-B/(2*A);
			cross.x=p1.x+(p2.x-p1.x)*t1;
			cross.y=p1.y+(p2.y-p1.y)*t1;
			cross.z=p1.z+(p2.z-p1.z)*t1;
			
			//法線ベクトル計算
			normal.x=2*object.ka*cross.x+object.kd*cross.y+object.kf*cross.z+object.kg;
			normal.y=2*object.kb*cross.y+object.kd*cross.x+object.ke*cross.z+object.kh;
			normal.z=2*object.kc*cross.z+object.ke*cross.y+object.kf*cross.x+object.ki;
			//単位法線ベクトルにする
			normal.normalize();
			
			return 1;
			
		}else if(D<0){	//交点0個
			return 0;
		}
		
		return 0;
	}
	
	/* 線と面の交点を求める関数。交点あれば1、なければ0を返す。 */
	public int CrosspointPlane(Object3d object,st_xyz p1,st_xyz p2,st_xyz cross,st_xyz normal){
		
		int i,j,first,next,out,find;
		float x10,y10,z10,x20,y20,z20,a,b,c,d,t;
		double distance,distancetemp,	//物体の表面と投影面間の距離
			   cosine;
		st_xyz cross1 = new st_xyz();		//物体と光線の交点の座標
		st_xyz crossproduct1 = new st_xyz();	//外積
		st_xyz crossproduct2 = new st_xyz();
		st_xyz v1 = new st_xyz();
		st_xyz v2 = new st_xyz();
		
		if(object.surfacenumber<1){	//面数が0
			return 0;
		}
		
		find=0;
		distance=10000;
		
		for(i=0;i<object.surfacenumber;i++){
			
			//現在注目している面の頂点数svtotal[i]、頂点番号svnumber[i][0..svtotal[i]]
			
			if(object.svtotal[i]<3){	//面を構成する頂点数が2以下＝面でない
				return 0;
			}

			x10=object.v[ object.svnumber[i][1] ].x - object.v[ object.svnumber[i][0] ].x;
			y10=object.v[ object.svnumber[i][1] ].y - object.v[ object.svnumber[i][0] ].y;
			z10=object.v[ object.svnumber[i][1] ].z - object.v[ object.svnumber[i][0] ].z;
			x20=object.v[ object.svnumber[i][2] ].x - object.v[ object.svnumber[i][0] ].x;
			y20=object.v[ object.svnumber[i][2] ].y - object.v[ object.svnumber[i][0] ].y;
			z20=object.v[ object.svnumber[i][2] ].z - object.v[ object.svnumber[i][0] ].z;
			a=y10*z20-z10*y20;
			b=z10*x20-x10*z20;
			c=x10*y20-y10*x20;
			d=-(a*object.v[object.svnumber[i][1]].x + b*object.v[object.svnumber[i][1]].y + c*object.v[object.svnumber[i][1]].z);
			
			t=-(a*p1.x+b*p1.y+c*p1.z+d) / (a*(p2.x-p1.x)+b*(p2.y-p1.y)+c*(p2.z-p1.z));
			
			cross1.x=p1.x+(p2.x-p1.x)*t;
			cross1.y=p1.y+(p2.y-p1.y)*t;
			cross1.z=p1.z+(p2.z-p1.z)*t;
			
			distancetemp=DistancePointPoint(p1,cross1);
			
			//交点がベクトル(p2-p1)の前方かつp1からある程度離れている、を満たさなければ交点採用しない
			if(t<0 || distancetemp<DISTANCE_MIN) continue;
			
			
			//現在求めた交点の方が近ければ面内部判定、値更新
			if(distancetemp<=distance){
				
				//交点が面の内部にあるか判定
				first=1;
				out=0;
				for(j=0;j<object.svtotal[i];j++){
					
					if(j==object.svtotal[i]-1){ next=0;	//jのループの最後のとき
					}else{ next=j+1; }
					
					v1=subVector(object.v[ object.svnumber[i][next] ], object.v[ object.svnumber[i][j] ]);
					v2=subVector(cross1, object.v[ object.svnumber[i][j] ]);
					
					if(first==1){	//jのループの最初のとき
						first=0;
						crossproduct1=CrossProduct(v1,v2);
						//continue;
					}else{
						crossproduct2=CrossProduct(v1,v2);
						cosine=DotProduct(crossproduct1,crossproduct2) /	//crossproduct1と2の間の角のcosを求める
							   ( Math.sqrt(crossproduct1.x*crossproduct1.x+crossproduct1.y*crossproduct1.y+crossproduct1.z*crossproduct1.z) *
							     Math.sqrt(crossproduct2.x*crossproduct2.x+crossproduct2.y*crossproduct2.y+crossproduct2.z*crossproduct2.z) );
						
						if(cosine>0.8){	//crossproduct1と2の間の角が小さい
						//	continue;
						}else{			//crossproduct1と2の間の角が大きい＝交点は面の外にある
							out=1;
							break;
						}
					}
				}
				
				if(out==1){	//交点は面の外にある。iループやり直し
					continue;
				}
				
				
				//現在求めた交点の方が近く、面内部にあるので値更新
				cross.substitute(cross1);	//交点
				normal.x=a;
				normal.y=b;
				normal.z=c;
				normal.normalize();	//単位法線ベクトル
				Surface=i;	//当たった面番号
				distance=distancetemp;
				find=1;
			}
		}
		
		return find;
	}
	
	/* ベクトル和 */
	public st_xyz addVector(st_xyz a,st_xyz b){
		st_xyz v = new st_xyz();
		v.x=a.x+b.x;
		v.y=a.y+b.y;
		v.z=a.z+b.z;
		return v;
	}
	
	/* ベクトル差 */
	public st_xyz subVector(st_xyz a,st_xyz b){
		st_xyz v = new st_xyz();
		v.x=a.x-b.x;
		v.y=a.y-b.y;
		v.z=a.z-b.z;
		return v;
	}
	
	/* ベクトルスカラー倍 */
	public st_xyz prodVector(st_xyz a,float b){
		st_xyz v = new st_xyz();
		v.x=a.x*b;
		v.y=a.y*b;
		v.z=a.z*b;
		return v;
	}
	
	/* 点と点の距離を返す */
	public double DistancePointPoint(st_xyz p1,st_xyz p2){
		return( Math.sqrt((p1.x-p2.x)*(p1.x-p2.x)+(p1.y-p2.y)*(p1.y-p2.y)+(p1.z-p2.z)*(p1.z-p2.z)) );
	}
	
	/* aとbの外積を求める。 */
	public st_xyz CrossProduct(st_xyz a,st_xyz b){
		st_xyz crossproduct = new st_xyz();
		crossproduct.x = a.y*b.z - a.z*b.y;
		crossproduct.y = a.z*b.x - a.x*b.z;
		crossproduct.z = a.x*b.y - a.y*b.x;
		return crossproduct;
	}
	
	/* aとbの内積を求める。 */
	public float DotProduct(st_xyz a,st_xyz b){
		return( a.x*b.x+a.y*b.y+a.z*b.z );
	}
	
	/* 2つのベクトルのなす角度のcosを求める。 */
	public double VectorAngle(st_xyz v1,st_xyz v2){
		return( DotProduct(v1,v2)/(Math.sqrt(v1.x*v1.x+v1.y*v1.y+v1.z*v1.z)*Math.sqrt(v2.x*v2.x+v2.y*v2.y+v2.z*v2.z)) );
	}
	
	/* 光の距離による減衰率を求める */
	public double lightDecreaseRate(double distance){
		distance/=300;
		double a=1/(distance*distance);
		if(a>1) a=1;
		return (1-Dec)*a;
	}
	
	/* 入射方向inと法線方向normalから反射方向ベクトルを求める。inとnormalは単位ベクトルにしておく。 */
	public st_xyz ReflectVector(st_xyz in,st_xyz normal){
		float a;
		st_xyz reflect = new st_xyz();
		st_xyz invin = new st_xyz();
		
		invin.x=-in.x; invin.y=-in.y; invin.z=-in.z;
		a=2.0f*DotProduct(invin,normal);
		reflect.x=a*normal.x+in.x;
		reflect.y=a*normal.y+in.y;
		reflect.z=a*normal.z+in.z;
		
		return reflect;
	}
	
	/* 入射方向inと法線方向normalから屈折方向ベクトルを求める。inとnormalは単位ベクトルにしておく。 */
	public st_xyz RefractVector(st_xyz in,st_xyz normal,double n1,double n2){
		double cos1,a;
		st_xyz invin = new st_xyz();
		st_xyz refract = new st_xyz();
		
		invin.x=-in.x;
		invin.y=-in.y;
		invin.z=-in.z;
		cos1=DotProduct(invin,normal);
		
		a=((n2*n2)/(n1*n1))-1+cos1*cos1;
		if(a>=0) a=Math.sqrt(a);
		else a=0;
        	
		refract.x=(float)(n1/n2)*(in.x-normal.x*(float)(a-cos1));
		refract.y=(float)(n1/n2)*(in.y-normal.y*(float)(a-cos1));
		refract.z=(float)(n1/n2)*(in.z-normal.z*(float)(a-cos1));
		
		return refract;
	}
	
	/* 線分が最初にぶつかる物体を求める */
	/* ぶつかる物体の番号を返す。なければ-1を返す。 */
	public int FirstHit(st_xyz from,st_xyz to){
		int ii,hit,objnumber=-1;
		double distance,distancetemp;
		st_xyz cross = new st_xyz();
		st_xyz normal = new st_xyz();	//利用せず
		
		distance=10000;
		for(ii=0;ii<OBJECT_NUMBER;ii++){
			hit=0;
			switch(object[ii].type){
			case 1:
			case 2:
			case 5:
				hit=CrosspointSphere(object[ii],from,to,cross,normal);
				break;
			case 20:
				hit=CrosspointPlane(object[ii],from,to,cross,normal);
				break;
			}
			if(hit==1){	//交点あり
				distancetemp=DistancePointPoint(from,cross);
				if(distancetemp<=distance){
					distance=distancetemp;
					objnumber=ii;
				}
			}
		}
		
		return objnumber;
	}
	
	/* 物体の面と、その上の交点の座標から、この点のテクスチャーの色を求める */
	public st_color TextureColor(Object3d object,st_xyz cross,int surface){
		int i,x,y;
		float u=0,v=0,a;
		
		switch(object.type){
		case 1:	//球
			double theta,gamma;
			theta=Math.atan((cross.x-object.center.x)/(cross.z-object.center.z));
			gamma=Math.acos(-(cross.y-object.center.y)/object.radius);
			
			u=(float)(theta/(2.0*Math.PI));
			v=(float)(gamma/Math.PI);
			break;
			
		case 20:	//多面体
			st_xyz p0 = new st_xyz();
			st_xyz pi = new st_xyz();
			st_xyz pj = new st_xyz();
			//面の(u,v)=(0,0)の頂点の座標を得る
			for(i=0;i<object.svtotal[surface];i++){
				if(object.svtextureuv[surface][i].u==0 && object.svtextureuv[surface][i].v==0){
					p0.substitute(object.v[ object.svnumber[surface][i] ]);
					break;
				}
			}
			
			//(u,v)=(0,0)の頂点から(u,v)=(i,0)の頂点へ向かうベクトルを求める
			for(i=0;i<object.svtotal[surface];i++){
				if(object.svtextureuv[surface][i].u!=0 && object.svtextureuv[surface][i].v==0){
					pi.x=(object.v[ object.svnumber[surface][i] ].x - p0.x) / object.svtextureuv[surface][i].u;
					pi.y=(object.v[ object.svnumber[surface][i] ].y - p0.y) / object.svtextureuv[surface][i].u;
					pi.z=(object.v[ object.svnumber[surface][i] ].z - p0.z) / object.svtextureuv[surface][i].u;
					break;
				}
			}
			
			//(u,v)=(0,0)の頂点から(u,v)=(0,j)の頂点へ向かうベクトルを求める
			for(i=0;i<object.svtotal[surface];i++){
				if(object.svtextureuv[surface][i].u==0 && object.svtextureuv[surface][i].v!=0){
					pj.x=(object.v[ object.svnumber[surface][i] ].x - p0.x) / object.svtextureuv[surface][i].v;
					pj.y=(object.v[ object.svnumber[surface][i] ].y - p0.y) / object.svtextureuv[surface][i].v;
					pj.z=(object.v[ object.svnumber[surface][i] ].z - p0.z) / object.svtextureuv[surface][i].v;
					break;
				}
			}
			
			a=pj.x*pi.y-pi.x*pj.y;
			if(a!=0){	//xyの値を使う
				u=((p0.x-cross.x)*pj.y+(-p0.y+cross.y)*pj.x) / a;
				v=((-p0.x+cross.x)*pi.y+(p0.y-cross.y)*pi.x) / a;
			}else{	//面がx-y平面に垂直のときはa=0になる。このときはxzの値を使う。
				a=pj.x*pi.z-pi.x*pj.z;
				if(a!=0){
					u=((p0.x-cross.x)*pj.z+(-p0.z+cross.z)*pj.x) / a;
					v=((-p0.x+cross.x)*pi.z+(p0.z-cross.z)*pi.x) / a;
				}else{	//面がx-y,x-z平面に垂直のときはa=0になる。このときはyzの値を使う。
					a=pj.y*pi.z-pi.y*pj.z;
					if(a!=0){
						u=((p0.y-cross.y)*pj.z+(-p0.z+cross.z)*pj.y) / a;
						v=((-p0.y+cross.y)*pi.z+(p0.z-cross.z)*pi.y) / a;
					}else{	//面がx-y,x-z,y-z平面に垂直？
						u=0; v=0;
					}
				}
			}
			break;
		}
		
		//u,vを0〜1の範囲におさめる
		if(u<0)
			u=-u;
		while(u>=1)
			u-=1;
		
		if(v<0)
			v=-v;
		while(v>=1)
			v-=1;
		
		//テクスチャ上の座標を計算（画像の左下原点）
		x=(int)(u*object.texture.getWidth());
		y=(int)(v*object.texture.getHeight());
		
		return object.texture.getTexelColor(x,y);
	}
	
	/* 全ての光源を点光源に置き換え、光源データに代入 */
	public void toPointLight(Light lightsource){
		int DENSITY=25;	//点光源を配置する間隔。小さいほど点光源数増加
		int i,total=0,first,last;
		int rroot,rnext,lroot,lnext;
		double vrsize,vlsize,vsize;
		float vrtimes,vltimes;
		st_xyz vr = new st_xyz();
		st_xyz vl = new st_xyz();
		st_xyz vrvec = new st_xyz();
		st_xyz vlvec = new st_xyz();
		st_xyz v = new st_xyz();
		
		first=light.size();
		
		switch(lightsource.type){
		case 1:	//点光源
			Light lighttemp1 = new Light();
			lighttemp1.type=1;
			lighttemp1.pos.substitute(lightsource.pos);
			lighttemp1.col.substitute(lightsource.col);
			light.addElement(lighttemp1);
			
			total++;
			break;
			
		case 2:	//面光源
			rroot=-1;	//rroot=0..svtotalとなるように
			rnext=1;
			lroot=1;	//lroot=0,svtotal..1となるように
			lnext=lightsource.svtotal[0];
			
			vrtimes=1; vltimes=1;	//最初に辺ベクトルが設定されるように
			vrsize=0; vlsize=0;
			
			while(true){
				//右回りで1つづつ辺を選ぶ
				if(vrtimes>vrsize){
					rroot++;
					if(rroot>lightsource.svtotal[0])
						break;
					rnext=rroot+1;
					if(rroot==lnext)
						break;
					vr=subVector(lightsource.v[ lightsource.svnumber[0][rnext] ], lightsource.v[ lightsource.svnumber[0][rroot] ]);
					vrsize=vr.getSize();
					vr.normalize();	//右回り辺ベクトル
					vrtimes=0;
				}
				
				//左回りで1つづつ辺を選ぶ
				if(vltimes>vlsize){
					lroot--;
					if(lroot<0)
						lroot=lightsource.svtotal[0];
					if(lroot==1)
						break;
					lnext=lroot-1;
					if(lnext<0)
						lnext=lightsource.svtotal[0];
					if(lroot==rnext)
						break;
					vl=subVector(lightsource.v[ lightsource.svnumber[0][lnext] ], lightsource.v[ lightsource.svnumber[0][lroot] ]);
					vlsize=vl.getSize();
					vl.normalize();	//左回り辺ベクトル
					vltimes=0;
				}
				
				//辺ベクトルを少しずつ伸ばしながら、2つの辺ベクトルの間のベクトルvを求める
				vrvec=addVector(lightsource.v[ lightsource.svnumber[0][rroot] ], prodVector(vr,vrtimes));
				vlvec=addVector(lightsource.v[ lightsource.svnumber[0][lroot] ], prodVector(vl,vltimes));
				v=subVector(vrvec,vlvec);
				vsize=v.getSize();
				v.normalize();
				//vを少しずつ伸ばしながら、点光源の座標を求める
				for(i=0;i<=vsize;i+=DENSITY){
					Light lighttemp2 = new Light();
					lighttemp2.type=1;
					lighttemp2.pos=addVector(vlvec,prodVector(v,i));
					lighttemp2.col.substitute(lightsource.col);
					light.addElement(lighttemp2);
					total++;
				}
				
				vrtimes+=DENSITY;
				vltimes+=DENSITY;
			}
			
			break;
		}
		
		last=light.size();
		
		//面光源などを点光源に分割したときは、分割数を代入する
		if(total>0){
			for(i=first;i<last;i++){
				((Light)light.elementAt(i)).division=total;
			}
		}
	}
}

