3
<title>3d thingy</title>
4
<style type="text/css">
5
div.z2 { position:absolute; z-index:2; }
6
div.z1 { position:absolute; z-index:1; }
8
<script type="text/javascript">
9
/**************************************************************************
10
JavaScript Graphics Library 0.0.1, Updated Source Code at Scriptersoft.com
11
Copyright (C) 2005 Kurt L. Whicher
14
This library is free software; you can redistribute it and/or
15
modify it under the terms of the GNU Lesser General Public
16
License as published by the Free Software Foundation; either
17
version 2.1 of the License, or (at your option) any later version.
19
This library is distributed in the hope that it will be useful,
20
but WITHOUT ANY WARRANTY; without even the implied warranty of
21
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22
Lesser General Public License for more details.
24
You should have received a copy of the GNU Lesser General Public
25
License along with this library; if not, write to the Free Software
26
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
27
**************************************************************************/
29
//________________________________________ global variables
31
var S_piDoubled=Math.PI*2;
32
var S_deg2Rad=Math.PI/180;
34
//_______________________________________________ functions
42
function S_vec2D(x,y) { this.x=x; this.y=y; }
43
function S_vec3D(x,y,z) { this.x=x; this.y=y; this.z=z; }
44
function S_subVec2D(a,b) {
45
return new S_vec2D(a.x-b.x, a.y-b.y);
47
function S_subVec3D(a,b) {
48
return new S_vec3D(a.x-b.x, a.y-b.y, a.z-b.z);
50
function S_dotVec3D(a, b) { return a.x*b.x+a.y*b.y+a.z*b.z; }
51
function S_cross(a,b) {
52
return new S_vec3D( a.y*b.z-a.z*b.y, a.z*b.x-a.x*b.z, a.x*b.y-a.y*b.x);
54
function S_lengthSquaredVec3D(v) { return S_dotVec3D(v,v); }
55
function S_lengthVec3D(v) { return Math.sqrt(S_lengthSquaredVec3D(v)); }
56
function S_normalizeVec3D(v) {
57
var l=S_lengthVec3D(v), nv=new S_vec3D(0,0,0);
58
if(l!=0) { nv.x=v.x/l; nv.y=v.y/l; nv.z=v.z/l; }
61
function S_rotate(m,ax,a) { // transformation matrix, axis, angle
62
var i,j,ij=new Array(),v=new Array(),c=Math.cos(a),s=Math.sin(a);
63
if (ax=="x") ij=[1,2,5,6,9,10,13,14];
64
else if (ax=="y") ij=[2,0,6,4,10,8,14,12];
65
else if (ax=="z") ij=[0,1,4,5,8,9,12,13];
66
for (i=0;i<8;i++) v[i]=m[ij[i]];
67
for (i=0,j=1;i<8;i+=2,j+=2) {
68
m[ij[i]]=v[i]*c-v[j]*s;
69
m[ij[j]]=v[i]*s+v[j]*c
72
function S_checkBrowser() {
73
if (document.getElementById) return true; else return false;
75
function S_zIndex(e,z) { document.getElementById(e).style.zIndex=z; }
76
function S_rgbColor(r,g,b) {
79
c[i]=Math.floor(c[i]);
80
if(c[i]<0) c[i]=0; else if(c[i]>255) c[i]=255;
84
function S_rgbColorString(c) {
85
return "rgb("+c[0]+","+c[1]+","+c[2]+")";
87
function S_vertice(x,y,z) {
88
this.x=x; this.y=y; this.z=z; this.w=1;
89
this.t=new S_vec3D(x,y,z); // transformed 3d
90
this.p=new S_vec2D(0,0); // projected 2d
92
function S_face(v0,v1,v2,c) { // 3 vertice faces
93
this.v=[v0,v1,v2]; this.c=c; this.b=0; // b:brightness
94
this.d=true; // display: true or false
96
// x coordinate, number of vertices, distance
97
function S_verticeRing(x,nv,d) {
98
var i,a,v=new Array();
101
v[i]=new S_vertice(x,d*Math.sin(a),d*Math.cos(a));
105
function S_triangleRing(r1,r2,c,clr) { // rows 1 & 2, cols, color
106
var i,j,tr=new Array();
107
for(i=0,j=1;i<c;i++,j=++j%c) {
108
tr.push(new S_face(r1+i,r2+i,r2+j,clr));
109
tr.push(new S_face(r1+i,r2+j,r1+j,clr));
113
function S_model(v,f) {
114
// vertice & face arrays, transformation matrix, display boolean
115
this.v=v; this.f=f, this.tm=S_matrix(), this.d=true;
117
S_model.prototype.S_rotateX=function(a) {
118
S_rotate(this.tm,"x",a*=S_deg2Rad);
120
S_model.prototype.S_rotateY=function(a) {
121
S_rotate(this.tm,"y",a*=S_deg2Rad);
123
S_model.prototype.S_rotateZ=function(a) {
124
S_rotate(this.tm,"z",a*=S_deg2Rad);
126
S_model.prototype.S_show=function() { this.d=true; }
127
S_model.prototype.S_hide=function() { this.d=false; }
128
function S_cube(d,c) { //distance & color
129
return new S_cone(d,d,Math.cos(Math.PI/4)*d*2,1,4,c);
131
function S_cylinder(w,h,r,c,clr,e) {
132
return new S_cone(w,w,h,r,c,clr,e);
134
// width, height, "rows", "columns", color, ends
135
function S_cone(w1,w2,h,r,c,clr,e) {
136
var i,r1=0,r2=c,v=new Array(),t=new Array(),rxc=r*c;
138
v=v.concat(S_verticeRing(h*(0.5-i/r),c,w1*i/r+w2*(r-i)/r));
139
for(i=0;i<r;i++,r1+=c,r2+=c)
140
t=t.concat(S_triangleRing(r1,r2,c,clr));
142
for(i=1;i<(c-1);i++) {
143
t.push(new S_face(0,i,i+1,clr));
144
t.push(new S_face(rxc,rxc+i+1,rxc+i,clr));
146
return new S_model(v,t);
148
function S_sphere(d,r,c,clr) {
149
// distance, "rows">=2, "columns">=3, color paramaters
150
var v=new Array(),t=new Array(),r_1xc=(r-1)*c,r_2xc=(r-2)*c;
151
var i,j,tmp,r1=0,r2=c;
154
v=v.concat(S_verticeRing(d*Math.cos(tmp),c,Math.sin(tmp)*d));
156
v.push(new S_vertice( d,0,0));
157
v.push(new S_vertice(-d,0,0));
158
for(i=0;i<(r-2);i++,r1+=c,r2+=c)
159
t=t.concat(S_triangleRing(r1,r2,c,clr));
160
for(i=0,j=1;i<c;i++,j=++j%c) {
161
t.push(new S_face(r_1xc,i,j,clr));
162
t.push(new S_face(r_1xc+1,r_2xc+j,r_2xc+i,clr));
164
return new S_model(v,t);
166
S_model.prototype.S_scale=function(x) {
167
this.tm[0]*=x; this.tm[5]*=x; this.tm[10]*=x;
169
S_model.prototype.S_faceColor=function(i,c) { this.f[i].c=c; }
170
S_model.prototype.S_scaleX=function(s) { this.tm[0]*=s; }
171
S_model.prototype.S_scaleY=function(s) { this.tm[5]*=s; }
172
S_model.prototype.S_scaleZ=function(s) { this.tm[10]*=s; }
173
function S_scene(dv,l,t,w,h,cmra) { // left, top, width, height
175
this.ps=1; // pixel size
176
this.l=l; this.t=t; this.w=w; this.h=h;
177
this.cx=l+w/2; this.cy=t+h/2; // center x, center y
178
this.dt="paint"; // output type
179
this.m=new Array(); // model array
180
this.lght=new S_light();
181
this.lc=S_rgbColor(255,255,255); // light color
182
this.cmra=-cmra; // camera on z axis
183
this.bfr=S_buffer(h,w);
185
function S_buffer(h,w) {
186
var i, j, b=new Array();
189
for(j=0;j<w;j++) b[i][j]=new S_pixel();
193
function S_pixel() { // display boolean, color
194
this.d=true; this.c=0;
196
S_pixel.prototype.S_setColor=function(c) {
197
this.d=true; this.c=c;
199
S_pixel.prototype.S_hide=function() { this.d=false; }
200
S_scene.prototype.S_pixelSize=function(ps){ this.ps=ps; }
201
S_scene.prototype.S_widthAndHeight=function(w,h){ this.w=w; this.h=h; }
202
S_scene.prototype.S_center=function(cx,cy){ this.cx=cx; this.cy=cy; }
203
S_scene.prototype.S_paint=function(){ this.dt="paint"; }
204
S_scene.prototype.S_models=function() {
205
var i; this.m=new Array();
206
for(i=0;i<arguments.length;i++) this.m.push(arguments[i]);
208
S_scene.prototype.S_lightColor=function(c){ this.lc=c; }
209
S_scene.prototype.S_project=function() {
210
var i, j, v, tm, d, m;
211
for(i=0;i<this.m.length;i++) {
212
m=this.m[i]; tm=this.m[i].tm;
213
for(j=0;j<m.v.length;j++) {
215
v.t.x=v.x*tm[0]+v.y*tm[4]+v.z*tm[8]+v.w*tm[12];
216
v.t.y=v.x*tm[1]+v.y*tm[5]+v.z*tm[9]+v.w*tm[13];
217
v.t.z=v.x*tm[2]+v.y*tm[6]+v.z*tm[10]+v.w*tm[14];
218
d=(this.cmra-v.t.z/2);
220
v.p.x=(this.cmra*v.t.x/d)+this.cx;
221
v.p.y=-(this.cmra*v.t.y/d)+this.cy;
226
S_scene.prototype.S_display=function(disp){
227
var i, j, k, s="", ds, c, cnt=0; // ds:div start
228
this.tr=new Array(); // triangles ready to draw
230
this.S_adjustLight();
231
this.S_clearBuffer();
232
for(i=0;i<this.m.length;i++) {
233
this.m[i].S_setupFaces(this.tr,this.lght.t);
234
for(j=0;j<this.tr.length;j++) { // loop through triangles
235
c=S_divColor(this.tr[j].c,this.lc,this.tr[j].b);
236
S_setupBuffer(this,this.tr[j].p,c);
239
for(i=0;i<this.h;i++) {
241
for(j=0,k=1;j<this.w;j++,k++) {
242
if((this.bfr[i][j].d==true)&&(ds==-1)) ds=j;
243
if( (this.bfr[i][j].d==true)&&
245
(this.bfr[i][k].d==false)||
246
(!S_sameColor(this.bfr[i][j].c, this.bfr[i][k].c)) ) ) {
247
s+=S_divString(S_rgbColorString(this.bfr[i][j].c),this.t+i*this.ps,this.l+ds*this.ps,this.ps,(k-ds)*this.ps);
253
S_writeInnerHTML(this.dv,s);
254
if(disp=="ShowCount") alert(cnt);
256
S_scene.prototype.S_displayAndShowCount=function(){
257
this.S_display("ShowCount");
259
S_model.prototype.S_setupFaces=function(tr,lght) {
260
var i, j, fn, v, p=new Array(); // vertice & projection arrays
262
for(i=0;i<this.f.length;i++) { // loop through faces
264
for(j=0;j<3;j++) { p[j]=this.v[v[j]].p; }
265
for(j=0;j<3;j++) { z[j]=this.v[v[j]].t.z; }
266
if (((p[1].x-p[0].x)*(p[2].y-p[0].y))<((p[2].x-p[0].x)*(p[1].y-p[0].y))) {
268
fn=S_faceNormal(this.v[v[0]].t, this.v[v[1]].t, this.v[v[2]].t);
269
this.f[i].b=S_faceIntensity(fn,lght);
270
tr.push(new S_triangle(fn,this.f[i].b,p.slice(),this.f[i].c,z));
271
} else { this.f[i].d=false; }
274
// normal, brightness, array of 2D projection coordinates, and z depth
275
function S_triangle(fn,b,p,c,z) {
276
this.fn=fn; this.b=b; this.p=p; this.z=z; this.c=c;
278
function S_faceNormal(a,b,c){
279
var cr=S_cross(S_subVec3D(b,a), S_subVec3D(b,c));
280
return S_normalizeVec3D(cr);
282
function S_faceIntensity(fn,lght) {
283
var i=S_dotVec3D(fn,lght); return (i>0)?i:0;
285
function S_divColor(c,lc,b) { // c:array of colors
286
var i, clr=new Array();
287
for(i=0;i<3;i++) clr[i]=Math.floor(c[i]+(lc[i]-c[i]+1)*b);
288
for(i=0;i<3;i++) if (clr[i]>lc[i]) { clr[i]=lc[i]; }
289
return S_rgbColor(clr[0],clr[1],clr[2]);
291
function S_sameColor(a,b) {
292
for(var i=0;i<3;i++) { if(a[i]!=b[i]) return false; }
295
function S_setupBuffer(scn,p,c) {
296
// temp, counters, min, max, scanline, vertice & slope arrays
297
var t,i,j,xmin=new Array(),xmax=new Array(),sl;
298
var v=new Array(), m=new Array();
299
p.sort(function(a,b) { return a.y-b.y; } );
300
for(i=0;i<3;i++) p[i].y=Math.floor(p[i].y);
301
v[0]=S_subVec2D(p[1],p[0]);
302
v[1]=S_subVec2D(p[2],p[0]);
303
v[2]=S_subVec2D(p[2],p[1]);
304
for(i=0;i<3;i++) { m[i]=(v[i].y!=0)?v[i].x/v[i].y:0; }
305
for(i=0,sl=scn.t;i<scn.h;i++,sl++) {
306
xmin[i]=1000;xmax[i]=0;
307
if((sl>=p[0].y)&&(sl<=p[2].y)) {
308
xmin[i]=xmax[i]=Math.floor(p[0].x+m[1]*(sl-p[0].y));
310
if((sl>=p[0].y)&&(sl<=p[1].y)) {
311
t=Math.floor(p[0].x+m[0]*(sl-p[0].y));
312
if(t<xmin[i]) xmin[i]=Math.floor(t);
313
else if(t>xmax[i]) xmax[i]=Math.floor(t);
315
if((sl>=p[1].y)&&(sl<=p[2].y)) {
316
t=Math.floor(p[1].x+m[2]*(sl-p[1].y));
317
if(t<xmin[i]) xmin[i]=Math.floor(t);
318
else if(t>xmax[i]) xmax[i]=Math.floor(t);
321
if((j>=(xmin[i]-scn.l))&&(j<=(xmax[i]-scn.l))) {
322
scn.bfr[i][j].d=true; scn.bfr[i][j].c=c;
327
this.x=0; this.y=1; this.z=0; this.w=1; // original coordinates
328
this.t=new S_vec3D(0,1,0); // transformed coordinates
329
this.tm=new S_matrix();
331
S_scene.prototype.S_adjustLight=function() {
332
var m=this.lght.tm, l=this.lght;
333
l.t.x=l.x*m[0]+l.y*m[4]+ l.z*m[8]+l.w*m[12];
334
l.t.y=l.x*m[1]+l.y*m[5]+ l.z*m[9]+l.w*m[13];
335
l.t.z=l.x*m[2]+l.y*m[6]+ l.z*m[10]+l.w*m[14];
336
l.t=S_normalizeVec3D(l.t);
338
S_scene.prototype.S_lightRotateX=function(a) {
339
S_rotate(this.lght.tm,"x",a*=S_deg2Rad);
341
S_scene.prototype.S_lightRotateY=function(a) {
342
S_rotate(this.lght.tm,"y",a*=S_deg2Rad);
344
S_scene.prototype.S_lightRotateZ=function(a) {
345
S_rotate(this.lght.tm,"z",a*=S_deg2Rad);
347
S_scene.prototype.S_clearBuffer=function() {
348
for(var i=0;i<this.h;i++)
349
for(var j=0;j<this.w;j++) this.bfr[i][j].d=false;
351
function S_divString(b,t,l,h,w) {
352
var s='<div style="background-color:'+b+';position:absolute;';
353
s+='top:'+t+'px;left:'+l+'px;height:'+h+'px;width:'+w;
354
return s+'px;font-size:0;visibility:visible"></div>';
356
function S_writeInnerHTML(id,text) {
357
document.getElementById(id).innerHTML = text;
362
<div class="z1" id="graphicsDiv">Text to be replaced with graphics.</div>
363
<script type="text/javascript">
364
if(S_checkBrowser()) {
366
// Create a new scene with parameters for
367
// div id, left, top, width, height, and camera distance
368
var scn=new S_scene("graphicsDiv",75,25,100,100,300);
369
scn.S_pixelSize(3); // set scene pixel size
370
var c=S_rgbColor(0,0,127); // color
371
var c2=S_rgbColor(0,127,127); // color
372
var m=new S_cube(18,c); // model
375
m.S_scaleX(2.5); // scale model along x axis
376
scn.S_models(m); // add model(s) to scene
377
scn.S_lightRotateX(-25); // adjust light
378
function r(){ // rotation function
379
m.S_rotateX(11); // rotate model around y axis
380
m.S_rotateY(5); // rotate model around y axis
381
m.S_rotateZ(7); // rotate model around z axis
382
scn.S_display(); // display scene
383
} // end rotation function
384
intrvl=setInterval('r();',75);