Full version: jsB@nk » Utility » Simple 3D Graphics Animation in JavaScript
URL: https://www.javascriptbank.com/simple-3d-graphics-animation-javascript.html
Here are some 3D graphics made with just JavaScript, let teach yourself by this advance JavaScript code & tutorial. We have a TIE fighter rotating, and moving left and right; we may change axises, drawing modes, viewing styles and scenes.
Full version: jsB@nk » Utility » Simple 3D Graphics Animation in JavaScript
URL: https://www.javascriptbank.com/simple-3d-graphics-animation-javascript.html
<script type="text/javascript" from="JavaScriptBank.com">/* This script downloaded from www.JavaScriptBank.com Come to view and download over 2000+ free javascript at www.JavaScriptBank.com*//************************************* * Copyright 2006 Christopher Thomas * * You are free to redistribute this * * code, in modified or unmodified * * form, so long as you retain this * * copyright notice. * *************************************//****************************************************************************** * Due to the performance issues of painting pixels, I had to create a custom * * z-buffering algorithm that works on pixel ranges rather than individual * * pixels to reduce the number of canvas draw calls. It might be * * patentable... though I doubt it is worth anything nowadays due to the * * relative costs of operations of modern hardware (and even most software * * framebuffers). * ******************************************************************************/var canvas;var ctx;var FULL_WIDTH = 800;var FULL_HEIGHT = 600;var WIDTH = 800;var HEIGHT = 600;var avgRenderTime = 0;// x, y, zvar vert1 = [[-1,-1,-1,1], [-1,1,-1,1], [1,1,-1,1], [1, -1, -1,1], [-1,-1,1,1], [-1,1,1,1], [1,1,1,1], [1, -1, 1,1]];var tri1 = [[0, 1, 2, "rgb(255,0,0)"], [2, 3, 0, "rgb(255,0,0)"], [4, 6, 5, "rgb(0,255,0)"], [6, 4, 7, "rgb(0,255,0)"], [0, 5, 1, "rgb(0,0,255)"], [0, 4, 5, "rgb(0,0,255)"], [3, 2, 7, "rgb(0,255,255)"], [2, 6, 7, "rgb(0,255,255)"], [0, 3, 4, "rgb(255,255,0)"], [3, 7, 4, "rgb(255,255,0)"], [1, 6, 2, "rgb(255,0,255)"], [1, 5, 6, "rgb(255,0,255)"]];var vert2 = [[-1, -1.5, .51, 1], [-1, 1.5, -.51, 1], [0, -1.5, .51, 1], [-1, .5, .51, 1], [2, 1.5, -.2, 1], [-2, 1.5, .51, 1], [1, 1.5, .51, 1], [2, 1.5, .51, 1], [-1, -1.5, -.51, 1]];var tri2 = [[0, 1, 2, "rgb(255,0,0)"], [3, 5, 4, "rgb(0,255,0)"], [6, 7, 8, "rgb(0,0,255)"]];var vert3 = [[.866, 0, .5, 1], [.5, .866, .5, 1], [0, 0, .5, 1], [.5, .866, .5, 1], [-.5, .866, .5, 1], [0, 0, .5, 1], [-.5, .866, .5, 1], [-.866, 0, .5, 1], [0, 0, .5, 1], [-.866, .5, .5, 1], [-.866, -.5, .5, 1], [0, 0, .5, 1], [-.866, 0, .5, 1], [-.5, -.866, .5, 1], [0, 0, .5, 1], [-.5, -.866, .5, 1], [.5, -.866, .5, 1], [0, 0, .5, 1], [.5, -.866, .5, 1], [.866, 0, .5, 1], [0, 0, .5, 1], [.866, -.5, .5, 1], [.866, .5, .5, 1], [0, 0, .5, 1], [.866, 0, -.5, 1], [.5, .866, -.5, 1], [0, 0, -.5, 1], [.5, .866, -.5, 1], [-.5, .866, -.5, 1], [0, 0, -.5, 1], [-.5, .866, -.5, 1], [-.866, 0, -.5, 1], [0, 0, -.5, 1], [-.866, .5, -.5, 1], [-.866, -.5, -.5, 1], [0, 0, -.5, 1], [-.866, 0, -.5, 1], [-.5, -.866, -.5, 1], [0, 0, -.5, 1], [-.5, -.866, -.5, 1], [.5, -.866, -.5, 1], [0, 0, -.5, 1], [.5, -.866, -.5, 1], [.866, 0, -.5, 1], [0, 0, -.5, 1], [.866, -.5, -.5, 1], [.866, .5, -.5, 1], [0, 0, -.5, 1], [.25, 0, 0, 1], [0, .25, 0, 1], [.0, 0, -.5, 1], [.25, 0, 0, 1], [0, -.25, 0, 1], [.0, 0, -.5, 1], [-.25, 0, 0, 1], [0, .25, 0, 1], [.0, 0, -.5, 1], [-.25, 0, 0, 1], [0, -.25, 0, 1], [.0, 0, -.5, 1], [.25, 0, 0, 1], [0, .25, 0, 1], [.0, 0, .5, 1], [.25, 0, 0, 1], [0, -.25, 0, 1], [.0, 0, .5, 1], [-.25, 0, 0, 1], [0, .25, 0, 1], [.0, 0, .5, 1], [-.25, 0, 0, 1], [0, -.25, 0, 1], [.0, 0, .5, 1],];// I did not properly order some of these triangles, so they're facing the wrong wayvar tri3 = [[0, 1, 2, "rgb(64, 64, 64)"], [3, 4, 5, "rgb(64, 64, 64)"], [6, 7, 8, "rgb(64, 64, 64)"], // [9, 10, 11, "rgb(64, 64, 64)"], [12, 13, 14, "rgb(64, 64, 64)"], [15, 16, 17, "rgb(64, 64, 64)"], [18, 19, 20, "rgb(64, 64, 64)"], // [21, 22, 23, "rgb(64, 64, 64)"], [24, 25, 26, "rgb(64, 64, 64)"], [27, 28, 29, "rgb(64, 64, 64)"], [30, 31, 32, "rgb(64, 64, 64)"], // [33, 34, 35, "rgb(64, 64, 64)"], [36, 37, 38, "rgb(64, 64, 64)"], [39, 40, 41, "rgb(64, 64, 64)"], [42, 43, 44, "rgb(64, 64, 64)"], // [45, 46, 47, "rgb(64, 64, 64)"], [48, 49, 50, "rgb(128, 128, 128)"], [51, 52, 53, "rgb(128, 128, 128)"], [54, 55, 56, "rgb(128, 128, 128)"], [57, 58, 59, "rgb(128, 128, 128)"], [60, 61, 62, "rgb(128, 128, 128)"], [63, 64, 65, "rgb(128, 128, 128)"], [66, 67, 68, "rgb(128, 128, 128)"], [69, 70, 71, "rgb(128, 128, 128)"]];var vert = vert3;var tri = tri3;var twosided = true;var angle = 47.4;var axis = "X";var mode = "lines";var lastPoint = null;var fastLines = true;var fill = false;var scanLineInfo;var zbuff;var drawInterval;var dumpZ = false;function changeQuality(direction) { if (direction == "better" && WIDTH < FULL_WIDTH) { WIDTH *= 2; HEIGHT *= 2; } else if (direction == "worse" && FULL_WIDTH/WIDTH < 16){ WIDTH /= 2; HEIGHT /= 2; } if (WIDTH < FULL_WIDTH) { document.getElementById("qUpButton").disabled = false; } else document.getElementById("qUpButton").disabled = true; if (FULL_WIDTH / WIDTH >= 16) { document.getElementById("qDownButton").disabled = true; } else document.getElementById("qDownButton").disabled = false; document.getElementById("qualitySpan").innerHTML = (WIDTH / FULL_WIDTH)*100 + "%";}function init() { canvas = document.getElementById("theCanvas"); var error = false; try { ctx = canvas.getContext("2d"); } catch(e) { document.getElementById("errorMsg").style.display="block"; error = true; }; if (!error) drawInterval = setInterval(plot, 10);}function dist(a, b) { var da; var db; var dc; da = a[0] - b[0]; db = a[1] - b[1]; dc = a[2] - b[2]; return Math.sqrt(da*da + db*db + dc*dc)}function min(a, b) { return (a < b) ? a : b;}function max(a, b) { return (a > b) ? a : b;}function bresenham(x2, y2, z2) { if (!lastPoint) { lastPoint = [x2, y2, z2]; return; // first point, just set up start point } var x1 = lastPoint[0]; var y1 = lastPoint[1]; var z1 = lastPoint[2]; lastPoint = [x2,y2,z2]; var steep; var temp; steep = Math.abs(y2-y1) > Math.abs(x2-x1); if (steep) { temp = x1; x1 = y1; y1 = temp; temp = x2; x2 = y2; y2 = temp; } if (x1 > x2) { temp = x1; x1 = x2; x2 = temp; temp = y1; y1 = y2; y2 = temp; temp = z1; z1 = z2; z2 = temp; } var dx = x2 - x1; var dy = Math.abs(y2 - y1); var error = 0; var derror = dy / dx; var y = y1; var ystep; if (y1 < y2) ystep = 1; else ystep = -1; var x; var minx, maxx; var zA; var zB; for (x=x1; x<=x2; x++) { var dx = max(x2 - x1, .01); if (steep) { plotPixel(y, x); if (fill && x >= 0 && x < HEIGHT) {if (scanLineInfo[x]) { minx = scanLineInfo[x][0]; maxx = scanLineInfo[x][1]; zA = scanLineInfo[x][2]; zB = scanLineInfo[x][3];}else { minx = y; maxx = y; zA = (x-x1)/dx * (z2-z1) + z1; zB = (x-x1)/dx * (z2-z1) + z1;}if (y < minx) { minx = y; zA = (x-x1)/dx * (z2-z1) + z1;}if (y > maxx) { maxx = y; zB = (x-x1)/dx * (z2-z1) + z1;}if (isNaN(zA) || isNaN(zB)) { alert(x + " " + x1 + " " + dx + " " + z2 + " " + z1); null[5] = 0;}scanLineInfo[x] = [minx, maxx, zA, zB]; } } else { plotPixel(x, y); if (fill && y >= 0 && y < HEIGHT) {if (scanLineInfo[y]) { minx = scanLineInfo[y][0]; maxx = scanLineInfo[y][1]; zA = scanLineInfo[y][2]; zB = scanLineInfo[y][3];}else { minx = x; maxx = x; zA = (x-x1)/dx * (z2-z1) + z1; zB = (x-x1)/dx * (z2-z1) + z1;}if (x < minx) { minx = x; zA = (x-x1)/dx * (z2-z1) + z1;}if (x > maxx) { maxx = x; zB = (x-x1)/dx * (z2-z1) + z1;}scanLineInfo[y] = [minx, maxx, zA, zB]; } } error += derror; if (error > .5) { y += ystep; error--; } }}function plotPixel(x, y) { if (fill) return; ctx.fillRect(x, y, 1, 1);}function doVert(v, d, first) { var y1 = (v[1]*d) / (d + v[2]); var x1 = (v[0]*d) / (d + v[2]); var z1 = v[2]; // center 0,0 on the screen y1 *= HEIGHT; x1 *= HEIGHT; y1 += HEIGHT/2; x1 += WIDTH/2; if (mode == "lines") { if (fastLines) { if (first)ctx.moveTo(x1, y1); elsectx.lineTo(x1, y1); } else { //bresenham(parseInt(x1), parseInt(y1), parseInt(z1)); bresenham(parseInt(x1), parseInt(y1), z1); } } else if (mode == "points") { ctx.fillRect(x1-1, y1-1, 2, 2); }}function transform(v, m) { var x2 = v[0] * m[0][0] + v[1]*m[0][1] + v[2]*m[0][2] + v[3]*m[0][3]; var y2 = v[0] * m[1][0] + v[1]*m[1][1] + v[2]*m[1][2] + v[3]*m[1][3]; var z2 = v[0] * m[2][0] + v[1]*m[2][1] + v[2]*m[2][2] + v[3]*m[2][3]; var w2 = v[0] * m[3][0] + v[1]*m[3][1] + v[2]*m[3][2] + v[3]*m[3][3]; var rv = [x2, y2, z2, w2]; return rv;}function plot() { var start; var stop; try { // safari compatibility start = Date.now(); } catch (e) {} angle += .05; //angle = 94.148; axis = "Y"; fastLines = false; fill = true; dumpZ = true;clearInterval(drawInterval); //angle = 94.149; axis = "Y"; fastLines = false; fill = true; dumpZ = true;clearInterval(drawInterval); //angle = 56.7; axis = "Y"; fastLines = false; fill = true; dumpZ = true;clearInterval(drawInterval); var xposition = 1.5 * Math.cos(1.05*angle); var yposition = 0;//Math.sin(2*angle); var aboutZ = (axis == "Z"); var aboutX = (axis == "X"); var i; var j; var matrix; ctx.save(); ctx.scale(FULL_WIDTH/WIDTH, FULL_HEIGHT/HEIGHT); zbuff = []; // clear z buffer ctx.clearRect(0, 0, WIDTH, HEIGHT); // clear screen if (aboutZ) { matrix = [[Math.cos(angle), -Math.sin(angle), 0, xposition], [Math.sin(angle), Math.cos(angle), 0, yposition], [0, 0, 1, +5], [0, 0, 0, 1]]; } else if (aboutX) { matrix = [[1, 0, 0, xposition], [0, Math.cos(angle), Math.sin(angle), yposition], [0, -Math.sin(angle), Math.cos(angle), +5], [0, 0, 0, 1]]; } else { matrix = [[Math.cos(angle), 0, -Math.sin(angle), xposition], [0, 1, 0, yposition], [Math.sin(angle), 0, Math.cos(angle), +5], [0, 0, 0, 1]]; } for (i=0; i<tri.length; i++) { doTri(tri[i], matrix); } if (!fastLines && mode == "lines" && fill) drawFromZBuff(); try { // safari compatibility stop = Date.now(); avgRenderTime = (.9 * avgRenderTime) + (.1 * (stop - start)); window.status = "Frame render took " + (stop-start) + " ms (frame rate: " + parseInt(100000/avgRenderTime)/100 + " fps)"; } catch (e) { } ctx.restore();}function zForPoint(x, range, reason) { var x1; var x2; var z1; var z2; x1 = range[0]; x2 = range[1]; z1 = range[2]; z2 = range[3]; var dx = x2-x1; dx = max(dx, .001); var fraction = (x-x1) / dx; var rv = fraction * (z2-z1) + z1; if (isNaN(rv)) { clearInterval(drawInterval); alert("x: " + x + " from range " + range + "\n" + "dx was " + dx + " with fraction " + fraction + "\n" + "z1: " + z1 + " z2: " + z2 + "\n" + "requested by " + reason); null[5] = 0; } return rv;}function horizOverlap(z, scan) { var zx1; var zx2; var sx1; var sx2; zx1 = z[0]; zx2 = z[1]; sx1 = scan[0]; sx2 = scan[1]; if (zx1 >= sx2 || zx2 <= sx1) return false; // no overlap var minx, maxx, overlap; if (zx1 <= sx1 && zx2 >= sx2) { // we're smaller than zbuff overlap = "newSmaller"; } else if (sx1 <= zx1 && sx2 >= zx2) { // we cover entire range overlap = "newBigger"; } else overlap = "partial"; minx = max(zx1, sx1); maxx = min(zx2, sx2); if (minx == maxx) return false; // they touch, or it's 0 width or something, so reject this return [minx, maxx, overlap];}function cross(n1, n2) { var x, y, z; x = n1[1]*n2[2] - n1[2]*n2[1]; y = n1[2]*n2[0] - n1[0]*n2[2]; z = n1[0]*n2[1] - n1[1]*n2[0]; var w = 0; return [x, y, z, w];}function dot(v1, v2) { return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];}function normalize(v) { var l = Math.sqrt(v[0]*v[0]+v[1]*v[1]+v[2]*v[2]+v[3]*v[3]); return [v[0]/l, v[1]/l, v[2]/l, v[3]/l];}function doTri(poly, matrix) { scanLineInfo = []; lastPoint = null; if (mode == "lines" && fastLines) { ctx.beginPath(); ctx.lineJoin = "bevel"; ctx.strokeStyle = "rgb(0,0,0)"; } var str; if (dumpZ) str = document.getElementById("statusText2").innerHTML; for (j=0; j<3; j++) { var d = 1; var v = transform(vert[poly[j]], matrix); //clearInterval(2); //alert(v); doVert(v, d, j == 0); if (dumpZ) str += v.join(", ") + "<br>"; } str += " <br>"; if (dumpZ) document.getElementById("statusText2").innerHTML = str; doVert(transform(vert[poly[0]], matrix), d, false); if (mode == "lines" && fastLines) ctx.stroke(); if (mode == "lines" && fill) { var v1 = vert[poly[0]]; var v2 = vert[poly[1]]; var v3 = vert[poly[2]]; var n1 = [v2[0]-v1[0], v2[1]-v1[1], v2[2]-v1[2], 0]; var n2 = [v3[0]-v1[0], v3[1]-v1[1], v3[2]-v1[2], 0]; n1 = normalize(n1); n2 = normalize(n2); var norm = cross(n1, n2); norm = normalize(norm); norm = transform(norm, matrix); // don't show backfacing if (!twosided && dot(norm, [0, 0, -1]) < -.1) return; // lighting var lightVec = normalize([.25, -.2, -1, 0]); var scaleFactor = Math.abs(dot(norm, lightVec)); var newColor = poly[3]; newColor = newColor.replace(/.*\(/, ""); newColor = newColor.replace(/\)/, ""); newColor = newColor.split(/,/); scaleFactor = max(scaleFactor, .3); newColor = "rgb(" + parseInt(newColor[0]*scaleFactor) + "," + parseInt(newColor[1]*scaleFactor) + "," + parseInt(newColor[2]*scaleFactor) + ")"; for (var i=0; i<HEIGHT; i++) { if (i == 563563)alert("Scanline " + i + "\n" + "before: " + zbuff[i]); // was there anything drawn to this row? if (scanLineInfo[i]) {// pull out the zbuffer array for this rowvar zbrow = zbuff[i];if (!zbrow) { zbrow = [[0, WIDTH, 9999, 9999, "rgb(255,255,255)"]];}for (var j=0; j<zbrow.length; j++) { if (i == 563563) { alert("for poly " + poly + "\n" + "zbrow item " + j + "\n" + "before: " + zbuff[i]) } // is there horizontal overlap? var range = horizOverlap(zbrow[j], scanLineInfo[i]); if (range) { var zbz1; var zbz2; var mz1; var mz2; zbz1 = zForPoint(range[0], zbrow[j], "z1"); zbz2 = zForPoint(range[1], zbrow[j], "z2"); mz1 = zForPoint(range[0], scanLineInfo[i], "s1"); mz2 = zForPoint(range[1], scanLineInfo[i], "s2"); if (zbz1 >= mz1 && zbz2 >= mz2) {// over the entire overlap range, we're closer// set our material for this overlap rangeif (range[2] == "newSmaller") { // split the range up into 3 pieces {z, us, z} var newx1, newx2, newx3, newx4; newx1 = zbrow[j][0]; newx2 = scanLineInfo[i][0]; newx3 = scanLineInfo[i][1]; newx4 = zbrow[j][1]; var oldMat = zbrow[j][4]; var oldz1 = zbrow[j][2]; var oldz2 = zbrow[j][3]; var addedCount = 0; if (newx1 != newx2) { zbrow.splice(j+1+addedCount, 0, [newx1, newx2, oldz1, zbz1, oldMat]); addedCount++; } if (newx2 != newx3) { zbrow.splice(j+1+addedCount, 0, [newx2, newx3, mz1, mz2, newColor]); addedCount++; } if (newx3 != newx4) { zbrow.splice(j+1+addedCount, 0, [newx3, newx4, zbz2, oldz2, oldMat]); addedCount++; } zbrow.splice(j, 1); j += 2; // skip the 2 we added}else if (range[2] == "newBigger") { // leave the full range, but set it to our material and update the z values zbrow[j][2] = mz1; zbrow[j][3] = mz2; zbrow[j][4] = newColor;}else { // split the range into pieces, since we're not completely // contained within the range or larger than it if (zbrow[j][0] >= scanLineInfo[i][0]) { // this poly is in the left half of the interval // insert it, and move the start of original region right if (i == 563563) { var blahstr = ""; for (var blah = 0; blah < zbuff[i].length; blah++)blahstr += zbuff[i][blah] + "\n"; alert("left before\n" + "j: " + j + "\n" + "zbrow[j]: " + zbrow[j] + "\n" + "scanLineInfo[i]: " + scanLineInfo[i] + "\n" + "poly: " + poly + "\n" + "range: " + range + "\n" + "zbrow: " + blahstr); } zbrow[j][2] = zForPoint(scanLineInfo[i][1], zbrow[j], "lateCut"); zbrow[j][0] = range[1];//scanLineInfo[i][1]; if (i == 563563) alert("left mid: " + zbrow[j]); var cutCount = (zbrow[j][0] == zbrow[j][1]) ? 1 : 0; if (i == 563563 && cutCount == 1) alert("CUT!"); zbrow.splice(j, cutCount, [range[0], scanLineInfo[i][1], mz1, mz2, newColor]); //if (confirm(zbrow)) // null[5] = 0; j++; if (i == 563563) { var blahstr = ""; for (var blah = 0; blah < zbuff[i].length; blah++)blahstr += zbuff[i][blah] + "\n"; alert("left after\n" + "j: " + j + "\n" + "zbrow[j]: " + zbrow[j] + "\n" + "scanLineInfo[i]: " + scanLineInfo[i] + "\n" + "range: " + range + "\n" + "poly: " + poly + "\n" + "zbrow: " + blahstr); } } // i don' understand why this test is <= instead of >= else if (zbrow[j][1] <= scanLineInfo[i][1]) { // this poly is in the right half of the interval // make original region end early and add the poly after it if (i == 563563) { var blahstr = ""; for (var blah = 0; blah < zbuff[i].length; blah++)blahstr += zbuff[i][blah] + "\n"; alert("right before\n" + "j: " + j + "\n" + "zbrow[j]: " + zbrow[j] + "\n" + "scanLineInfo[i]: " + scanLineInfo[i] + "\n" + "poly: " + poly + "\n" + "range: " + range + "\n" + "zbrow: " + blahstr); } // TODO can this be zbz1? zbrow[j][3] = zForPoint(scanLineInfo[i][0], zbrow[j], "earlyCut"); zbrow[j][1] = range[0]; var cutCount = (zbrow[j][0] == zbrow[j][1]) ? 1 : 0; zbrow.splice(j+1, cutCount, [range[0], range[1], mz1, mz2, newColor]); //if (confirm(zbrow)) // null[5] = 0; j++; // skip over new range if (i == 563563) { var blahstr = ""; for (var blah = 0; blah < zbuff[i].length; blah++)blahstr += zbuff[i][blah] + "\n"; alert("right after\n" + "j: " + j + "\n" + "cutCount: " + cutCount + "\n" + "zbrow[j]: " + zbrow[j] + "\n" + "scanLineInfo[i]: " + scanLineInfo[i] + "\n" + "range: " + range + "\n" + "zbrow: " + blahstr); } } else if (range[0] == range[1]) { // HACK TODO FIXME!!! // this range is 0px wide, so ignore it? window.status = "ignored!"; if (i == 563563) alert("ignored"); } else { // wtf? clearInterval(drawInterval); alert("wtf?"); alert("need to split :-(\n" + "range of overlap: " + range + "\n" + "z: " + zbrow[j] + "\n" + "poly: " + scanLineInfo[i] + "\n" + "zbrow: " + zbrow); null[5] = 0; }} } else if (zbz1 <= mz1 && zbz2 <= mz2) {// already something closer... do nothingif (i == 563563) alert("already something closer"); } else {// partially in front, partially behindvar isect = findIntersection(range, mz1, mz2, zbz1, zbz2);if (i == 563563) { alert("partially in front, partially behind - doing intersect!\n" +"range: " + range + "\n" + "poly: " + scanLineInfo[i] + "\n" +"zb: " + zbrow[j] + "\n" + "isect: " + isect + "\n" + "j: " + j);}isect = parseInt(isect);var die = true;if (mz1 <= zbz1) { // we're on the left of the range, so end result should be // [existing] {[us] [existing]} // where { } indicates range of overlap if (i == 563563) { var blahstr = ""; for (var blah = 0; blah < zbuff[i].length; blah++) blahstr += zbuff[i][blah] + "\n"; alert("Partial Left Before: " + blahstr); } var newx1; var newx2; var newx3; var newx4; newx1 = zbrow[j][0]; newx2 = range[0]; newx3 = isect; newx4 = zbrow[j][1]; var oldz1 = zbrow[j][2]; var oldz2 = zbrow[j][3]; var oldMat = zbrow[j][4]; var addedCount = 0; if (newx1 != newx2) { zbrow.splice(j+1+addedCount, 0, [newx1, newx2, oldz1, zbz1, oldMat]); addedCount++; } if (newx2 != newx3) { zbrow.splice(j+1+addedCount, 0, [newx2, newx3, mz1, zForPoint(newx3, [range[0], range[1], mz1, mz2], "splitRegion"), newColor]); addedCount++; } if (newx3 != newx4) { zbrow.splice(j+1+addedCount, 0, [newx3, newx4, zForPoint(newx3, [range[0], range[1], zbz1, zbz2], "splitRegion"), oldz2, oldMat]); addedCount++; } zbrow.splice(j, 1); // cut the existing one die = false;}else if (mz2 <= zbz2) { if (i == 563563) { var blahstr = ""; for (var blah = 0; blah < zbrow.length; blah++) blahstr += zbrow[blah] + "\n"; alert("Partial Right Before: " + blahstr + "\n" + "scanLine: " + scanLineInfo[i] + "\n" + "zb: " + zbrow[j] + "\n" + "range: " + range + "\n"); } var newx1, newx2, newx3, newx4; newx1 = zbrow[j][0]; newx2 = isect; newx3 = range[1]; newx4 = zbrow[j][1]; if (i == 563563) alert(newx1 + " " + newx2 + " " + newx3 + " " + newx4); var oldz1 = zbrow[j][2]; var oldz2 = zbrow[j][3]; var oldMat = zbrow[j][4]; var addedCount = 0; if (newx1 != newx2) { zbrow.splice(j+1+addedCount, 0, [newx1, newx2, oldz1, zForPoint(isect, [range[0], range[1], zbz1, zbz2], "splitRegion"), oldMat]); addedCount++; } if (newx2 != newx3) { zbrow.splice(j+1+addedCount, 0, [newx2, newx3, zForPoint(isect, [range[0], range[1], mz1, mz2], "splitRegion"), mz2, newColor]); addedCount++; } if (newx3 != newx4) { zbrow.splice(j+1+addedCount, 0, [newx3, newx4, zbz2, oldz1, oldMat]); addedCount++; } zbrow.splice(j, 1); // cut the existing one if (i == 563563) { var blahstr = ""; for (var blah = 0; blah < zbrow.length; blah++) blahstr += zbrow[blah] + "\n"; alert("Partial Right After: " + blahstr); } die = false;}else { alert("partial, strange!");}if (die) { alert("partial :-("); alert("range: " + range + "\n" +"zbrow: " + zbrow[j] + "\n" + "poly: " + scanLineInfo[i] + "\n"); //zbz1 + "->" + zbz2 + " vs " + mz1 + "->" + mz2); clearInterval(drawInterval); null[5] = 0;} } } if (i == 563563 && zbuff[i]) { var blahstr = ""; for (var blah = 0; blah < zbuff[i].length; blah++) blahstr += zbuff[i][blah] + "\n"; alert("for poly " + poly + "\n" + "after item " + j + ": " + blahstr); }}zbuff[i] = zbrow;if (i == 563563) { var blahstr = ""; for (var blah = 0; blah < zbuff[i].length; blah++) blahstr += zbuff[i][blah] + "\n"; alert("after: " + blahstr);} } } }}// return x coordinate of intersection pointfunction findIntersection(range, za1, za2, zb1, zb2) { var dx = range[1] - range[0]; var dza = za2 - za1; var dzb = zb2 - zb1; var slopea = dza / dx; var slopeb = dzb / dx; var offseta = zForPoint(0, [range[0], range[1], za1, za2], "findIntersection"); var offsetb = zForPoint(0, [range[0], range[1], zb1, zb2], "findIntersection"); var rv = (offseta - offsetb) / (slopeb - slopea); return rv;}function drawFromZBuff() { var str; if (dumpZ) str = "<table>"; var j; for (j=0; j<HEIGHT; j++) { var zbrow = zbuff[j]; if (zbrow) { if (dumpZ)str += "<tr><td>"+j+"</td>"; var i; for (i=0; i<zbrow.length; i++) {if (!dumpZ) if (zbrow[i][4] == "rgb(255,255,255)") { continue; // don't bother drawing white }ctx.beginPath();ctx.strokeStyle = zbrow[i][4];ctx.moveTo(zbrow[i][0], j+.5);ctx.lineTo(zbrow[i][1], j+.5);ctx.stroke();if (dumpZ) str += "<td>" + zbrow[i] + "</td>"; } if (dumpZ)str += "</tr>"; } } if (dumpZ) { str += "</table>"; document.getElementById("statusText").innerHTML = str; } }window.onload = init;</script>
<p>Rotation axis: <input name="axis" value="Z" onclick="axis='Z'" type="radio"> Z <input name="axis" value="Y" onclick="axis='Y';" type="radio"> Y <input name="axis" value="X" onclick="axis='X';" checked="checked" type="radio"> X</p> <p>Draw mode: <input name="drawStyle" value="lines" onclick="mode='lines'" checked="checked" type="radio"> Lines / Polygons <input name="drawStyle" value="points" onclick="mode='points'" type="radio"> Points</p> <p>View style: <input name="fastLines" value="fast" onclick="fastLines=true;fill=false;" checked="checked" type="radio"> Built in lines (fast) <input name="fastLines" value="slow" onclick="fastLines=false;fill=false;" type="radio"> Manual Bresenham <input name="fastLines" value="true2" onclick="fill=true; fastLines=false;" type="radio"> <b>Filled polygons</b></p> <p>Scene: <input name="scene" value="square" onclick="vert=vert1;tri=tri1;twosided=false;" type="radio"> Cube <input name="scene" value="tris" onclick="vert=vert2;tri=tri2;twosided=true;" type="radio"> Mutually-overlapping triangles <input name="scene" value="tie" onclick="vert=vert3;tri=tri3;twosided=true;" checked="checked" type="radio"> <b>TIE fighter</b></p> <p>Quality: <input id="qDownButton" value="Worse (faster)" onclick="changeQuality('worse')" type="button"> <input id="qUpButton" disabled="DISABLED" value="Better (slower)" onclick="changeQuality('better')" type="button"> <span id="qualitySpan">100%</span> </p><div id="errorMsg" style="border: 5px solid red; display: none; font-size: 14pt;">Your browser doesn't support a required feature (the <a href="http://www.google.com/search?q=html+canvas+tag&start=0&start=0&ie=utf-8&oe=utf-8&client=mozilla&rls=org.mozilla:en-US:unofficial">HTML Canvas tag</a>). You could get a <a href="http://www.mozilla.org/projects/seamonkey">better browser</a> (or <a href="http://www.mozilla.com/">this one</a>, or, if you're on a Mac, Safari).</div> <canvas id="theCanvas" width="800" height="600" onmousemove="return;var y = event.clientY - document.getBoxObjectFor(document.getElementById('theCanvas')).y + document.body.scrollTop; var x = event.clientX - document.getBoxObjectFor(document.getElementById('theCanvas')).x + document.body.scrollLeft; window.status=x+', '+y;"></canvas> <div id="statusText2"></div> <div id="statusText"></div>