<HTML xmlns:v="urn:schemas-microsoft-com:vml">
<STYLE>
v\:* { behavior: url(#default#vml); }
</STYLE>
<head>
<style>
button { font-face:arial;font-size:10px;border:1px solid black;}
input { font-face:arial;font-size:10px;border:1px solid black;}
</style>
<script>
/********************************************/
/*********************************************
JavaScript 3D - points
BY JOEY FORTUNA
http://neoncelery.com
COPYRIGHT (C) 2004, Joey Fortuna
PERMISSION TO USE GRANTED PROVIDING THE
ADOPTER INCLUDES THIS NOTICE
*********************************************/
/********************************************/
var nGon;
var moveX=0;
var oldMoveX=0;
var moveY=0;
var oldMoveY=0;
var xRotate=0;
var yRotate=0;
var bRightMouseDown=false;
var bLeftMouseDown=false;
var iDistance=525;
var iFov=590;
var iLineYDiff=60;
function drawPolygon() {
nGon=new nGonObj();
getWinSize();
/*******************
X-WING FIGHTER
point coords
..probably better to define faces in triplets
********************/
var strPoints="-25,-75,25 25,-75,25 25,-75,-25 -25,-75,-25"; // roof of cab
strPoints+=" -50,-50,50 50,-50,50 50,-50,-50 -50,-50,-50"; // outer roof of cab
strPoints+=" -50,50,-50 50,50,-50 50,50,50 -50,50,50" // outer base of cab
strPoints+=" -25,75,25 25,75,25 25,75,-25 -25,75,-25"; //base of cab
strPoints+=" 25,25,75 -25,25,75 -25,-25,75 25,-25,75"; //nose
strPoints+=" 25,25,-75 -25,25,-75 -25,-25,-75 25,-25,-75"; //aft
strPoints+=" -75,25,25 -75,25,-25 -75,-25,25 -75,-25,-25"; // left inner strut
strPoints+=" 75,25,25 75,25,-25 75,-25,25 75,-25,-25"; // right inner strut
strPoints+=" -125,15,25 -125,15,-25 -125,-15,25 -125,-15,-25"; // left outer strut
strPoints+=" 125,15,25 125,15,-25 125,-15,25 125,-15,-25"; // right outer strut
strPoints+=" -135,25,45 -135,25,-45 -135,-25,45 -135,-25,-45"; // left wing hub
strPoints+=" 135,25,45 135,25,-45 135,-25,45 135,-25,-45"; // right wing hub
strPoints+=" -155,105,50 -155,105,-50 -155,-105,50 -155,-105,-50"; // left inner wing
strPoints+=" 155,105,50 155,105,-50 155,-105,50 155,-105,-50"; // right inner wing
strPoints+=" -175,80,60 -175,80,-60 -175,-80,60 -175,-80,-60"; // left outer wing
strPoints+=" 175,80,70 175,80,-70 175,-80,70 175,-80,-70"; // right outer wing
nGon.init(strPoints);
nGon.rotate(0,0,0);
}
function getWinSize()
{
winX = document.body.clientWidth - 10;
winY = document.body.clientHeight - 10;
nGon.centerX=winX/2;
nGon.centerY=winY/2;
}
function nGonPointObj(tid,x,y,z) {
this.id=tid;
this.x=x;
this.y=y;
this.z=z;
this.scrX=x;
this.scrY=y;
var newObj=newObj=document.createElement("div");
newObj.id="nGonPoint"+tid;
newObj.innerHTML="";
newObj.style.position="absolute";
newObj.style.display="inline";
newObj.style.color="red";
newObj.style.textAlign="center";
newObj.style.fontWeight="bold";
newObj.style.fontSize="16px";
newObj.style.fontFamily="arial";
newObj.style.width="20px";
newObj.style.heigth="20px";
newObj.style.cursor="hand";
newObj.style.top=this.y+"px";
newObj.style.left=this.x+"px";
var divObj=document.body.appendChild(newObj);
this.divObj=divObj;
this.redraw=NGON_POINT_redraw;
return this;
}
function nGonFaceObj(p1,p2,p3) {
var objShape=document.body.appendChild(document.createElement("v:shape"));
objShape.style.position="absolute";
objShape.style.display="inline";
objShape.style.zindex="-1";
objShape.fillcolor="silver";
objShape.coordorigin="0,0";
this.shape=objShape;
this.p1=p1;
this.p2=p2;
this.p3=p3;
return this;
}
function nGonObj() {
this.centerX=0;
this.centerY=0;
this.centerZ=0;
this.parallel=false;
this.name="NGonObject";
this.nPoints=new Array();
this.nFaces=new Array();
this.angleDivisor=0;
this.angle=0;
this.rotate=NGON_rotate;
this.clear=NGON_clear;
this.addPoint=NGON_addPoint;
this.addFace=NGON_addFace;
this.init=NGON_init;
this.drawFaces=NGON_drawFaces;
return this;
}
function NGON_POINT_redraw() {
if (this.z<-50) {
this.divObj.style.backgroundColor="#990000";
this.divObj.style.zIndex="10";
this.divObj.style.fontSize="10px";
}
else if (this.z<-25) {
this.divObj.style.backgroundColor="#999900";
this.divObj.style.zIndex="20";
this.divObj.style.fontSize="12px";
}
else if (this.z<-0) {
this.divObj.style.backgroundColor="#339900";
this.divObj.style.zIndex="30";
this.divObj.style.fontSize="14px";
}
else if (this.z<-25) {
this.divObj.style.backgroundColor="#009999";
this.divObj.style.zIndex="40";
this.divObj.style.fontSize="16px";
}
else if (this.z<50) {
this.divObj.style.backgroundColor="#003399";
this.divObj.style.zIndex="50";
this.divObj.style.fontSize="18px";
}
else {
this.divObj.style.backgroundColor="#000099";
this.divObj.style.zIndex="60";
this.divObj.style.fontSize="20px";
}
this.divObj.style.left=this.scrX+"px";
this.divObj.style.top=this.scrY+"px";
}
function NGON_init(strPoints) {
// passed an array of points: "200,200,0 300,200,0 250,200,0"
// create n pointObjs
// create n faceObjs
var pointArray=strPoints.split(" ");
for (i=0;i<pointArray.length;i++) {
var coorArray=pointArray[i].split(",");
var objPoint= new nGonPointObj(i,this.centerX+parseInt(coorArray[0]),this.centerY+parseInt(coorArray[1]),parseInt(coorArray[2]));
this.addPoint(objPoint);
/*
if (i==2) {
var objFace = new nGonFaceObj(this.nPoints[i],this.nPoints[i-1],this.nPoints[i-2]);
this.addFace(objFace);
}
*/
}
}
function NGON_clear() {
for (i=this.nPoints.length-1;i>=0;i--) {
this.nPoints[i].divObj.style.display="none";
this.nPoints[i].divObj=null;
this.nPoints.pop(i);
}
while (this.nPoints.length>0) this.nPoints.pop(0);
for (i=this.nFaces.length-1;i>=0;i--) {
this.nFaces[i].shape.style.display="none";
this.nFaces[i].shape=null;
this.nFaces[i]=null;
this.nFaces.pop(i);
}
while (this.nFaces.length>0) this.nFaces.pop(0);
}
function NGON_addFace(obj) {
this.nFaces[this.nFaces.length]=obj;
}
function NGON_addPoint(obj) {
this.nPoints[this.nPoints.length]=obj;
}
function showFace(objFace,strPath) {
objFace.shape.style.display="inline";
objFace.shape.style.width=winX;
objFace.shape.style.height=winY;
objFace.shape.coordsize=winX+","+winY;
objFace.shape.path.v=strPath;
}
function NGON_drawFaces () {
var strPath="";
var dprod=0;
for (i=0;i<this.nFaces.length;i++) {
strPath="m";
strPath+=parseInt(this.nFaces[i].p1.scrX)+","+parseInt(this.nFaces[i].p1.scrY-iLineYDiff);
strPath+=" l ";
strPath+=parseInt(this.nFaces[i].p2.scrX)+","+parseInt(this.nFaces[i].p2.scrY-iLineYDiff);
strPath+=" " + parseInt(this.nFaces[i].p3.scrX)+","+parseInt(this.nFaces[i].p3.scrY-iLineYDiff);
strPath+="xe";
dprod=faceNormal(this.nFaces[i].p1,this.nFaces[i].p2,this.nFaces[i].p1,this.nFaces[i].p3);
if (dprod>0) {
showFace(this.nFaces[i],strPath);
} else this.nFaces[i].shape.style.display="none";
}
}
function faceNormal(point1,point2,point3,point4) {
var sx1=point1.scrX-point2.scrX;
var sy1=point1.scrY-point2.scrY;
var sz1=point1.z-point2.z;
var sx2=point3.scrX-point4.scrX;
var sy2=point3.scrY-point4.scrY;
var sz2=point3.z-point4.z;
var dpx = sy1 * sz2 - sy2 * sz1;
var dpy = sx2 * sz1 - sx1 * sz2;
var dpz= sx1 * sy2 - sx2 * sy1;
var dprod = 0 * dpx + 0 * dpy + iFov*(dpz/iDistance);
return dprod;
}
function NGON_rotate(xRotate,yRotate,iZoom) {
var xRotateAngle=(-yRotate)*(2*Math.PI)/180;
var yRotateAngle=(-xRotate)*(2*Math.PI)/180;
var zRotateAngle=0;//xRotate*(2*Math.PI)/180;
for (i=0;i<this.nPoints.length;i++) {
var pointObj=this.nPoints[i];
var x=pointObj.x-this.centerX;
var y=this.centerY-pointObj.y;
var z=pointObj.z;
var newy=y;
var newx=x;
var newz=z;
newy=(y*Math.cos(xRotateAngle))-(z*Math.sin(xRotateAngle)); // X axis
newz=(z*Math.cos(xRotateAngle))+(y*Math.sin(xRotateAngle));
y=newy;
z=newz;
newz=(z*Math.cos(yRotateAngle))-(x*Math.sin(yRotateAngle)); // Y axis
newx=(x*Math.cos(yRotateAngle))+(z*Math.sin(yRotateAngle));
z=newz;
x=newx;
newx=(x*Math.cos(zRotateAngle))-(y*Math.sin(zRotateAngle)); // Z axis
newy=(y*Math.cos(zRotateAngle))+(x*Math.sin(zRotateAngle));
x=newx;
y=newy;
// PARALLEL PROJECTION //
pointObj.x=newx+this.centerX;
pointObj.y=this.centerY-newy;
// PERSPECTIVE PROJECTION //
// ** DO THIS WITH X/Y VALUES
// ** DERIVED FROM PARALLEL ROTATION
// ** BUT DON''T UPDATE POINTOBJ.X/Y
// ** WITH PROJECTED RESULTS!
iDistance+=iZoom;
if (!this.parallel) {
pointObj.scrX = ((iFov*newx) / (iDistance-(newz+this.centerZ))) + (this.centerX);
pointObj.scrY = (this.centerY) - ((iFov*newy) / (iDistance-(newz+this.centerZ)));
}
else {
pointObj.scrX=pointObj.x;
pointObj.scrY=pointObj.y;
}
pointObj.z=newz;
pointObj.redraw();
}
this.drawFaces();
}
function MoveHandler(e) {
moveX = window.event.x + document.body.scrollLeft;
moveY = window.event.y;
if (moveX<oldMoveX) xRotate=1;
else if(moveX>oldMoveX) xRotate=-1;
else xRotate=0;
if (moveY<oldMoveY) yRotate=1;
else if(moveY>oldMoveY) yRotate=-1;
else yRotate=0;
oldMoveX=moveX;
oldMoveY=moveY;
if (bRightMouseDown && moveX%2==0 && (xRotate!=0 || yRotate!=0)) {
nGon.rotate(xRotate,yRotate,0);
}
else if (nGon) {
for (i=1;i<nGon.nPoints.length;i++) {
var objPoint=nGon.nPoints[i];
if (moveX>objPoint.scrX-10 &&
moveX<objPoint.scrX+10 &&
moveY>objPoint.scrY-10 &&
moveY<objPoint.scrY+10 &&
bLeftMouseDown) {
objPoint.x=moveX;
objPoint.y=moveY;
objPoint.scrX=moveX;
objPoint.scrY=moveY;
objPoint.redraw();
}
}
}
}
function KeyHandler(e) {
switch(window.event.keyCode) {
case 51:
nGon.clear();
nGon.init();
break;
case 16: // strafe left;
nGon.centerX-=10;
nGon.rotate(0,0,0);
break;
case 67: // strafe right;
nGon.centerX+=10;
nGon.rotate(0,0,0);
break;
case 80: // toggle parallel
nGon.parallel=!nGon.parallel;
projection.innerHTML=(nGon.parallel)?"parallel projection":"perspective projection";
nGon.rotate(0,0,0);
break;
case 37:
nGon.rotate(1,0,0);
break;
case 38:
nGon.rotate(0,1,0);
break;
case 39:
nGon.rotate(-1,0,0);
break;
case 40:
nGon.rotate(0,-1,0);
break;
case 83:
nGon.rotate(0,0,-1);
break;
case 90:
nGon.rotate(0,0,1);
break;
default:
break;
}
}
function PressHandler(e) {
mousegrabber.setCapture(true);
if (window.event.button==1) bLeftMouseDown=true;
else if (window.event.button==2) {bRightMouseDown=true;}
return false;
}
function UpHandler(e) {
mousegrabber.releaseCapture();
bLeftMouseDown=false;
bRightMouseDown=false;
return false;
}
window.onresize = getWinSize;
document.onmouseup=UpHandler;
document.onkeydown = KeyHandler;
document.onmousemove = MoveHandler;
document.onmousedown = PressHandler;
document.oncontextmenu=new Function("return false;");
</script>
<LINK rel="stylesheet" type="text/css" href="style.css">
</head>
<body onload="drawPolygon();">
<div onmouseup="this.releaseCapture();" id="mousegrabber" style="border:none;font-family:arial;">
<table width=100% cellpadding=0 cellspacing=0>
<tr>
<td>3D Engine - Points</td>
<td align=right><font style="font-size:12px;">
<script src="nav.js"></script>
</td>
</tr>
</table>
<table><tr>
<td><font style="font-size:10px;"><b>arrow keys</b> </td><td><font style="font-size:10px;">- step rotate </td></tr><tr>
<td><font style="font-size:10px;"><b>right-click & drag</b> </td><td><font style="font-size:10px;">- free rotate</td></tr>
<td><font style="font-size:10px;"><b>s</b> </td><td><font style="font-size:10px;">- zoom in</td></tr>
<td><font style="font-size:10px;"><b>z</b> </td><td><font style="font-size:10px;">- zoom out</td></tr>
<td><font style="font-size:10px;"><b>p</b> </td><td><font style="font-size:10px;">- toggle parallel / perspective projection</td></tr>
<td colspan=2><font style="font-size:10px;">*note: window resize shifts center and may cause funky orbit</td></tr>
</tr>
</td>
</table><br>
<font style="font-size:10px;">
</font>
<div id="projection" style="font-size:10px;font-weight:bold;color:#990000;">perspective projection</div>
</div>
<div id="centerPoint" style="position:absolute;top=100px;left=100px;display:none;">@</div>
</body>