From e1af5e214c389aea2b55daf82bdec92472db3f19 Mon Sep 17 00:00:00 2001
From: Chris Xiong <chirs241097@gmail.com>
Date: Sat, 9 Feb 2019 00:00:53 +0800
Subject: Moving shitty stuff sitting around in the www folder here.

---
 xp/cgxp/1.html     |  14 +++
 xp/cgxp/2.html     |  14 +++
 xp/cgxp/main1.js   | 320 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 xp/cgxp/main2.js   | 280 ++++++++++++++++++++++++++++++++++++++++++++++
 xp/cgxp/wglmath.js | 102 +++++++++++++++++
 5 files changed, 730 insertions(+)
 create mode 100644 xp/cgxp/1.html
 create mode 100644 xp/cgxp/2.html
 create mode 100644 xp/cgxp/main1.js
 create mode 100644 xp/cgxp/main2.js
 create mode 100644 xp/cgxp/wglmath.js

(limited to 'xp/cgxp')

diff --git a/xp/cgxp/1.html b/xp/cgxp/1.html
new file mode 100644
index 0000000..b05e78f
--- /dev/null
+++ b/xp/cgxp/1.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<title>CGxp1</title>
+<link rel="icon" href="/favicon.png">
+<link rel="stylesheet" type="text/css" href="/common.css">
+<script type="text/javascript" src="main1.js"></script>
+<script type="text/javascript" src="wglmath.js"></script>
+</head>
+<body onload="init();" style="margin:0;">
+<canvas id="glCvs" width="800" height="450" style=""></canvas>
+</body>
+</html>
diff --git a/xp/cgxp/2.html b/xp/cgxp/2.html
new file mode 100644
index 0000000..880c0cb
--- /dev/null
+++ b/xp/cgxp/2.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<title>CGxp2</title>
+<link rel="icon" href="/favicon.png">
+<link rel="stylesheet" type="text/css" href="/common.css">
+<script type="text/javascript" src="main2.js"></script>
+<script type="text/javascript" src="wglmath.js"></script>
+</head>
+<body onload="init();" style="margin:0;">
+<canvas id="glCvs" width="800" height="450" style=""></canvas>
+</body>
+</html>
diff --git a/xp/cgxp/main1.js b/xp/cgxp/main1.js
new file mode 100644
index 0000000..bd52e13
--- /dev/null
+++ b/xp/cgxp/main1.js
@@ -0,0 +1,320 @@
+//Copyright Chris Xiong 2018
+//License: Expat (MIT)
+var cvs,WGL,vpw,vph,hdiv;
+var fsh=`
+varying lowp vec4 vC;
+void main(void)
+{
+	gl_FragColor=vC;
+}`;
+var vsh=`
+attribute vec3 vp;
+attribute vec4 vc;
+uniform mat4 mmodelview;
+uniform mat4 mprojection;
+varying lowp vec4 vC;
+void main(void)
+{
+	gl_Position=mprojection*mmodelview*vec4(vp,1.);
+	vC=vc;
+}`;
+var shp;
+var vbufsize=4096;
+var vbo,ibo;
+var vb=new Float32Array(vbufsize*7);
+var ib=new Uint16Array(vbufsize*6/4);
+var Mprojection,Mmodelview;
+var primc;
+var kst=[];
+var dbc,mbtn,mup,mdn,mx,my,mox,moy;
+var shapes=[];
+var curshape=null;
+var dragging=false,drg;
+
+var Shape=function(t)
+{
+	this.type=t;
+	this.vert=[];
+}
+function copyshape(s)
+{
+	var r=new Shape(s.type);
+	for(var i=0;i<s.vert.length;++i)
+	r.vert.push(new v3d(s.vert[i].x,s.vert[i].y,s.vert[i].z));
+	return r;
+}
+Shape.prototype.draw=function(a,r,g,b)
+{
+	var drawseg=function(a,b,c,d,aa,rr,gg,bb)
+	{
+		var pa=new v3d(a,b,0);
+		var pb=new v3d(c,d,0);
+		var d=pb.subtract(pa);
+		var pd1=new v3d(-d.y,d.x,0),pd2=new v3d(d.y,-d.x,0);
+		pd1=pd1.n();pd2=pd2.n();
+		var p1=pa.add(pd1),p2=pa.add(pd2);
+		var p3=pb.add(pd2),p4=pb.add(pd1);
+		var q=[];
+		q.push(p1.x);q.push(vph-p1.y);q.push(p1.z);
+		q.push(rr);q.push(gg);q.push(bb);q.push(aa);
+		q.push(p2.x);q.push(vph-p2.y);q.push(p2.z);
+		q.push(rr);q.push(gg);q.push(bb);q.push(aa);
+		q.push(p3.x);q.push(vph-p3.y);q.push(p3.z);
+		q.push(rr);q.push(gg);q.push(bb);q.push(aa);
+		q.push(p4.x);q.push(vph-p4.y);q.push(p4.z);
+		q.push(rr);q.push(gg);q.push(bb);q.push(aa);
+		pushQuad(q);
+	}
+	if(this.type=='segment')
+	drawseg(this.vert[0].x,this.vert[0].y,this.vert[1].x,this.vert[1].y,
+	a,r,g,b);
+	if(this.type=='segstrip'||this.type=='segloop')
+	{
+		for(var i=0;i<this.vert.length-1;++i)
+		drawseg(this.vert[i].x,this.vert[i].y,this.vert[i+1].x,this.vert[i+1].y,
+		a,r,g,b);
+		if(this.type=='segloop')
+		{
+			var i=this.vert.length-1;
+			drawseg(this.vert[i].x,this.vert[i].y,this.vert[0].x,this.vert[0].y,
+			a,r,g,b);
+		}
+	}
+}
+Shape.prototype.coltest=function(x,y)
+{
+	var dp2s=function(x,y,_a,_b,_c,_d)
+	{
+		var a=new v3d(_a,_b,0);
+		var b=new v3d(_c,_d,0);
+		var p=new v3d(x,y,0);
+		var ab=b.subtract(a);
+		var ap=p.subtract(a);
+		var pl=ab.dot(ap)/ab.l();
+		var pp=a.add(ab.n().ms(pl));
+		if(pl<0||pl>ab.l())pp=new v3d(1e9,1e9,1e9);
+		return Math.min(p.subtract(pp).l(),p.subtract(a).l(),p.subtract(b).l());
+	}
+	if(this.type=='segment')
+	{
+		var d=dp2s(x,y,this.vert[0].x,this.vert[0].y,
+						this.vert[1].x,this.vert[1].y);
+		if(d<5)return true;
+	}
+	if(this.type=='segstrip'||this.type=="segloop")
+	{
+		for(var i=0;i<this.vert.length-1;++i)
+		{
+			var d=dp2s(x,y,this.vert[i].x,this.vert[i].y,
+							this.vert[i+1].x,this.vert[i+1].y);
+			if(d<5)return true;
+		}
+		if(this.type=="segloop")
+		{
+			var i=this.vert.length-1;
+			var d=dp2s(x,y,this.vert[i].x,this.vert[i].y,
+							this.vert[0].x,this.vert[0].y);
+			if(d<5)return true;
+		}
+	}
+	return false;
+}
+
+function createShader(sh,t)
+{
+	var shader=WGL.createShader(t);
+	WGL.shaderSource(shader,sh);
+	WGL.compileShader(shader);
+	if(!WGL.getShaderParameter(shader,WGL.COMPILE_STATUS))
+	{
+		alert("shader error..."+WGL.getShaderInfoLog(shader));
+		return null;
+	}
+	return shader;
+}
+function pushQuad(a)
+{
+	if(primc>=vbufsize/4)batchGL();
+	for(var i=0;i<4;++i)
+	for(var j=0;j<7;++j)vb[primc*7*4+i*7+j]=a[i*7+j];
+	++primc;
+}
+
+function init()
+{
+	cvs=document.getElementById("glCvs");
+	if(!window.devicePixelRatio)window.devicePixelRatio=1;
+	cvs.width=window.innerWidth;
+	cvs.height=window.innerHeight;
+	cvs.style.width=cvs.width+"px";
+	cvs.style.height=cvs.height+"px";
+	cvs.width=cvs.width*window.devicePixelRatio;
+	cvs.height=cvs.height*window.devicePixelRatio;
+	vpw=cvs.width;vph=cvs.height;
+	try
+	{WGL=cvs.getContext("webgl")||cvs.getContext("experimental-webgl");}
+	catch(e){WGL=null;}
+	if(!WGL){alert("WebGL is not supported by your browser...");return;}
+	
+	WGL.clearColor(0.5,0.5,0.5,1.0);
+	WGL.clearDepth(1);
+	WGL.enable(WGL.DEPTH_TEST);
+	WGL.depthFunc(WGL.LESS);
+	WGL.enable(WGL.BLEND);
+	WGL.blendFunc(WGL.SRC_ALPHA,WGL.ONE_MINUS_SRC_ALPHA);
+	WGL.clear(WGL.COLOR_BUFFER_BIT|WGL.DEPTH_BUFFER_BIT);
+	WGL.viewport(0,0,cvs.width,cvs.height);
+	
+	shp=WGL.createProgram();
+	var fshs=createShader(fsh,WGL.FRAGMENT_SHADER);
+	var vshs=createShader(vsh,WGL.VERTEX_SHADER);
+	WGL.attachShader(shp,vshs);WGL.attachShader(shp,fshs);
+	WGL.linkProgram(shp);
+	if(!WGL.getProgramParameter(shp,WGL.LINK_STATUS))
+	{
+		alert("shader link error...");
+	}
+	WGL.useProgram(shp);
+	
+	vbo=WGL.createBuffer();
+	WGL.bindBuffer(WGL.ARRAY_BUFFER,vbo);
+	WGL.bufferData(WGL.ARRAY_BUFFER,vb,WGL.STATIC_DRAW);
+	var vpp=WGL.getAttribLocation(shp,"vp");
+	var vcp=WGL.getAttribLocation(shp,"vc");
+	WGL.enableVertexAttribArray(vpp);
+	WGL.enableVertexAttribArray(vcp);
+	WGL.bindBuffer(WGL.ARRAY_BUFFER,vbo);
+	WGL.vertexAttribPointer(vpp,3,WGL.FLOAT,false,7*4,0);
+	WGL.vertexAttribPointer(vcp,4,WGL.FLOAT,false,7*4,3*4);
+	
+	for(var i=0,n=0,p=0;i<vbufsize/4;++i)
+	{
+		ib[p++]=n;ib[p++]=n+1;
+		ib[p++]=n+2;ib[p++]=n+2;
+		ib[p++]=n+3;ib[p++]=n;
+		n+=4;
+	}
+	ibo=WGL.createBuffer();
+	WGL.bindBuffer(WGL.ELEMENT_ARRAY_BUFFER,ibo);
+	WGL.bufferData(WGL.ELEMENT_ARRAY_BUFFER,ib,WGL.STATIC_DRAW);
+	
+	document.addEventListener('keydown',function(e){kst[e.code]=1;});
+	document.addEventListener('keyup',function(e){kst[e.code]=0;});
+	document.addEventListener('mousedown',function(e){mdn=true;mbtn=e.button;});
+	document.addEventListener('contextmenu',function(e){e.preventDefault();});
+	document.addEventListener('mouseup',function(e){mup=true;});
+	document.addEventListener('dblclick',function(e){dbc=true;});
+	document.addEventListener('mousemove',function(e)
+	{mx=e.clientX/window.innerWidth*vpw;my=e.clientY/window.innerHeight*vph;});
+
+	requestAnimationFrame(mainloop);
+}
+function getpick()
+{
+	for(var i=0;i<shapes.length;++i)
+	if(shapes[i].coltest(mx,my))return i;
+	return -1;
+}
+
+function mainloop()
+{
+	WGL.clearColor(0.5,0.5,0.5,1.0);
+	WGL.clearDepth(1);
+	WGL.clear(WGL.COLOR_BUFFER_BIT|WGL.DEPTH_BUFFER_BIT);
+	primc=0;
+	Mmodelview=buildIdentityMatrix();
+	var picked=getpick();
+	
+	//interaction shit
+	if(dragging)
+	{
+		if(mup)
+		{dragging=false;curshape=null;mdn=mup=false;}
+		if(!mdn&&mbtn==0&&dragging)
+		for(var i=0;i<shapes[drg].vert.length;++i)
+		shapes[drg].vert[i]=curshape.vert[i].add(new v3d(mx,my,0).subtract(new v3d(mox,moy,0)));
+		if(!mdn&&mbtn==2&&dragging)
+		{
+			var newscale=new v3d(mox,moy,0).subtract(new v3d(mx,my,0)).l()/20;
+			if(mx<mox||my<moy)newscale=-newscale;
+			if(newscale<-95)newscale=-95;
+			var sc=(100+newscale)/100.;
+			var mmx=curshape.vert[0].x,mmy=curshape.vert[0].y;
+			for(var i=1;i<curshape.vert.length;++i)
+			mmx=Math.min(mmx,curshape.vert[i].x),
+			mmy=Math.min(mmy,curshape.vert[i].y);
+			var c=new v3d(mmx,mmy,0);
+			for(var i=0;i<shapes[drg].vert.length;++i)
+				shapes[drg].vert[i]=curshape.vert[i].subtract(c).n().ms
+				(curshape.vert[i].subtract(c).l()*sc).add(c);
+		}
+		
+	}
+	if(dbc)
+	{
+		if(dragging)
+		{dragging=false;curshape=null;}
+		else
+		if(curshape)
+		{
+			if(kst['ControlLeft']==1&&curshape.type=='segstrip')
+				curshape.type='segloop';
+			shapes.push(curshape);
+			curshape=null;
+		}
+	}
+	else
+	{
+		if(mup&&kst['ControlLeft']==1&&!curshape)
+		{
+			if(picked!=-1)
+			{
+				dragging=true;
+				mox=mx,moy=my;drg=picked;
+				curshape=copyshape(shapes[picked]);
+			}
+		}
+		if(mup&&!dragging&&!kst['ControlLeft'])
+		{
+			if(!curshape)
+			{
+				curshape=new Shape('segment');
+				curshape.vert.push(new v3d(mx,my,0));
+				curshape.vert.push(new v3d(mx,my,0));
+			}
+			else
+			{
+				if(curshape.type=='segment')curshape.type='segstrip';
+				curshape.vert.push(new v3d(mx,my,0));
+			}
+		}
+	}
+	
+	if(curshape&&!dragging)
+		curshape.vert[curshape.vert.length-1]=new v3d(mx,my,0);
+
+	for(var i=0;i<shapes.length;++i)
+	if(!curshape&&!dragging&&i==picked)shapes[i].draw(1,0.8,0,0);
+	else shapes[i].draw(1,0.8,0.8,0.8);
+	
+	if(curshape&&!dragging)curshape.draw(1,0.8,0.8,0);
+
+	batchGL();
+
+	mup=mdn=dbc=false;
+	requestAnimationFrame(mainloop);
+}
+
+function batchGL()
+{
+	Mprojection=buildProjectionMatrix2D(vpw,vph);
+	var mpp=WGL.getUniformLocation(shp,"mprojection");
+	WGL.uniformMatrix4fv(mpp,false,Mprojection);
+	var mvpp=WGL.getUniformLocation(shp,"mmodelview");
+	WGL.uniformMatrix4fv(mvpp,false,Mmodelview);
+	WGL.bindBuffer(WGL.ARRAY_BUFFER,vbo);
+	WGL.bufferData(WGL.ARRAY_BUFFER,vb,WGL.STATIC_DRAW);
+	WGL.drawElements(WGL.TRIANGLES,6*primc,WGL.UNSIGNED_SHORT,0);
+	primc=0;
+}
+
diff --git a/xp/cgxp/main2.js b/xp/cgxp/main2.js
new file mode 100644
index 0000000..05b1fdb
--- /dev/null
+++ b/xp/cgxp/main2.js
@@ -0,0 +1,280 @@
+//Copyright Chris Xiong 2018
+//License: Expat (MIT)
+var cvs,WGL,vpw,vph,hdiv;
+var fsh=`
+varying lowp vec4 vC;
+void main(void)
+{
+	gl_FragColor=vC;
+}`;
+var vsh=`
+attribute vec3 vp;
+attribute vec4 vc;
+uniform mat4 mmodelview;
+uniform mat4 mprojection;
+varying lowp vec4 vC;
+void main(void)
+{
+	gl_Position=mprojection*mmodelview*vec4(vp,1.);
+	vC=vc;
+}`;
+var shp;
+var vbufsize=4096;
+var vbo,ibo;
+var vb=new Float32Array(vbufsize*7);
+var ib=new Uint16Array(vbufsize*6/4);
+var Mprojection,Mmodelview;
+var primc;
+var kst=[];
+var pos=[15,4,30];
+var ofs=[0.9,3.5,20];
+var mzw=50,mzh=35,ppx,ppy,ex,ey;
+var maz=[];
+
+var Sphere=function()
+{
+	this.x=10-Math.random()*20;
+	this.y=10-Math.random()*20;
+	this.timer=0;this.r=0.2;
+}
+Sphere.prototype.update=function()
+{
+	var d=Math.sqrt((this.x-pp.x)*(this.x-pp.x)+(this.y-pp.y)*(this.y-pp.y));
+	if(d<0.5&&this.timer===0)this.timer=1;
+	if(this.timer>0&&state===0)
+	{
+		++this.timer;health+=0.01;
+		this.r+=0.02;if(health>1)health=1;
+	}
+	if(this.timer>25)this.timer=-1;
+}
+Sphere.prototype.draw=function(x,y,a)
+{
+	if(this.timer!==-1)pushSphere(x,y,0,this.r,[0,1,0,a*(0.6-this.timer*0.6/25)]);
+}
+
+function createShader(sh,t)
+{
+	var shader=WGL.createShader(t);
+	WGL.shaderSource(shader,sh);
+	WGL.compileShader(shader);
+	if(!WGL.getShaderParameter(shader,WGL.COMPILE_STATUS))
+	{
+		alert("shader error..."+WGL.getShaderInfoLog(shader));
+		return null;
+	}
+	return shader;
+}
+function pushQuad(a)
+{
+	if(primc>=vbufsize/4)batchGL();
+	for(var i=0;i<4;++i)
+	for(var j=0;j<7;++j)vb[primc*7*4+i*7+j]=a[i*7+j];
+	++primc;
+}
+function cube(x,y,z,l,r,g,b,a)
+{
+	var L=x-l/2,R=x+l/2;
+	var B=y-l/2,T=y+l/2;
+	var N=z-l/2,F=z+l/2;
+	pushQuad([
+		L,B,N,r,g,b,a,
+		L,T,N,r,g,b,a,
+		R,T,N,r,g,b,a,
+		R,B,N,r,g,b,a
+	]);
+	pushQuad([
+		L,B,F,r,g,b,a,
+		L,T,F,r,g,b,a,
+		R,T,F,r,g,b,a,
+		R,B,F,r,g,b,a
+	]);
+	pushQuad([
+		L,B,N,r,g,b,a,
+		L,T,N,r,g,b,a,
+		L,T,F,r,g,b,a,
+		L,B,F,r,g,b,a
+	]);
+	pushQuad([
+		R,B,N,r,g,b,a,
+		R,T,N,r,g,b,a,
+		R,T,F,r,g,b,a,
+		R,B,F,r,g,b,a
+	]);
+	pushQuad([
+		L,B,N,r,g,b,a,
+		R,B,N,r,g,b,a,
+		R,B,F,r,g,b,a,
+		L,B,F,r,g,b,a
+	]);
+	pushQuad([
+		L,T,N,r,g,b,a,
+		R,T,N,r,g,b,a,
+		R,T,F,r,g,b,a,
+		L,T,F,r,g,b,a
+	]);
+}
+function pushSphere(x,y,z,r,col)
+{
+	for(var i=0;i<12;++i)
+	for(var j=0;j<12;++j)
+	{
+		var r1=r*Math.sin(i*Math.PI/12);
+		var a=new v3d(x+r1*Math.cos(j*Math.PI/12*2),y+r1*Math.sin(j*Math.PI/12*2),z+r*Math.cos(i*Math.PI/12));
+		var b=new v3d(x+r1*Math.cos((j+1)*Math.PI/12*2),y+r1*Math.sin((j+1)*Math.PI/12*2),z+r*Math.cos(i*Math.PI/12));
+		r1=r*Math.sin((i+1)*Math.PI/12);
+		var c=new v3d(x+r1*Math.cos(j*Math.PI/12*2),y+r1*Math.sin(j*Math.PI/12*2),z+r*Math.cos((i+1)*Math.PI/12));
+		var d=new v3d(x+r1*Math.cos((j+1)*Math.PI/12*2),y+r1*Math.sin((j+1)*Math.PI/12*2),z+r*Math.cos((i+1)*Math.PI/12));
+		pushQuad([
+			a.x,a.y,a.z,col[0],col[1],col[2],col[3],
+			b.x,b.y,b.z,col[0],col[1],col[2],col[3],
+			d.x,d.y,d.z,col[0],col[1],col[2],col[3],
+			c.x,c.y,c.z,col[0],col[1],col[2],col[3]
+		]);
+	}
+}
+function randint(c)
+{return Math.floor(Math.random()*c);}
+function genmaze()
+{
+	for(var i=0;i<mzw;++i)
+	{
+		maz[i]=[];
+		for(var j=0;j<mzh;++j)maz[i][j]=false;
+	}
+	var dx=[0,0,-1,1],
+		dy=[1,-1,0,0];
+	var lst=[];
+	var cx=randint(mzw),cy=randint(mzh);
+	lst.push({x:cx,y:cy,z:cx,w:cy});
+	while(lst.length)
+	{
+		var rm=lst.splice(randint(lst.length),1);
+		var x=rm[0].z,y=rm[0].w;
+		if(maz[x][y]==false)
+		{
+			maz[x][y]=maz[rm[0].x][rm[0].y]=true;
+			for(var i=0;i<4;++i)
+			{
+				cx=x+dx[i]*2;cy=y+dy[i]*2;
+				if(cx>=0&&cy>=0&&cx<mzw&&cy<mzh&&
+				maz[cx][cy]==false)
+				lst.push({x:x+dx[i],y:y+dy[i],z:cx,w:cy});
+			}
+		}
+	}
+	for(var i=0;i<mzh;++i)maz[0][i]=maz[mzw-1][i]=false;
+	for(var i=0;i<mzw;++i)maz[i][0]=maz[i][mzh-1]=false;
+	for(var i=0;i<mzh;++i){if(maz[1][i])lst.push({x:1,y:i});if(maz[mzw-2][i])lst.push({x:mzw-2,y:i});}
+	for(var i=0;i<mzw;++i){if(maz[i][1])lst.push({x:i,y:1});if(maz[i][mzh-2])lst.push({x:i,y:mzh-2});}
+	if(lst.length<2)return genmaze();
+	var rm=lst.splice(randint(lst.length),1);
+	ppx=rm[0].x,ppy=rm[0].y;
+	rm=lst.splice(randint(lst.length),1);
+	ex=rm[0].x,ey=rm[0].y;
+}
+function init()
+{
+	cvs=document.getElementById("glCvs");
+	if(!window.devicePixelRatio)window.devicePixelRatio=1;
+	cvs.width=window.innerWidth;
+	cvs.height=window.innerHeight;
+	cvs.style.width=cvs.width+"px";
+	cvs.style.height=cvs.height+"px";
+	cvs.width=cvs.width*window.devicePixelRatio;
+	cvs.height=cvs.height*window.devicePixelRatio;
+	vpw=cvs.width;vph=cvs.height;
+	try
+	{WGL=cvs.getContext("webgl")||cvs.getContext("experimental-webgl");}
+	catch(e){WGL=null;}
+	if(!WGL){alert("WebGL is not supported by your browser...");return;}
+	
+	WGL.clearColor(0.5,0.5,0.5,1.0);
+	WGL.clearDepth(1);
+	WGL.enable(WGL.DEPTH_TEST);
+	WGL.depthFunc(WGL.LESS);
+	WGL.enable(WGL.BLEND);
+	WGL.blendFunc(WGL.SRC_ALPHA,WGL.ONE_MINUS_SRC_ALPHA);
+	WGL.clear(WGL.COLOR_BUFFER_BIT|WGL.DEPTH_BUFFER_BIT);
+	WGL.viewport(0,0,cvs.width,cvs.height);
+	
+	shp=WGL.createProgram();
+	var fshs=createShader(fsh,WGL.FRAGMENT_SHADER);
+	var vshs=createShader(vsh,WGL.VERTEX_SHADER);
+	WGL.attachShader(shp,vshs);WGL.attachShader(shp,fshs);
+	WGL.linkProgram(shp);
+	if(!WGL.getProgramParameter(shp,WGL.LINK_STATUS))
+	{
+		alert("shader link error...");
+	}
+	WGL.useProgram(shp);
+	
+	vbo=WGL.createBuffer();
+	WGL.bindBuffer(WGL.ARRAY_BUFFER,vbo);
+	WGL.bufferData(WGL.ARRAY_BUFFER,vb,WGL.STATIC_DRAW);
+	var vpp=WGL.getAttribLocation(shp,"vp");
+	var vcp=WGL.getAttribLocation(shp,"vc");
+	WGL.enableVertexAttribArray(vpp);
+	WGL.enableVertexAttribArray(vcp);
+	WGL.bindBuffer(WGL.ARRAY_BUFFER,vbo);
+	WGL.vertexAttribPointer(vpp,3,WGL.FLOAT,false,7*4,0);
+	WGL.vertexAttribPointer(vcp,4,WGL.FLOAT,false,7*4,3*4);
+	
+	for(var i=0,n=0,p=0;i<vbufsize/4;++i)
+	{
+		ib[p++]=n;ib[p++]=n+1;
+		ib[p++]=n+2;ib[p++]=n+2;
+		ib[p++]=n+3;ib[p++]=n;
+		n+=4;
+	}
+	ibo=WGL.createBuffer();
+	WGL.bindBuffer(WGL.ELEMENT_ARRAY_BUFFER,ibo);
+	WGL.bufferData(WGL.ELEMENT_ARRAY_BUFFER,ib,WGL.STATIC_DRAW);
+	
+	document.addEventListener('keydown',function(e){kst[e.code]=1;});
+	document.addEventListener('keyup',function(e)
+	{
+		kst[e.code]=0;
+		if(e.code=='KeyD'){if(ppx+1<mzw&&maz[ppx+1][ppy])++ppx;}
+		if(e.code=='KeyA'){if(ppx-1>=0&&maz[ppx-1][ppy])--ppx;}
+		if(e.code=='KeyW'){if(ppy+1<mzh&&maz[ppx][ppy+1])++ppy;}
+		if(e.code=='KeyS'){if(ppy-1>=0&&maz[ppx][ppy-1])--ppy;}
+	});
+	genmaze();
+	requestAnimationFrame(mainloop);
+}
+
+function mainloop()
+{
+	const ofx=-9,ofy=-11;
+	WGL.clearColor(0.5,0.5,0.5,1.0);
+	WGL.clearDepth(1);
+	WGL.clear(WGL.COLOR_BUFFER_BIT|WGL.DEPTH_BUFFER_BIT);
+	primc=0;
+	Mmodelview=buildIdentityMatrix();
+
+	Mmodelview=buildLookAtMatrix(pos,[15,10,0],[0,0,1]);
+	for(var i=0;i<mzw;++i)
+	for(var j=0;j<mzh;++j)
+	if(!maz[i][j])cube(i+ofx,j+ofy,0,1,0.1,0.1,0.1,1);
+	
+	cube(ppx+ofx,ppy+ofy,0,0.6,0.1,0.8,0.1,1);
+	cube(ex+ofx,ey+ofy,0,0.8,0.4,0.9,0.9,1);
+	
+	batchGL();
+	
+	requestAnimationFrame(mainloop);
+}
+
+function batchGL()
+{
+	Mprojection=buildProjectionMatrix3D(vpw,vph,60,0.1,100);
+	var mpp=WGL.getUniformLocation(shp,"mprojection");
+	WGL.uniformMatrix4fv(mpp,false,Mprojection);
+	var mvpp=WGL.getUniformLocation(shp,"mmodelview");
+	WGL.uniformMatrix4fv(mvpp,false,Mmodelview);
+	WGL.bindBuffer(WGL.ARRAY_BUFFER,vbo);
+	WGL.bufferData(WGL.ARRAY_BUFFER,vb,WGL.STATIC_DRAW);
+	WGL.drawElements(WGL.TRIANGLES,6*primc,WGL.UNSIGNED_SHORT,0);
+	primc=0;
+}
diff --git a/xp/cgxp/wglmath.js b/xp/cgxp/wglmath.js
new file mode 100644
index 0000000..1b9b9e3
--- /dev/null
+++ b/xp/cgxp/wglmath.js
@@ -0,0 +1,102 @@
+//Copyright Chris Xiong 2018
+//License: Expat (MIT)
+var v3d=function(x,y,z)
+{
+	this.x=(x!==undefined)?x:0;
+	this.y=(y!==undefined)?y:0;
+	this.z=(z!==undefined)?z:0;
+}
+v3d.prototype.l=function(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z);}
+v3d.prototype.n=function(){var L=this.l();if(L==0)return new v3d();return new v3d(this.x/L,this.y/L,this.z/L);}
+v3d.prototype.ms=function(s)
+{
+	return new v3d(this.x*s,this.y*s,this.z*s);
+}
+v3d.prototype.mm=function(m)
+{
+	return new v3d(
+		m[0]*this.x+m[4]*this.y+m[8]*this.z,
+		m[1]*this.x+m[5]*this.y+m[9]*this.z,
+		m[2]*this.x+m[6]*this.y+m[10]*this.z
+	);
+}
+v3d.prototype.add=function(b)
+{
+	return new v3d(this.x+b.x,this.y+b.y,this.z+b.z);
+}
+v3d.prototype.subtract=function(b)
+{
+	return new v3d(this.x-b.x,this.y-b.y,this.z-b.z);
+}
+v3d.prototype.dot=function(b)
+{
+	return this.x*b.x+this.y*b.y+this.z*b.z;
+}
+v3d.prototype.cross=function(b)
+{
+	return new v3d(
+		this.y*b.z-this.z*b.y,
+		this.z*b.x-this.x*b.z,
+		this.x*b.y-this.y*b.x
+	);
+}
+function buildIdentityMatrix()
+{
+	var m=new Float32Array(16);
+	for(var i=0;i<4;++i)m[i*4+i]=1.;
+	return m;
+}
+function buildProjectionMatrix2D(w,h)
+{
+	var m=buildIdentityMatrix();
+	m[0]=2/w;m[5]=2/h;m[10]=-2;
+	m[12]=m[13]=m[14]=-1;
+	return m;
+}
+function buildProjectionMatrix3D(w,h,fov,near,far)
+{
+	var m=new Float32Array(16);
+	var f=1./Math.tan(Math.PI*fov/360.);
+	var ar=w/h;
+	m[0]=f/ar;m[5]=f;m[10]=(far+near)/(near-far);
+	m[11]=-1.;m[14]=(2*far*near)/(near-far);
+	return m;
+}
+function buildTranslationMatrix(x,y,z)
+{
+	var m=buildIdentityMatrix();
+	m[12]=x;m[13]=y;m[14]=z;
+	return m;
+}
+function buildRotationMatrix(a,x,y,z)
+{
+	var m=buildIdentityMatrix();
+	//check (x,y,z) here
+	var c=Math.cos(a),s=Math.sin(a);
+	m[0]=x*x*(1-c)+c;m[4]=x*y*(1-c)-z*s;m[8]=x*z*(1-c)+y*s;
+	m[1]=y*x*(1-c)+z*s;m[5]=y*y*(1-c)+c;m[9]=y*z*(1-c)-x*s;
+	m[2]=x*z*(1-c)-y*s;m[6]=y*z*(1-c)+x*s;m[10]=z*x*(1-c)+c;
+	m[15]=1.;
+	return m;
+}
+function buildLookAtMatrix(e,a,u)
+{
+	var f=new v3d(a[0]-e[0],a[1]-e[1],a[2]-e[2]).n();
+	var up=new v3d(u[0],u[1],u[2]).n();
+	var r=f.cross(up).n();var p=r.cross(f);
+	var m=buildIdentityMatrix();
+	m[0]=r.x;m[4]=r.y;m[8]=r.z;
+	m[1]=p.x;m[5]=p.y;m[9]=p.z;
+	m[2]=-f.x;m[6]=-f.y;m[10]=-f.z;
+	m=multMatrix(m,buildTranslationMatrix(-e[0],-e[1],-e[2]));
+	return m;
+}
+function multMatrix(a,b)
+{
+	var r=new Float32Array(16);
+	for(var i=0;i<4;++i)
+	for(var j=0;j<4;++j)
+	for(var k=0;k<4;++k)
+		r[i*4+j]+=a[i*4+k]*b[k*4+j];
+	return r;
+}
-- 
cgit v1.2.3