niotso/Tools/zbuffer/index.html

152 lines
No EOL
4.7 KiB
HTML

<script>
window.onload = init;
function LoadSpriteset(names) {
images = new Array(names.length);
imagesloaded = 0;
imagecount = 1 + names.length * 3;
ext = ['a', 'p', 'z'];
for (i = 0; i < names.length; i++) {
images[i] = new Array(3);
for (j = 0; j < 3; j++) {
img = new Image();
img.idi = i, img.idj = j;
img.src = names[i] + '_' + ext[j] + ".png";
img.onload = function() {
context.drawImage(this, 0, 0);
images[this.idi][this.idj] = context.getImageData(0, 0, 136, 384);
delete this;
if (++imagesloaded == imagecount) {
redraw = true;
setInterval(update, 16);
}
};
}
}
}
function init() {
// capture keys
left = 0;
right = 0;
up = 0;
down = 0;
window.onkeydown = function(evt) {
if (evt.keyCode == 37) left = 1;
if (evt.keyCode == 38) up = 1;
if (evt.keyCode == 39) right = 1;
if (evt.keyCode == 40) down = 1;
};
window.onkeyup = function(evt) {
if (evt.keyCode == 37) left = 0;
if (evt.keyCode == 38) up = 0;
if (evt.keyCode == 39) right = 0;
if (evt.keyCode == 40) down = 0;
};
// end capture keys
// The game does not use true isometric projection because each tile is 128x64 (close), 64x32 (medium), or 32x16 (far)
// which, when tilex or tiley is the hypotenuse, does not form a 30-60-90 triangle.
// It's actually arctan(1/2)-arctan(2/1)-90. The image is compressed vertically a bit to allow for power-of-2 texture sizes.
tilex = 0;
tiley = 0;
sin60 = 2.0/Math.sqrt(5); // sin(arctan(2)) or cos(arctan(1/2))
sin30 = 1.0/Math.sqrt(5); // sin(arctan(1/2)) or cos(arctan(2))
sqrt5120 = 32*Math.sqrt(5);
debug = document.getElementById('debug');
canvas = document.getElementById('draw');
context = canvas.getContext('2d');
background = new Image();
background.src = "background.png";
background.onload = function() {
context.drawImage(this, 0, 0);
delete this;
background = context.getImageData(0, 0, 136, 384);
if (++imagesloaded == imagecount) {
redraw = true;
setInterval(update, 16);
}
}
LoadSpriteset(["Chair-Liv-Deco_large_front", "tower_large_ne"]);
render = context.createImageData(136, 384);
}
function Blend(sourceid, soffset)
{
sa = images[sourceid][0].data[soffset+0] / 255.0;
if (sa == 0) return;
sr = images[sourceid][1].data[soffset+0];
sg = images[sourceid][1].data[soffset+1];
sb = images[sourceid][1].data[soffset+2];
if (sa == 255) {
render.data[dest+0] = sr;
render.data[dest+1] = sr;
render.data[dest+2] = sr;
return;
}
dr = render.data[dest+0];
dg = render.data[dest+1];
db = render.data[dest+2];
da = 1.0 - sa;
render.data[dest+0] = da * dr + sa * sr;
render.data[dest+1] = da * dg + sa * sg;
render.data[dest+2] = da * db + sa * sb;
}
function update() {
if (!left && !right && !up && !down && !redraw) return;
redraw = false;
if (left == 1) tilex -= 1;
if (right == 1) tilex += 1;
if (up == 1) tiley += 1;
if (down == 1) tiley -= 1;
screenx = Math.round((tilex + tiley)*sin60);
screeny = Math.round((tilex - tiley)*sin30);
z = screeny*1.5;
for (y = 0; y < 384; y++) {
for (x = 0; x < 136; x++) {
dest = (y*136+x)*4;
render.data[dest+0] = background.data[dest+0];
render.data[dest+1] = background.data[dest+1];
render.data[dest+2] = background.data[dest+2];
render.data[dest+3] = 255;
// Shift: read from the data so-many bytes ago. Subtract rather than add.
if (y-screeny >= 0 && y-screeny < 384 && x-screenx >= 0 && x-screenx < 136) {
source = ((y-screeny)*136 + x-screenx)*4;
if (images[1][2].data[source] != 255 && images[1][2].data[source] - z < images[0][2].data[dest]) {
// Object 2 on top
Blend(0, dest);
Blend(1, source);
} else {
// Object 1 on top
Blend(1, source);
Blend(0, dest);
}
} else {
// Object 1 only
Blend(0, dest);
}
}
}
context.putImageData(render, 0, 0);
debug.innerHTML = "Tile x: " + tilex/sqrt5120 + "<br />Tile y: " + tiley/sqrt5120 + "<br />Screen x: " + screenx + "<br />Screen y: " + screeny + "<br />z: " + z;
}
</script>
<div id="debug"></div>
<canvas width="136" height="384" id="draw" style="border: 1px solid #888"></canvas>