UNPKG

@2003scape/rsc-client

Version:
1,830 lines (1,559 loc) 138 kB
const Long = require('long'); const Polygon = require('./polygon'); const Scanline = require('./scanline'); const COLOUR_TRANSPARENT = 12345678; /*function polygonDepthSort(a, b) { if (a.depth === 0) { return 1; } if (a.depth === b.depth) { return 0; } return a.depth < b.depth ? 1 : -1; }*/ class Scene { constructor(surface, maxModelCount, polygonCount, spriteCount) { this.lastVisiblePolygonsCount = 0; this.anIntArray377 = null; this.textureCount = 0; this.textureColoursUsed = null; this.textureColourList = null; this.textureDimension = null; this.textureLoadedNumber = null; this.texturePixels = null; this.textureBackTransparent = null; this.textureColours64 = null; this.textureColours128 = null; this.scanlines = null; this.minY = 0; this.maxY = 0; this.interlace = false; this.mouseX = 0; this.mouseY = 0; this.mousePickedCount = 0; this.newStart = 0; this.newEnd = 0; this.cameraX = 0; this.cameraY = 0; this.cameraZ = 0; this.cameraYaw = 0; this.cameraPitch = 0; this.cameraRoll = 0; this.rampCount = 50; this.gradientBase = new Int32Array(this.rampCount); this.gradientRamps = []; for (let i = 0; i < this.rampCount; i += 1) { this.gradientRamps.push(new Int32Array(256)); } this.clipNear = 5; this.clipFar3d = 1000; this.clipFar2d = 1000; this.fogZFalloff = 20; this.fogZDistance = 10; this.wideBand = false; this.mousePickingActive = false; this.mousePickedMax = 100; this.mousePickedModels = []; this.mousePickedModels.length = this.mousePickedMax; this.mousePickedModels.fill(null); this.mousePickedFaces = new Int32Array(this.mousePickedMax); this.width = 512; this.clipX = 256; this.clipY = 192; this.baseX = 256; this.baseY = 256; this.viewDistance = 8; this.normalMagnitude = 4; this.planeX = new Int32Array(40); this.planeY = new Int32Array(40); this.vertexShade = new Int32Array(40); this.vertexX = new Int32Array(40); this.vertexY = new Int32Array(40); this.vertexZ = new Int32Array(40); this.interlace = false; this.surface = surface; this.clipX = (surface.width2 / 2) | 0; this.clipY = (surface.height2 / 2) | 0; this.raster = surface.pixels; this.modelCount = 0; this.maxModelCount = maxModelCount; this.models = []; this.models.length = this.maxModelCount; this.models.fill(null); this.visiblePolygonsCount = 0; this.visiblePolygons = []; for (let i = 0; i < polygonCount; i++) { this.visiblePolygons.push(new Polygon()); } this.spriteCount = 0; //this.view = new GameModel(k * 2, k); this.spriteId = new Int32Array(spriteCount); this.spriteWidth = new Int32Array(spriteCount); this.spriteHeight = new Int32Array(spriteCount); this.spriteX = new Int32Array(spriteCount); this.spriteZ = new Int32Array(spriteCount); this.spriteY = new Int32Array(spriteCount); this.spriteTranslateX = new Int32Array(spriteCount); /*if (this.aByteArray434 === null) { this.aByteArray434 = new Int8Array(17691); }*/ this.cameraX = 0; this.cameraY = 0; this.cameraZ = 0; this.cameraYaw = 0; this.cameraPitch = 0; this.cameraRoll = 0; for (let i = 0; i < 256; i++) { Scene.sin512Cache[i] = (Math.sin(i * 0.02454369) * 32768) | 0; Scene.sin512Cache[i + 256] = (Math.cos(i * 0.02454369) * 32768) | 0; } for (let i = 0; i < 1024; i++) { Scene.sinCosCache[i] = (Math.sin(i * 0.00613592315) * 32768) | 0; Scene.sinCosCache[i + 1024] = (Math.cos(i * 0.00613592315) * 32768) | 0; } } static textureScanline( ai, ai1, i, j, k, l, i1, j1, k1, l1, i2, j2, k2, l2 ) { if (i2 <= 0) { return; } let i3 = 0; let j3 = 0; let i4 = 0; if (i1 !== 0) { i = (k / i1) << 7; j = (l / i1) << 7; } if (i < 0) { i = 0; } else if (i > 16256) { i = 16256; } k += j1; l += k1; i1 += l1; if (i1 !== 0) { i3 = (k / i1) << 7; j3 = (l / i1) << 7; } if (i3 < 0) { i3 = 0; } else if (i3 > 16256) { i3 = 16256; } let k3 = (i3 - i) >> 4; let l3 = (j3 - j) >> 4; for (let j4 = i2 >> 4; j4 > 0; j4--) { i += k2 & 0x600000; i4 = k2 >> 23; k2 += l2; ai[j2++] = ai1[(j & 0x3f80) + (i >> 7)] >>> i4; i += k3; j += l3; ai[j2++] = ai1[(j & 0x3f80) + (i >> 7)] >>> i4; i += k3; j += l3; ai[j2++] = ai1[(j & 0x3f80) + (i >> 7)] >>> i4; i += k3; j += l3; ai[j2++] = ai1[(j & 0x3f80) + (i >> 7)] >>> i4; i += k3; j += l3; i = (i & 0x3fff) + (k2 & 0x600000); i4 = k2 >> 23; k2 += l2; ai[j2++] = ai1[(j & 0x3f80) + (i >> 7)] >>> i4; i += k3; j += l3; ai[j2++] = ai1[(j & 0x3f80) + (i >> 7)] >>> i4; i += k3; j += l3; ai[j2++] = ai1[(j & 0x3f80) + (i >> 7)] >>> i4; i += k3; j += l3; ai[j2++] = ai1[(j & 0x3f80) + (i >> 7)] >>> i4; i += k3; j += l3; i = (i & 0x3fff) + (k2 & 0x600000); i4 = k2 >> 23; k2 += l2; ai[j2++] = ai1[(j & 0x3f80) + (i >> 7)] >>> i4; i += k3; j += l3; ai[j2++] = ai1[(j & 0x3f80) + (i >> 7)] >>> i4; i += k3; j += l3; ai[j2++] = ai1[(j & 0x3f80) + (i >> 7)] >>> i4; i += k3; j += l3; ai[j2++] = ai1[(j & 0x3f80) + (i >> 7)] >>> i4; i += k3; j += l3; i = (i & 0x3fff) + (k2 & 0x600000); i4 = k2 >> 23; k2 += l2; ai[j2++] = ai1[(j & 0x3f80) + (i >> 7)] >>> i4; i += k3; j += l3; ai[j2++] = ai1[(j & 0x3f80) + (i >> 7)] >>> i4; i += k3; j += l3; ai[j2++] = ai1[(j & 0x3f80) + (i >> 7)] >>> i4; i += k3; j += l3; ai[j2++] = ai1[(j & 0x3f80) + (i >> 7)] >>> i4; i = i3; j = j3; k += j1; l += k1; i1 += l1; if (i1 !== 0) { i3 = (k / i1) << 7; j3 = (l / i1) << 7; } if (i3 < 0) { i3 = 0; } else if (i3 > 16256) { i3 = 16256; } k3 = (i3 - i) >> 4; l3 = (j3 - j) >> 4; } for (let k4 = 0; k4 < (i2 & 0xf); k4++) { if ((k4 & 3) === 0) { i = (i & 0x3fff) + (k2 & 0x600000); i4 = k2 >> 23; k2 += l2; } ai[j2++] = ai1[(j & 0x3f80) + (i >> 7)] >>> i4; i += k3; j += l3; } } static textureTranslucentScanline( ai, ai1, i, j, k, l, i1, j1, k1, l1, i2, j2, k2, l2 ) { if (i2 <= 0) { return; } let i3 = 0; let j3 = 0; let i4 = 0; if (i1 !== 0) { i = (k / i1) << 7; j = (l / i1) << 7; } if (i < 0) { i = 0; } else if (i > 16256) { i = 16256; } k += j1; l += k1; i1 += l1; if (i1 !== 0) { i3 = (k / i1) << 7; j3 = (l / i1) << 7; } if (i3 < 0) { i3 = 0; } else if (i3 > 16256) { i3 = 16256; } let k3 = (i3 - i) >> 4; let l3 = (j3 - j) >> 4; for (let j4 = i2 >> 4; j4 > 0; j4--) { i += k2 & 0x600000; i4 = k2 >> 23; k2 += l2; ai[j2++] = (ai1[(j & 0x3f80) + (i >> 7)] >>> i4) + ((ai[j2] >> 1) & 0x7f7f7f); i += k3; j += l3; ai[j2++] = (ai1[(j & 0x3f80) + (i >> 7)] >>> i4) + ((ai[j2] >> 1) & 0x7f7f7f); i += k3; j += l3; ai[j2++] = (ai1[(j & 0x3f80) + (i >> 7)] >>> i4) + ((ai[j2] >> 1) & 0x7f7f7f); i += k3; j += l3; ai[j2++] = (ai1[(j & 0x3f80) + (i >> 7)] >>> i4) + ((ai[j2] >> 1) & 0x7f7f7f); i += k3; j += l3; i = (i & 0x3fff) + (k2 & 0x600000); i4 = k2 >> 23; k2 += l2; ai[j2++] = (ai1[(j & 0x3f80) + (i >> 7)] >>> i4) + ((ai[j2] >> 1) & 0x7f7f7f); i += k3; j += l3; ai[j2++] = (ai1[(j & 0x3f80) + (i >> 7)] >>> i4) + ((ai[j2] >> 1) & 0x7f7f7f); i += k3; j += l3; ai[j2++] = (ai1[(j & 0x3f80) + (i >> 7)] >>> i4) + ((ai[j2] >> 1) & 0x7f7f7f); i += k3; j += l3; ai[j2++] = (ai1[(j & 0x3f80) + (i >> 7)] >>> i4) + ((ai[j2] >> 1) & 0x7f7f7f); i += k3; j += l3; i = (i & 0x3fff) + (k2 & 0x600000); i4 = k2 >> 23; k2 += l2; ai[j2++] = (ai1[(j & 0x3f80) + (i >> 7)] >>> i4) + ((ai[j2] >> 1) & 0x7f7f7f); i += k3; j += l3; ai[j2++] = (ai1[(j & 0x3f80) + (i >> 7)] >>> i4) + ((ai[j2] >> 1) & 0x7f7f7f); i += k3; j += l3; ai[j2++] = (ai1[(j & 0x3f80) + (i >> 7)] >>> i4) + ((ai[j2] >> 1) & 0x7f7f7f); i += k3; j += l3; ai[j2++] = (ai1[(j & 0x3f80) + (i >> 7)] >>> i4) + ((ai[j2] >> 1) & 0x7f7f7f); i += k3; j += l3; i = (i & 0x3fff) + (k2 & 0x600000); i4 = k2 >> 23; k2 += l2; ai[j2++] = (ai1[(j & 0x3f80) + (i >> 7)] >>> i4) + ((ai[j2] >> 1) & 0x7f7f7f); i += k3; j += l3; ai[j2++] = (ai1[(j & 0x3f80) + (i >> 7)] >>> i4) + ((ai[j2] >> 1) & 0x7f7f7f); i += k3; j += l3; ai[j2++] = (ai1[(j & 0x3f80) + (i >> 7)] >>> i4) + ((ai[j2] >> 1) & 0x7f7f7f); i += k3; j += l3; ai[j2++] = (ai1[(j & 0x3f80) + (i >> 7)] >>> i4) + ((ai[j2] >> 1) & 0x7f7f7f); i = i3; j = j3; k += j1; l += k1; i1 += l1; if (i1 !== 0) { i3 = (k / i1) << 7; j3 = (l / i1) << 7; } if (i3 < 0) { i3 = 0; } else if (i3 > 16256) { i3 = 16256; } k3 = (i3 - i) >> 4; l3 = (j3 - j) >> 4; } for (let k4 = 0; k4 < (i2 & 0xf); k4++) { if ((k4 & 3) === 0) { i = (i & 0x3fff) + (k2 & 0x600000); i4 = k2 >> 23; k2 += l2; } ai[j2++] = (ai1[(j & 0x3f80) + (i >> 7)] >>> i4) + ((ai[j2] >> 1) & 0x7f7f7f); i += k3; j += l3; } } static textureBackTranslucentScanline( ai, i, j, k, ai1, l, i1, j1, k1, l1, i2, j2, k2, l2, i3 ) { if (j2 <= 0) { return; } let j3 = 0; let k3 = 0; i3 <<= 2; if (j1 !== 0) { j3 = (l / j1) << 7; k3 = (i1 / j1) << 7; } if (j3 < 0) { j3 = 0; } else if (j3 > 16256) { j3 = 16256; } for (let j4 = j2; j4 > 0; j4 -= 16) { l += k1; i1 += l1; j1 += i2; j = j3; k = k3; if (j1 !== 0) { j3 = (l / j1) << 7; k3 = (i1 / j1) << 7; } if (j3 < 0) { j3 = 0; } else if (j3 > 16256) { j3 = 16256; } let l3 = (j3 - j) >> 4; let i4 = (k3 - k) >> 4; let k4 = l2 >> 23; j += l2 & 0x600000; l2 += i3; if (j4 < 16) { for (let l4 = 0; l4 < j4; l4++) { if ((i = ai1[(k & 0x3f80) + (j >> 7)] >>> k4) !== 0) { ai[k2] = i; } k2++; j += l3; k += i4; if ((l4 & 3) === 3) { j = (j & 0x3fff) + (l2 & 0x600000); k4 = l2 >> 23; l2 += i3; } } } else { if ((i = ai1[(k & 0x3f80) + (j >> 7)] >>> k4) !== 0) { ai[k2] = i; } k2++; j += l3; k += i4; if ((i = ai1[(k & 0x3f80) + (j >> 7)] >>> k4) !== 0) { ai[k2] = i; } k2++; j += l3; k += i4; if ((i = ai1[(k & 0x3f80) + (j >> 7)] >>> k4) !== 0) { ai[k2] = i; } k2++; j += l3; k += i4; if ((i = ai1[(k & 0x3f80) + (j >> 7)] >>> k4) !== 0) { ai[k2] = i; } k2++; j += l3; k += i4; j = (j & 0x3fff) + (l2 & 0x600000); k4 = l2 >> 23; l2 += i3; if ((i = ai1[(k & 0x3f80) + (j >> 7)] >>> k4) !== 0) { ai[k2] = i; } k2++; j += l3; k += i4; if ((i = ai1[(k & 0x3f80) + (j >> 7)] >>> k4) !== 0) { ai[k2] = i; } k2++; j += l3; k += i4; if ((i = ai1[(k & 0x3f80) + (j >> 7)] >>> k4) !== 0) { ai[k2] = i; } k2++; j += l3; k += i4; if ((i = ai1[(k & 0x3f80) + (j >> 7)] >>> k4) !== 0) { ai[k2] = i; } k2++; j += l3; k += i4; j = (j & 0x3fff) + (l2 & 0x600000); k4 = l2 >> 23; l2 += i3; if ((i = ai1[(k & 0x3f80) + (j >> 7)] >>> k4) !== 0) { ai[k2] = i; } k2++; j += l3; k += i4; if ((i = ai1[(k & 0x3f80) + (j >> 7)] >>> k4) !== 0) { ai[k2] = i; } k2++; j += l3; k += i4; if ((i = ai1[(k & 0x3f80) + (j >> 7)] >>> k4) !== 0) { ai[k2] = i; } k2++; j += l3; k += i4; if ((i = ai1[(k & 0x3f80) + (j >> 7)] >>> k4) !== 0) { ai[k2] = i; } k2++; j += l3; k += i4; j = (j & 0x3fff) + (l2 & 0x600000); k4 = l2 >> 23; l2 += i3; if ((i = ai1[(k & 0x3f80) + (j >> 7)] >>> k4) !== 0) { ai[k2] = i; } k2++; j += l3; k += i4; if ((i = ai1[(k & 0x3f80) + (j >> 7)] >>> k4) !== 0) { ai[k2] = i; } k2++; j += l3; k += i4; if ((i = ai1[(k & 0x3f80) + (j >> 7)] >>> k4) !== 0) { ai[k2] = i; } k2++; j += l3; k += i4; if ((i = ai1[(k & 0x3f80) + (j >> 7)] >>> k4) !== 0) { ai[k2] = i; } k2++; } } } static textureScanline2( ai, ai1, i, j, k, l, i1, j1, k1, l1, i2, j2, k2, l2 ) { if (i2 <= 0) { return; } let i3 = 0; let j3 = 0; l2 <<= 2; if (i1 !== 0) { i3 = (k / i1) << 6; j3 = (l / i1) << 6; } if (i3 < 0) { i3 = 0; } else if (i3 > 4032) { i3 = 4032; } for (let i4 = i2; i4 > 0; i4 -= 16) { k += j1; l += k1; i1 += l1; i = i3; j = j3; if (i1 !== 0) { i3 = (k / i1) << 6; j3 = (l / i1) << 6; } if (i3 < 0) { i3 = 0; } else if (i3 > 4032) { i3 = 4032; } let k3 = (i3 - i) >> 4; let l3 = (j3 - j) >> 4; let j4 = k2 >> 20; i += k2 & 0xc0000; k2 += l2; if (i4 < 16) { for (let k4 = 0; k4 < i4; k4++) { ai[j2++] = ai1[(j & 0xfc0) + (i >> 6)] >>> j4; i += k3; j += l3; if ((k4 & 3) === 3) { i = (i & 0xfff) + (k2 & 0xc0000); j4 = k2 >> 20; k2 += l2; } } } else { ai[j2++] = ai1[(j & 0xfc0) + (i >> 6)] >>> j4; i += k3; j += l3; ai[j2++] = ai1[(j & 0xfc0) + (i >> 6)] >>> j4; i += k3; j += l3; ai[j2++] = ai1[(j & 0xfc0) + (i >> 6)] >>> j4; i += k3; j += l3; ai[j2++] = ai1[(j & 0xfc0) + (i >> 6)] >>> j4; i += k3; j += l3; i = (i & 0xfff) + (k2 & 0xc0000); j4 = k2 >> 20; k2 += l2; ai[j2++] = ai1[(j & 0xfc0) + (i >> 6)] >>> j4; i += k3; j += l3; ai[j2++] = ai1[(j & 0xfc0) + (i >> 6)] >>> j4; i += k3; j += l3; ai[j2++] = ai1[(j & 0xfc0) + (i >> 6)] >>> j4; i += k3; j += l3; ai[j2++] = ai1[(j & 0xfc0) + (i >> 6)] >>> j4; i += k3; j += l3; i = (i & 0xfff) + (k2 & 0xc0000); j4 = k2 >> 20; k2 += l2; ai[j2++] = ai1[(j & 0xfc0) + (i >> 6)] >>> j4; i += k3; j += l3; ai[j2++] = ai1[(j & 0xfc0) + (i >> 6)] >>> j4; i += k3; j += l3; ai[j2++] = ai1[(j & 0xfc0) + (i >> 6)] >>> j4; i += k3; j += l3; ai[j2++] = ai1[(j & 0xfc0) + (i >> 6)] >>> j4; i += k3; j += l3; i = (i & 0xfff) + (k2 & 0xc0000); j4 = k2 >> 20; k2 += l2; ai[j2++] = ai1[(j & 0xfc0) + (i >> 6)] >>> j4; i += k3; j += l3; ai[j2++] = ai1[(j & 0xfc0) + (i >> 6)] >>> j4; i += k3; j += l3; ai[j2++] = ai1[(j & 0xfc0) + (i >> 6)] >>> j4; i += k3; j += l3; ai[j2++] = ai1[(j & 0xfc0) + (i >> 6)] >>> j4; } } } static textureTranslucentScanline2( ai, ai1, i, j, k, l, i1, j1, k1, l1, i2, j2, k2, l2 ) { if (i2 <= 0) { return; } let i3 = 0; let j3 = 0; l2 <<= 2; if (i1 !== 0) { i3 = (k / i1) << 6; j3 = (l / i1) << 6; } if (i3 < 0) { i3 = 0; } else if (i3 > 4032) { i3 = 4032; } for (let i4 = i2; i4 > 0; i4 -= 16) { k += j1; l += k1; i1 += l1; i = i3; j = j3; if (i1 !== 0) { i3 = (k / i1) << 6; j3 = (l / i1) << 6; } if (i3 < 0) { i3 = 0; } else if (i3 > 4032) { i3 = 4032; } let k3 = (i3 - i) >> 4; let l3 = (j3 - j) >> 4; let j4 = k2 >> 20; i += k2 & 0xc0000; k2 += l2; if (i4 < 16) { for (let k4 = 0; k4 < i4; k4++) { ai[j2++] = (ai1[(j & 0xfc0) + (i >> 6)] >>> j4) + ((ai[j2] >> 1) & 0x7f7f7f); i += k3; j += l3; if ((k4 & 3) === 3) { i = (i & 0xfff) + (k2 & 0xc0000); j4 = k2 >> 20; k2 += l2; } } } else { ai[j2++] = (ai1[(j & 0xfc0) + (i >> 6)] >>> j4) + ((ai[j2] >> 1) & 0x7f7f7f); i += k3; j += l3; ai[j2++] = (ai1[(j & 0xfc0) + (i >> 6)] >>> j4) + ((ai[j2] >> 1) & 0x7f7f7f); i += k3; j += l3; ai[j2++] = (ai1[(j & 0xfc0) + (i >> 6)] >>> j4) + ((ai[j2] >> 1) & 0x7f7f7f); i += k3; j += l3; ai[j2++] = (ai1[(j & 0xfc0) + (i >> 6)] >>> j4) + ((ai[j2] >> 1) & 0x7f7f7f); i += k3; j += l3; i = (i & 0xfff) + (k2 & 0xc0000); j4 = k2 >> 20; k2 += l2; ai[j2++] = (ai1[(j & 0xfc0) + (i >> 6)] >>> j4) + ((ai[j2] >> 1) & 0x7f7f7f); i += k3; j += l3; ai[j2++] = (ai1[(j & 0xfc0) + (i >> 6)] >>> j4) + ((ai[j2] >> 1) & 0x7f7f7f); i += k3; j += l3; ai[j2++] = (ai1[(j & 0xfc0) + (i >> 6)] >>> j4) + ((ai[j2] >> 1) & 0x7f7f7f); i += k3; j += l3; ai[j2++] = (ai1[(j & 0xfc0) + (i >> 6)] >>> j4) + ((ai[j2] >> 1) & 0x7f7f7f); i += k3; j += l3; i = (i & 0xfff) + (k2 & 0xc0000); j4 = k2 >> 20; k2 += l2; ai[j2++] = (ai1[(j & 0xfc0) + (i >> 6)] >>> j4) + ((ai[j2] >> 1) & 0x7f7f7f); i += k3; j += l3; ai[j2++] = (ai1[(j & 0xfc0) + (i >> 6)] >>> j4) + ((ai[j2] >> 1) & 0x7f7f7f); i += k3; j += l3; ai[j2++] = (ai1[(j & 0xfc0) + (i >> 6)] >>> j4) + ((ai[j2] >> 1) & 0x7f7f7f); i += k3; j += l3; ai[j2++] = (ai1[(j & 0xfc0) + (i >> 6)] >>> j4) + ((ai[j2] >> 1) & 0x7f7f7f); i += k3; j += l3; i = (i & 0xfff) + (k2 & 0xc0000); j4 = k2 >> 20; k2 += l2; ai[j2++] = (ai1[(j & 0xfc0) + (i >> 6)] >>> j4) + ((ai[j2] >> 1) & 0x7f7f7f); i += k3; j += l3; ai[j2++] = (ai1[(j & 0xfc0) + (i >> 6)] >>> j4) + ((ai[j2] >> 1) & 0x7f7f7f); i += k3; j += l3; ai[j2++] = (ai1[(j & 0xfc0) + (i >> 6)] >>> j4) + ((ai[j2] >> 1) & 0x7f7f7f); i += k3; j += l3; ai[j2++] = (ai1[(j & 0xfc0) + (i >> 6)] >>> j4) + ((ai[j2] >> 1) & 0x7f7f7f); } } } static textureBackTranslucentScanline2( ai, i, j, k, ai1, l, i1, j1, k1, l1, i2, j2, k2, l2, i3 ) { if (j2 <= 0) { return; } let j3 = 0; let k3 = 0; i3 <<= 2; if (j1 !== 0) { j3 = (l / j1) << 6; k3 = (i1 / j1) << 6; } if (j3 < 0) { j3 = 0; } else if (j3 > 4032) { j3 = 4032; } for (let j4 = j2; j4 > 0; j4 -= 16) { l += k1; i1 += l1; j1 += i2; j = j3; k = k3; if (j1 !== 0) { j3 = (l / j1) << 6; k3 = (i1 / j1) << 6; } if (j3 < 0) { j3 = 0; } else if (j3 > 4032) { j3 = 4032; } let l3 = (j3 - j) >> 4; let i4 = (k3 - k) >> 4; let k4 = l2 >> 20; j += l2 & 0xc0000; l2 += i3; if (j4 < 16) { for (let l4 = 0; l4 < j4; l4++) { if ((i = ai1[(k & 0xfc0) + (j >> 6)] >>> k4) !== 0) { ai[k2] = i; } k2++; j += l3; k += i4; if ((l4 & 3) === 3) { j = (j & 0xfff) + (l2 & 0xc0000); k4 = l2 >> 20; l2 += i3; } } } else { if ((i = ai1[(k & 0xfc0) + (j >> 6)] >>> k4) !== 0) { ai[k2] = i; } k2++; j += l3; k += i4; if ((i = ai1[(k & 0xfc0) + (j >> 6)] >>> k4) !== 0) { ai[k2] = i; } k2++; j += l3; k += i4; if ((i = ai1[(k & 0xfc0) + (j >> 6)] >>> k4) !== 0) { ai[k2] = i; } k2++; j += l3; k += i4; if ((i = ai1[(k & 0xfc0) + (j >> 6)] >>> k4) !== 0) { ai[k2] = i; } k2++; j += l3; k += i4; j = (j & 0xfff) + (l2 & 0xc0000); k4 = l2 >> 20; l2 += i3; if ((i = ai1[(k & 0xfc0) + (j >> 6)] >>> k4) !== 0) { ai[k2] = i; } k2++; j += l3; k += i4; if ((i = ai1[(k & 0xfc0) + (j >> 6)] >>> k4) !== 0) { ai[k2] = i; } k2++; j += l3; k += i4; if ((i = ai1[(k & 0xfc0) + (j >> 6)] >>> k4) !== 0) { ai[k2] = i; } k2++; j += l3; k += i4; if ((i = ai1[(k & 0xfc0) + (j >> 6)] >>> k4) !== 0) { ai[k2] = i; } k2++; j += l3; k += i4; j = (j & 0xfff) + (l2 & 0xc0000); k4 = l2 >> 20; l2 += i3; if ((i = ai1[(k & 0xfc0) + (j >> 6)] >>> k4) !== 0) { ai[k2] = i; } k2++; j += l3; k += i4; if ((i = ai1[(k & 0xfc0) + (j >> 6)] >>> k4) !== 0) { ai[k2] = i; } k2++; j += l3; k += i4; if ((i = ai1[(k & 0xfc0) + (j >> 6)] >>> k4) !== 0) { ai[k2] = i; } k2++; j += l3; k += i4; if ((i = ai1[(k & 0xfc0) + (j >> 6)] >>> k4) !== 0) { ai[k2] = i; } k2++; j += l3; k += i4; j = (j & 0xfff) + (l2 & 0xc0000); k4 = l2 >> 20; l2 += i3; if ((i = ai1[(k & 0xfc0) + (j >> 6)] >>> k4) !== 0) { ai[k2] = i; } k2++; j += l3; k += i4; if ((i = ai1[(k & 0xfc0) + (j >> 6)] >>> k4) !== 0) { ai[k2] = i; } k2++; j += l3; k += i4; if ((i = ai1[(k & 0xfc0) + (j >> 6)] >>> k4) !== 0) { ai[k2] = i; } k2++; j += l3; k += i4; if ((i = ai1[(k & 0xfc0) + (j >> 6)] >>> k4) !== 0) { ai[k2] = i; } k2++; } } } static gradientScanline(ai, i, j, k, ai1, l, i1) { if (i >= 0) { return; } i1 <<= 1; k = ai1[(l >> 8) & 0xff]; l += i1; let j1 = (i / 8) | 0; for (let k1 = j1; k1 < 0; k1++) { ai[j++] = k; ai[j++] = k; k = ai1[(l >> 8) & 0xff]; l += i1; ai[j++] = k; ai[j++] = k; k = ai1[(l >> 8) & 0xff]; l += i1; ai[j++] = k; ai[j++] = k; k = ai1[(l >> 8) & 0xff]; l += i1; ai[j++] = k; ai[j++] = k; k = ai1[(l >> 8) & 0xff]; l += i1; } j1 = -(i % 8); for (let l1 = 0; l1 < j1; l1++) { ai[j++] = k; if ((l1 & 1) === 1) { k = ai1[(l >> 8) & 0xff]; l += i1; } } } static textureGradientScanline(ai, i, j, k, ai1, l, i1) { if (i >= 0) { return; } i1 <<= 2; k = ai1[(l >> 8) & 0xff]; l += i1; let j1 = (i / 16) | 0; for (let k1 = j1; k1 < 0; k1++) { ai[j++] = k + ((ai[j] >> 1) & 0x7f7f7f); ai[j++] = k + ((ai[j] >> 1) & 0x7f7f7f); ai[j++] = k + ((ai[j] >> 1) & 0x7f7f7f); ai[j++] = k + ((ai[j] >> 1) & 0x7f7f7f); k = ai1[(l >> 8) & 0xff]; l += i1; ai[j++] = k + ((ai[j] >> 1) & 0x7f7f7f); ai[j++] = k + ((ai[j] >> 1) & 0x7f7f7f); ai[j++] = k + ((ai[j] >> 1) & 0x7f7f7f); ai[j++] = k + ((ai[j] >> 1) & 0x7f7f7f); k = ai1[(l >> 8) & 0xff]; l += i1; ai[j++] = k + ((ai[j] >> 1) & 0x7f7f7f); ai[j++] = k + ((ai[j] >> 1) & 0x7f7f7f); ai[j++] = k + ((ai[j] >> 1) & 0x7f7f7f); ai[j++] = k + ((ai[j] >> 1) & 0x7f7f7f); k = ai1[(l >> 8) & 0xff]; l += i1; ai[j++] = k + ((ai[j] >> 1) & 0x7f7f7f); ai[j++] = k + ((ai[j] >> 1) & 0x7f7f7f); ai[j++] = k + ((ai[j] >> 1) & 0x7f7f7f); ai[j++] = k + ((ai[j] >> 1) & 0x7f7f7f); k = ai1[(l >> 8) & 0xff]; l += i1; } j1 = -(i % 16); for (let l1 = 0; l1 < j1; l1++) { ai[j++] = k + ((ai[j] >> 1) & 0x7f7f7f); if ((l1 & 3) === 3) { k = ai1[(l >> 8) & 0xff]; l += i1; l += i1; } } } static gradientScanline2(ai, i, j, k, ai1, l, i1) { if (i >= 0) { return; } i1 <<= 2; k = ai1[(l >> 8) & 0xff]; l += i1; let j1 = (i / 16) | 0; for (let k1 = j1; k1 < 0; k1++) { ai[j++] = k; ai[j++] = k; ai[j++] = k; ai[j++] = k; k = ai1[(l >> 8) & 0xff]; l += i1; ai[j++] = k; ai[j++] = k; ai[j++] = k; ai[j++] = k; k = ai1[(l >> 8) & 0xff]; l += i1; ai[j++] = k; ai[j++] = k; ai[j++] = k; ai[j++] = k; k = ai1[(l >> 8) & 0xff]; l += i1; ai[j++] = k; ai[j++] = k; ai[j++] = k; ai[j++] = k; k = ai1[(l >> 8) & 0xff]; l += i1; } j1 = -(i % 16); for (let l1 = 0; l1 < j1; l1++) { ai[j++] = k; if ((l1 & 3) === 3) { k = ai1[(l >> 8) & 0xff]; l += i1; } } } static rgb(i, j, k) { return -1 - ((i / 8) | 0) * 1024 - ((j / 8) | 0) * 32 - ((k / 8) | 0); } addModel(model) { if (model === null) { console.log('Warning tried to add null object!'); } if (this.modelCount < this.maxModelCount) { this.models[this.modelCount++] = model; } } removeModel(gameModel) { for (let i = 0; i < this.modelCount; i++) { if (this.models[i] === gameModel) { this.modelCount--; for (let j = i; j < this.modelCount; j++) { this.models[j] = this.models[j + 1]; } } } } dispose() { this.clear(); for (let i = 0; i < this.modelCount; i++) { this.models[i] = null; } this.modelCount = 0; } clear() { this.spriteCount = 0; this.view.clear(); } reduceSprites(i) { this.spriteCount -= i; this.view.reduce(i, i * 2); if (this.spriteCount < 0) { this.spriteCount = 0; } } addSprite(n, x, z, y, w, h, tag) { this.spriteId[this.spriteCount] = n; this.spriteX[this.spriteCount] = x; this.spriteZ[this.spriteCount] = z; this.spriteY[this.spriteCount] = y; this.spriteWidth[this.spriteCount] = w; this.spriteHeight[this.spriteCount] = h; this.spriteTranslateX[this.spriteCount] = 0; const bottomVert = this.view.createVertex(x, z, y); const topVert = this.view.createVertex(x, z - h, y); const vertexes = new Int32Array([bottomVert, topVert]); this.view.createFace(2, vertexes, 0, 0); this.view.faceTag[this.spriteCount] = tag; this.view.isLocalPlayer[this.spriteCount++] = 0; return this.spriteCount - 1; } setLocalPlayer(i) { this.view.isLocalPlayer[i] = 1; } setSpriteTranslateX(i, n) { this.spriteTranslateX[i] = n; } setMouseLoc(x, y) { this.mouseX = x - this.baseX; this.mouseY = y; this.mousePickedCount = 0; this.mousePickingActive = true; } // TODO remove these getters getMousePickedCount() { return this.mousePickedCount; } getMousePickedFaces() { return this.mousePickedFaces; } getMousePickedModels() { return this.mousePickedModels; } setBounds(baseX, baseY, clipX, clipY, width, viewDistance) { this.clipX = clipX; this.clipY = clipY; this.baseX = baseX; this.baseY = baseY; this.width = width; this.viewDistance = viewDistance; this.scanlines = []; for (let k1 = 0; k1 < clipY + baseY; k1++) { this.scanlines.push(new Scanline()); } } polygonsQSort(polygons, low, high) { if (low < high) { let min = low - 1; let max = high + 1; let mid = ((low + high) / 2) | 0; let polygon = polygons[mid]; polygons[mid] = polygons[low]; polygons[low] = polygon; let j1 = polygon.depth; while (min < max) { do { max--; } while (polygons[max].depth < j1); do { min++; } while (polygons[min].depth > j1); if (min < max) { let polygon_1 = polygons[min]; polygons[min] = polygons[max]; polygons[max] = polygon_1; } } this.polygonsQSort(polygons, low, max); this.polygonsQSort(polygons, max + 1, high); } } polygonsIntersectSort(step, polygons, count) { for (let i = 0; i <= count; i++) { polygons[i].skipSomething = false; polygons[i].index = i; polygons[i].index2 = -1; } let l = 0; do { while (polygons[l].skipSomething) { l++; } if (l === count) { return; } let polygon = polygons[l]; polygon.skipSomething = true; let i1 = l; let j1 = l + step; if (j1 >= count) { j1 = count - 1; } for (let k1 = j1; k1 >= i1 + 1; k1--) { let other = polygons[k1]; if ( polygon.minPlaneX < other.maxPlaneX && other.minPlaneX < polygon.maxPlaneX && polygon.minPlaneY < other.maxPlaneY && other.minPlaneY < polygon.maxPlaneY && polygon.index !== other.index2 && !this.separatePolygon(polygon, other) && this.heuristicPolygon(other, polygon) ) { this.polygonsOrder(polygons, i1, k1); if (polygons[k1] !== other) { k1++; } i1 = this.newStart; other.index2 = polygon.index; } } } while (true); } polygonsOrder(polygons, start, end) { do { let polygon = polygons[start]; for (let k = start + 1; k <= end; k++) { let polygon_1 = polygons[k]; if (!this.separatePolygon(polygon_1, polygon)) { break; } polygons[start] = polygon_1; polygons[k] = polygon; start = k; if (start === end) { this.newStart = start; this.newEnd = start - 1; return true; } } let polygon_2 = polygons[end]; for (let l = end - 1; l >= start; l--) { let polygon_3 = polygons[l]; if (!this.separatePolygon(polygon_2, polygon_3)) { break; } polygons[end] = polygon_3; polygons[l] = polygon_2; end = l; if (start === end) { this.newStart = end + 1; this.newEnd = end; return true; } } if (start + 1 >= end) { this.newStart = start; this.newEnd = end; return false; } if (!this.polygonsOrder(polygons, start + 1, end)) { this.newStart = start; return false; } end = this.newEnd; } while (true); } setFrustum(i, j, k) { let l = (-this.cameraYaw + 1024) & 0x3ff; let i1 = (-this.cameraPitch + 1024) & 0x3ff; let j1 = (-this.cameraRoll + 1024) & 0x3ff; if (j1 !== 0) { let k1 = Scene.sinCosCache[j1]; let j2 = Scene.sinCosCache[j1 + 1024]; let i3 = (j * k1 + i * j2) >> 15; j = (j * j2 - i * k1) >> 15; i = i3; } if (l !== 0) { let l1 = Scene.sinCosCache[l]; let k2 = Scene.sinCosCache[l + 1024]; let j3 = (j * k2 - k * l1) >> 15; k = (j * l1 + k * k2) >> 15; j = j3; } if (i1 !== 0) { let i2 = Scene.sinCosCache[i1]; let l2 = Scene.sinCosCache[i1 + 1024]; let k3 = (k * i2 + i * l2) >> 15; k = (k * l2 - i * i2) >> 15; i = k3; } if (i < Scene.frustumMaxX) { Scene.frustumMaxX = i; } if (i > Scene.frustumMinX) { Scene.frustumMinX = i; } if (j < Scene.frustumMaxY) { Scene.frustumMaxY = j; } if (j > Scene.frustumMinY) { Scene.frustumMinY = j; } if (k < Scene.frustumFarZ) { Scene.frustumFarZ = k; } if (k > Scene.frustumNearZ) { Scene.frustumNearZ = k; } } render() { this.interlace = this.surface.interlace; let i3 = (this.clipX * this.clipFar3d) >> this.viewDistance; let j3 = (this.clipY * this.clipFar3d) >> this.viewDistance; Scene.frustumMaxX = 0; Scene.frustumMinX = 0; Scene.frustumMaxY = 0; Scene.frustumMinY = 0; Scene.frustumFarZ = 0; Scene.frustumNearZ = 0; this.setFrustum(-i3, -j3, this.clipFar3d); this.setFrustum(-i3, j3, this.clipFar3d); this.setFrustum(i3, -j3, this.clipFar3d); this.setFrustum(i3, j3, this.clipFar3d); this.setFrustum(-this.clipX, -this.clipY, 0); this.setFrustum(-this.clipX, this.clipY, 0); this.setFrustum(this.clipX, -this.clipY, 0); this.setFrustum(this.clipX, this.clipY, 0); Scene.frustumMaxX += this.cameraX; Scene.frustumMinX += this.cameraX; Scene.frustumMaxY += this.cameraY; Scene.frustumMinY += this.cameraY; Scene.frustumFarZ += this.cameraZ; Scene.frustumNearZ += this.cameraZ; this.models[this.modelCount] = this.view; this.view.transformState = 2; for (let i = 0; i < this.modelCount; i++) { this.models[i].project( this.cameraX, this.cameraY, this.cameraZ, this.cameraYaw, this.cameraPitch, this.cameraRoll, this.viewDistance, this.clipNear ); } this.models[this.modelCount].project( this.cameraX, this.cameraY, this.cameraZ, this.cameraYaw, this.cameraPitch, this.cameraRoll, this.viewDistance, this.clipNear ); this.visiblePolygonsCount = 0; for (let count = 0; count < this.modelCount; count++) { let gameModel = this.models[count]; if (gameModel.visible) { for (let face = 0; face < gameModel.numFaces; face++) { let num_vertices = gameModel.faceNumVertices[face]; let vertices = gameModel.faceVertices[face]; let visible = false; for (let vertex = 0; vertex < num_vertices; vertex++) { let z = gameModel.projectVertexZ[vertices[vertex]]; if (z <= this.clipNear || z >= this.clipFar3d) { continue; } visible = true; break; } if (visible) { let viewXCount = 0; for (let vertex = 0; vertex < num_vertices; vertex++) { let x = gameModel.vertexViewX[vertices[vertex]]; if (x > -this.clipX) { viewXCount |= 1; } if (x < this.clipX) { viewXCount |= 2; } if (viewXCount === 3) { break; } } if (viewXCount === 3) { let viewYCount = 0; for ( let vertex = 0; vertex < num_vertices; vertex++ ) { let k1 = gameModel.vertexViewY[vertices[vertex]]; if (k1 > -this.clipY) { viewYCount |= 1; } if (k1 < this.clipY) { viewYCount |= 2; } if (viewYCount === 3) { break; } } if (viewYCount === 3) { let polygon_1 = this.visiblePolygons[ this.visiblePolygonsCount ]; polygon_1.model = gameModel; polygon_1.face = face; this.initialisePolygon3D( this.visiblePolygonsCount ); let faceFill = 0; if (polygon_1.visibility < 0) { faceFill = gameModel.faceFillFront[face]; } else { faceFill = gameModel.faceFillBack[face]; } if (faceFill !== COLOUR_TRANSPARENT) { let h = 0; for ( let vertex = 0; vertex < num_vertices; vertex++ ) { h += gameModel.projectVertexZ[ vertices[vertex] ]; } polygon_1.depth = ((h / num_vertices) | 0) + gameModel.depth; polygon_1.facefill = faceFill; this.visiblePolygonsCount++; } } } } } } } let model_2d = this.view; if (model_2d.visible) { for (let face = 0; face < model_2d.numFaces; face++) { let faceVertices = model_2d.faceVertices[face]; let vertex0 = faceVertices[0]; let vx = model_2d.vertexViewX[vertex0]; let vy = model_2d.vertexViewY[vertex0]; let vz = model_2d.projectVertexZ[vertex0]; if (vz > this.clipNear && vz < this.clipFar2d) { let vw = ((this.spriteWidth[face] << this.viewDistance) / vz) | 0; let vh = ((this.spriteHeight[face] << this.viewDistance) / vz) | 0; if ( vx - ((vw / 2) | 0) <= this.clipX && vx + ((vw / 2) | 0) >= -this.clipX && vy - vh <= this.clipY && vy >= -this.clipY ) {