[97编程世界冠军4K组]代码转化为js脚本后代码

由于 ts脚本需要编译,有些不怎么使用ts,比较麻烦,转为js后可以直接通过html导入,本地只需要1个文件:index.html,对于学习可能有些用。

不过为了减少学习的成本,实际删除了很多代码,当前代码量大概762行(除去空行)。

代码量少的话,本地浏览器打开,打断点或者加打印日志会比较方便(不过代码还是挺难,并且算法的代码好像被压缩过,变量命名没有可读性)。

index.html

<!DOCTYPE html>
<html lang="en">
    <body>
        <script src="https://cdn.tmooc.cn//tnote-web//bsfile/ckimg/2023/11/9//3866954413554b14bc837949ac48c74a.js"></script>
        <canvas id="main-canvas" width="320" height="240"></canvas>
        <script>
            class Generate
            {
                static randomA = 0x8405;
                static randomB = 0x10FB;

                static LightMap()
                {
                    const lightMap = new Uint8Array(0x80 * 0x100);
                    let p = 0;
                    for (let i = 0x00; i < 0x80; ++i)
                    {
                        for (let j = 0x00; j < 0xC0; ++j) lightMap[p++] = (j & 0xE0) + ((j & 0x1F) * i * 2 >> 8);
                        for (let j = 0xC0; j < 0x100; ++j) lightMap[p++] = j;
                    }
                    return lightMap;
                }

                static Palette()
                {
                    this.PALETTE_TABLE = [0x10, 0x1F, 0x3F, 0x3F, 0x3F, 0x01, 0x00, 0x00, 0x00, 0x1F, 0x28, 0x20, 0x3F, 0x01, 0x00, 0x00, 0x00, 0x1F, 0x3F, 0x00, 0x00, 0x01, 0x06, 0x01, 0x00, 0x1F, 0x3F, 0x29, 0x14, 0x01, 0x00, 0x00, 0x00, 0x1F, 0x3F, 0x3F, 0x08, 0x01, 0x00, 0x00, 0x00, 0x1F, 0x38, 0x38, 0x3F, 0x01, 0x3F, 0x00, 0x00, 0x10, 0x3F, 0x3F, 0x00, 0x10, 0x3F, 0x00, 0x00, 0x01, 0x16, 0x05, 0x00, 0x07, 0x3F, 0x38, 0x11]

                    const palette = new Uint8Array(3 * 0x100);
                    let a = 0x0000,
                        b = 0x0001;
                    for (let i = 0; i < 3; ++i)
                    {
                        let p = 0,
                            q = 0;
                        a = this.PALETTE_TABLE[p];
                        b &= 0x00FF;
                        let entryCount = this.PALETTE_TABLE[p++];
                        for (let j = 0; j < entryCount; ++j)
                        {
                            a = a & 0x00FF | this.PALETTE_TABLE[p + i + 1] << 8;
                            a = (a - b) / this.PALETTE_TABLE[p] | 0;

                            for (let k = 0; k < this.PALETTE_TABLE[p]; ++k, ++q)
                            {
                                b += a;
                                palette[q * 3 + i] = b >> 8;
                            }
                            p += 4;
                        }
                    }
                    for (let i = 0; i < 3 * 0x100; ++i) palette[i] = palette[i] << 2 | palette[i] >> 4;
                    return palette;
                }

                static random(x)
                {
                    Generate.randomB = Generate.randomB * Generate.randomA + 1 | 0; //注意这个randomB是不断变化的
                    return (Generate.randomB >> 16 & 0xFFFF) * x >> 16 & 0xFFFF;
                }
            }

            class Util
            {
                static quickSort(data, l, r)
                {
                    if (l >= r) return;
                    let ll = l,
                        rr = r;
                    const x = data[ll * 2];

                    do
                    {
                        while (data[ll * 2] > x) ++ll;
                        while (data[rr * 2] < x) --rr;

                        if (ll > rr) break;

                        const t0 = data[ll * 2];
                        data[ll * 2] = data[rr * 2];
                        data[rr * 2] = t0;

                        const t1 = data[ll * 2 + 1];
                        data[ll * 2 + 1] = data[rr * 2 + 1];
                        data[rr * 2 + 1] = t1;

                        ++ll;
                        --rr;
                    } while (ll <= rr);
                    Util.quickSort(data, l, rr);
                    Util.quickSort(data, ll, r);
                }

                static rotateVector2(vector, angle)
                {
                    const a = angle * (Math.PI / 0x10000);
                    const c = Math.cos(a);
                    const s = Math.sin(a);
                    return [c * vector[0] - s * vector[1], s * vector[0] + c * vector[1]];
                }

                static rotateVector3(vector, angle)
                {
                    const result = [vector[0], vector[1], vector[2]];
                    const a = Util.rotateVector2([result[1], result[2]], angle[2]);
                    result[1] = a[0];
                    result[2] = a[1];
                    const b = Util.rotateVector2([result[2], result[0]], angle[1]);
                    result[2] = b[0];
                    result[0] = b[1];
                    const c = Util.rotateVector2([result[0], result[1]], angle[0]);
                    result[0] = c[0];
                    result[1] = c[1];
                    return result;
                }

                static toInt16(x)
                {
                    let y = x & 0xFFFF;
                    if (y >= 0x8000) y -= 0x10000;
                    return y;
                }
            }

            class Camera
            {
                constructor()
                {
                    this.position = [-330.0, 0.0, 64.0];
                    this.matrix0 = [0.0, -1.0, 0.0, 0.0, 0.0, -1.0, 1.0, 0.0, 0.0];
                    this.matrix1 = Array.from(this.matrix0);
                    this.CAMERA_TABLE=[0xA1, 0xF8, 0xF8, 0x98, 0xA1, 0xA6, 0xF0, 0xA7, 0xB3, 0x37, 0x10, 0x36, 0x50, 0x84, 0x85, 0x85, 0x84, 0xF0, 0xF0, 0xB2, 0xA7, 0xA6, 0xA6, 0xA7, 0xF3, 0x26, 0x70, 0x27, 0x80, 0x44, 0x45, 0x77, 0x76, 0xA6, 0xB0, 0x61, 0x61, 0x52, 0xA7, 0x77, 0x30, 0x76, 0x80, 0xA2, 0x01, 0x41, 0x41, 0x01, 0xF5, 0x30, 0xF4, 0xB3, 0xA4, 0xF8, 0xA5, 0xD0, 0x47, 0x46, 0xF0, 0xA6, 0x80, 0xA7, 0x70, 0xA7, 0x10, 0xA6, 0x8E, 0xF0, 0x50, 0x8F, 0xB2, 0xF8, 0xA3, 0x80, 0x8E, 0xF0, 0x50, 0x8F, 0xB7, 0x10, 0xB6, 0xF0, 0x80, 0xA6, 0xA7, 0xF0, 0x87, 0xF0, 0x70, 0x86, 0x36, 0xF0, 0xF0, 0x90, 0x37, 0x83, 0x2C, 0xF0, 0xF0, 0xF0, 0x30, 0x2D, 0x82, 0x30, 0xB5, 0xB4, 0xF2, 0xA6, 0x30, 0xA7, 0x83, 0x83, 0xA6, 0xF0, 0x58, 0xA7, 0x77, 0x76, 0xF0, 0xF0, 0xF0, 0xF0, 0xF8, 0xF8, 0x00]
                    this.directionX = 1
                    this.speed = new Int16Array(4).fill(0);
                    this.pointer = 0
                    this.counter = 0
                    this.direction = 0
                }

                updateMatrix(a, b, c, d)
                {
                    const matrix2 = new Float32Array(9);

                    for (let i = 0; i < 3; ++i) for (let j = 0; j < 3; ++j) matrix2[i * 3 + j] = Number(i === j);

                    for (let i = 0; i < 3; ++i)
                    {
                        const v = Util.rotateVector3([matrix2[i * 3], matrix2[i * 3 + 1], matrix2[i * 3 + 2]], [b, c, d]);
                        matrix2[i * 3] = v[0];
                        matrix2[i * 3 + 1] = v[1];
                        matrix2[i * 3 + 2] = v[2];
                        for (let j = 0; j < 3; ++j) this.matrix0[i * 3 + j] = this.matrix1[i * 3 + j] = matrix2[i * 3] * this.matrix0[j]
                            + matrix2[i * 3 + 1] * this.matrix0[3 + j]
                            + matrix2[i * 3 + 2] * this.matrix0[6 + j];
                    }

                    for (let i = 0; i < 3; ++i)
                    {
                        const v = Util.rotateVector2([this.matrix1[i], this.matrix1[3 + i]], a);
                        this.matrix1[i] = v[0];
                        this.matrix1[3 + i] = v[1];
                    }
                }

                onTimer()
                {
                    if (--this.counter < 0)
                    {
                        let a = this.CAMERA_TABLE[this.pointer];

                        if (a === 0) return false;

                        this.counter = (a & 0xF8) << 1;
                        a &= 0x07;
                        this.direction = a;

                        if (a === 0x1) this.directionX = -this.directionX;

                        ++this.pointer;
                    }

                    if (this.direction === 0x1) this.speed[3] += this.directionX;

                    for (let i = 0; i < 3; ++i)
                    {
                        if (this.direction === 0x02 + i * 2) ++this.speed[i];
                        if (this.direction === 0x03 + i * 2) --this.speed[i];
                    }

                    this.updateMatrix(this.speed[2] << 4, this.speed[3] >> 2, this.speed[2] >> 2, this.speed[1] >> 2);
                    for (let i = 0; i < 3; ++i) this.position[i] += this.matrix0[6 + i] * this.speed[0] / 1792;
                }
            }

            class Texture
            {
                constructor()
                {
                    this.TEXTURE_PATTERN_TABLE = [0x13, 0x0F, 0x0F, 0x31, 0x31, 0x0A, 0x13, 0x10, 0x10, 0x30, 0x30, 0x11, 0x13, 0x11, 0x11, 0x2F, 0x2F, 0x18, 0x13, 0x12, 0x12, 0x2E, 0x2E, 0xBE, 0x13, 0x15, 0x15, 0x2B, 0x2B, 0x1E, 0x25, 0x00, 0x00, 0x3E, 0x1E, 0x03, 0x25, 0x03, 0x03, 0x3E, 0x1E, 0x07, 0x25, 0x03, 0x03, 0x3B, 0x1B, 0xFC, 0x25, 0x00, 0x20, 0x3E, 0x3E, 0x03, 0x25, 0x03, 0x23, 0x3E, 0x3E, 0x07, 0x25, 0x03, 0x23, 0x3B, 0x3B, 0xFC, 0x25, 0x00, 0x00, 0x3F, 0x3F, 0xFE, 0x2C, 0x00, 0x0A, 0x3F, 0x0F, 0xF6, 0x2C, 0x00, 0x0B, 0x3F, 0x10, 0x04, 0x2C, 0x00, 0x2F, 0x3F, 0x34, 0xF6, 0x2C, 0x00, 0x30, 0x3F, 0x35, 0x04, 0x2E, 0x13, 0x18, 0x2C, 0x27, 0x05, 0x2E, 0x14, 0x19, 0x2C, 0x27, 0xF4, 0x2E, 0x14, 0x19, 0x2B, 0x26, 0x07, 0x3E, 0x14, 0x19, 0x2B, 0x26, 0x06, 0x2F, 0x00, 0x18, 0x3F, 0x1E, 0x06, 0x2F, 0x00, 0x19, 0x3F, 0x1F, 0xFA, 0x3F, 0x00, 0x19, 0x3F, 0x1E, 0x06, 0x2F, 0x00, 0x20, 0x3F, 0x26, 0x06, 0x2F, 0x00, 0x21, 0x3F, 0x27, 0xFA, 0x3F, 0x00, 0x21, 0x3F, 0x26, 0x06]
                    this.TEXTURE_BACKGROUND_TABLE = [0x22, 0xC0, 0x26, 0x01, 0x26, 0x01, 0x26, 0x00, 0x20, 0x00, 0x20, 0x20, 0x20, 0x40, 0x22, 0x60, 0x24, 0x00, 0x22, 0x60, 0x24, 0x00, 0x24, 0x00, 0x24, 0x00, 0x24, 0x00]

                    console.log("Texture constructor");
                    this.doorCounter = 0;
                    this.textures = new Array(0x14);
                    for (let i = 0; i < 0x14; ++i)
                        this.textures[i] = new Uint8Array(64 * 64);

                    this.texture01Data = new Array(0x1E);
                }

                updateDoorTexture()
                {
                    const texture0D = this.textures[0x0D],
                        texture0F = this.textures[0x0F];
                    let offset = this.doorCounter;
                    if (offset < 0) offset = 0;
                    if (offset > 0x18) offset = 0x18;
                    offset <<= 6;
                    for (let i = 0; i < 0x800; ++i) texture0D[i] = texture0F[offset + i];
                    for (let i = 0; i < 0x800; ++i) texture0D[0x800 + i] = texture0F[0x800 - offset + i];
                    for (let i = 0; i < offset * 2; ++i) texture0D[0x800 - offset + i] = 0x00;
                }

                onTimer()
                {
                    const texture01 = this.textures[0x01];
                    const texture01Data = this.texture01Data;
                    texture01.fill(0x00);
                    for (let i = 0; i < 0x1E; ++i)
                    {
                        texture01Data[i][0] = texture01Data[i][0] - 1 & 0xFF;
                        texture01Data[i][0] & 0x3F;
                    }
                    ++this.doorCounter;
                }
                reset()
                {
                    this.doorCounter = -4250;
                    this.generateCircleNoise(0x11, 0x05, 0x0320);
                    this.generateCircleNoise(0x10, 0x0F, 0x0070);
                    this.textures[0x12].fill(0x14);
                    for (let i = 0; i < 0xFC0; ++i)
                    {
                        let a = Generate.random(0x4);
                        a = a + this.textures[0x12][i] + this.textures[0x12][i + 1] & 0xFF;
                        a = a - 1 >> 1;
                        this.textures[0x12][i + 0x40] = a;
                    }
                    this.textures[0x13].fill(0x03);
                    for (let i = 0; i < 0x1000; ++i)
                    {
                        const p = Generate.random(0x1000);
                        ++this.textures[0x13][p];
                    }

                    for (let i = 0; i < 0x1E; ++i)
                        this.texture01Data[i] = [Generate.random(0x100), Generate.random(0xEC0 + 0x80) + 0x40];

                    for (let i = 0; i < 0x1000; ++i)
                    {
                        let x = i;
                        if (x & 0x08)
                            x ^= 0x00FF;
                        x &= 0x0F;
                        let y = i >> 6;
                        if (y & 0x08)
                            y ^= 0x00FF;
                        y &= 0x0F;
                        this.textures[0x00][i] = 0xE0 + Math.min(x, y);
                    }

                    for (let i = 0x02, p = 0; i <= 0x0F; ++i, p += 2)
                    {
                        const src = this.textures[this.TEXTURE_BACKGROUND_TABLE[p] >> 1],
                            dst = this.textures[i];
                        const offset = this.TEXTURE_BACKGROUND_TABLE[p + 1];
                        for (let j = 0; j < 0x1000; ++j)
                            dst[j] = src[j] + offset;
                    }

                    for (let i = 0, p = 0; i < 0x1A; ++i, p += 6)
                    {
                        const dst = this.textures[this.TEXTURE_PATTERN_TABLE[p] & 0x0F];
                        const mode = this.TEXTURE_PATTERN_TABLE[p] >> 4;
                        const x0 = this.TEXTURE_PATTERN_TABLE[p + 1];
                        const y0 = this.TEXTURE_PATTERN_TABLE[p + 2];
                        const x1 = this.TEXTURE_PATTERN_TABLE[p + 3];
                        const y1 = this.TEXTURE_PATTERN_TABLE[p + 4];
                        const offset = this.TEXTURE_PATTERN_TABLE[p + 5];
                        for (let y = y0; y <= y1; ++y)
                            for (let x = x0; x <= x1; ++x)
                            {
                                const index = y << 6 | x;
                                let a;
                                switch (mode)
                                {
                                    case 1: a = 0;break;
                                    case 2: a = dst[index];break;
                                    default: a = x + y & 0x04; if (a !== 0) a = 0x98; break;
                                }
                                a += offset;
                                dst[index] = a;
                            }
                    }
                    for (let i = 0; i < 0x14; ++i)
                    {
                        for (let j = 0; j < 0x14 - i << 3; ++j)
                        {
                            const p = 0xFFF - 0x40 * i - Generate.random(0x40);
                            this.textures[0x0B][p] = 0x5E - i;
                        }
                    }
                }

                generateCircleNoise(id, r, n)
                {
                    const texture = this.textures[id];
                    texture.fill(0x00);
                    const table = new Array(r * 2);
                    for (let i = r; i > -r; --i)
                        table[r - i] = Math.round(Math.sqrt(r * r - i * i)) | 0;

                    for (let i = 0; i < n; ++i)
                    {
                        let p = Generate.random(0x1000);
                        for (let j = 0; j < r * 2; ++j)
                        {
                            const a = table[j];
                            for (let k = 0; k < a * 2; ++k)
                                ++texture[p - a + k & 0x0FFF];
                            p += 0x40;
                        }
                    }
                }
            }

            class Model
            {
                constructor()
                {
                    console.log("Model constructor");
                    this.INDEX_TABLE = [0x08, 0x28, 0x30, 0x10, 0x18, 0x38, 0x20, 0x00, 0x10, 0x30, 0x38, 0x18, 0x00, 0x20, 0x28, 0x08, 0x38, 0x30, 0x28, 0x20, 0x00, 0x08, 0x10, 0x18]
                    this.VERTEX_TABLE = [-32,-32,-32,32,-32,-32,32,32,-32,-32, 32, -32, -32, -32, 32, 32, -32, 32, 32, 32, 32, -32, 32, 32, 64, 0, 0, -64, 0, 0, 0, 64, 0, 0, -64, 0, 0, 0, 64, 0, 0, -64, 0, 0, 0]
                    this.MODEL_TABLE = [0x71, 0x70, 0x00, 0x06, 0x72, 0x00, 0x00, 0x06, 0x71, 0x00, 0x70, 0x06, 0x73, 0x07, 0x70, 0x06, 0x73, 0x07, 0x00, 0x06, 0x70, 0x07, 0x07, 0x06, 0x74, 0x00, 0x07, 0x06, 0x70, 0x00, 0x07, 0x40, 0x72, 0x70, 0x07, 0x50, 0x72, 0x70, 0x00, 0x50, 0x71, 0x70, 0x70, 0x50, 0x73, 0x00, 0x70, 0x40, 0x71, 0x00, 0x00, 0x40, 0x72, 0x00, 0x00, 0x50, 0x71, 0x00, 0x70, 0x50, 0x73, 0x07, 0x70, 0x46, 0x73, 0x00, 0x00, 0x46, 0x70, 0x07, 0x07, 0x46, 0x72, 0x00, 0x07, 0x50, 0x71, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, 0x71, 0x00, 0xBB, 0x56, 0x70, 0x0F, 0xBB, 0x46, 0xFF, 0x33, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x07, 0x06, 0xE4, 0xB0, 0x00, 0xBB, 0x46, 0xE4, 0x90, 0x00, 0xBB, 0x56, 0xE4, 0x90, 0x00, 0xBB, 0x56, 0xE4, 0x30, 0x00, 0xBB, 0x56, 0xF0, 0x00, 0xBB, 0x56, 0x11, 0xF0, 0x00, 0xBB, 0x46, 0x11, 0xB0, 0x00, 0xBB, 0x56, 0x11, 0x90, 0x00, 0xBB, 0x56, 0x11, 0xB0, 0x00, 0xBB, 0x56, 0x11, 0xF0, 0x00, 0xBB, 0x56, 0x11, 0xF0, 0x00, 0xBB, 0x46, 0x11, 0xB0, 0x00, 0xBB, 0x56, 0x11, 0x30, 0x00, 0xBB, 0x56, 0x10, 0x00, 0xBB, 0x56, 0x34, 0x00, 0x00, 0x00, 0x32, 0x05, 0x00, 0x80, 0x35, 0x05, 0x80, 0x80, 0x35, 0x05, 0x80, 0x00, 0x33, 0x05, 0x80, 0x08, 0x33, 0x05, 0x00, 0x08, 0x74, 0x05, 0x08, 0x08, 0x74, 0x05, 0x00, 0x00, 0x73, 0x05, 0x08, 0x80, 0x75, 0x00, 0x00, 0x00, 0x75, 0x05, 0x08, 0x88, 0x70, 0x00, 0x00, 0x00, 0x74, 0x64, 0x08, 0x08, 0x74, 0x60, 0x08, 0x00, 0x72, 0x64, 0x08, 0x80, 0x05, 0x60, 0x00, 0x80, 0x05, 0x60, 0x00, 0x00, 0x02, 0x60, 0x00, 0x08, 0x34, 0x60, 0x00, 0x08, 0x34, 0x60, 0x00, 0x00, 0x32, 0x60, 0x00, 0x80, 0x35, 0x60, 0x00, 0x80, 0x35, 0x60, 0x00, 0x00, 0x32, 0x60, 0x00, 0x08, 0x34, 0x35, 0x00, 0x08, 0x14, 0x65, 0x00, 0x00, 0x32, 0x35, 0x00, 0x80, 0x35, 0x35, 0x00, 0x80, 0x15, 0x65, 0x00, 0x00, 0x32, 0x35, 0x00, 0x08, 0x34, 0x35, 0x80, 0x08, 0x14, 0x65, 0x00, 0x00, 0x32, 0x35, 0x80, 0x80, 0x75, 0x00, 0x00, 0x00, 0x52, 0x65, 0xE0, 0x77, 0x32, 0x64, 0x0E, 0x77, 0x12, 0x65, 0x00, 0x77, 0x00, 0x65, 0x00, 0x77, 0xFF, 0x32, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x14, 0xB0, 0x00, 0x00, 0x00, 0x14, 0x30, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0xF4, 0xF0, 0x00, 0xDD, 0x56, 0xF4, 0x30, 0x00, 0xDD, 0x46, 0x30, 0x00, 0xDD, 0x56, 0x30, 0x00, 0xDD, 0x56, 0x32, 0x00, 0x00, 0x50, 0x30, 0x0A, 0xA0, 0x50, 0x33, 0x00, 0xA0, 0x50, 0x30, 0x00, 0x00, 0x50, 0x32, 0x70, 0x00, 0x50, 0x30, 0x00, 0xA0, 0x50, 0x33, 0xA0, 0xA7, 0x50, 0x33, 0x00, 0x00, 0x00, 0x31, 0xA0, 0x7A, 0x50, 0x31, 0x00, 0x0A, 0x50, 0x31, 0x00, 0x0A, 0x50, 0x32, 0x0A, 0x0A, 0x50, 0x35, 0x00, 0x00, 0x00, 0x72, 0x0A, 0x00, 0x00, 0x70, 0x0A, 0xA0, 0x00, 0x73, 0x00, 0xA0, 0x00, 0x70, 0x00, 0x00, 0x00, 0x72, 0x00, 0x00, 0x00, 0x70, 0x00, 0xA0, 0x00, 0x73, 0xA0, 0xA0, 0x00, 0x73, 0xA0, 0x00, 0x99, 0x71, 0xA0, 0x0A, 0x00, 0x71, 0x00, 0x0A, 0x00, 0x71, 0x00, 0x0A, 0x00, 0x75, 0x0A, 0x0A, 0x00, 0x70, 0x0C, 0x0C, 0x03, 0x70, 0x00, 0x0C, 0x03, 0x70, 0x00, 0x0C, 0x03, 0x72, 0xC0, 0x7C, 0x03, 0x72, 0x00, 0x00, 0x00, 0x71, 0xC0, 0xC7, 0x03, 0x73, 0x00, 0xC0, 0x03, 0x71, 0x70, 0x00, 0x03, 0x72, 0x00, 0x00, 0x03, 0x71, 0x00, 0xC0, 0x03, 0x73, 0x0C, 0xC0, 0x03, 0x71, 0x00, 0x00, 0x03, 0x31, 0x0C, 0xCC, 0xA3, 0xFF, 0x32, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x70, 0x06, 0x14, 0xB0, 0x00, 0xDD, 0x46, 0x14, 0x30, 0x00, 0xDD, 0x56, 0xB2, 0x00, 0x0D, 0x56, 0xC4, 0x32, 0xDD, 0x00, 0x56, 0x32, 0xDD, 0x00, 0x56, 0x32, 0xDD, 0x00, 0x56, 0x70, 0x00, 0xF0, 0x56, 0x70, 0x00, 0xBB, 0x56, 0x32, 0xB0, 0x0B, 0x46, 0x72, 0xBB, 0x00, 0x56, 0x71, 0xB0, 0xB0, 0x56, 0x71, 0x02, 0x11, 0x56, 0x71, 0x22, 0x11, 0x56, 0x31, 0x20, 0x11, 0x56, 0x73, 0x0B, 0xB0, 0x56, 0x73, 0xBB, 0x00, 0x56, 0x30, 0x0B, 0x0B, 0x46, 0x30, 0x00, 0xBB, 0x56, 0xFF]

                    this.generateModel();
                    console.log("this.quadCount: " + this.quadCount);
                    console.log("this.vertexCount: " + this.vertexCount);
                    console.log("this.quads: " + this.quads);
                    console.log("this.vertexs: " + this.vertexs);
                    this.transformedVertexs = new Float32Array(this.vertexCount * 3);
                }

                generateModel()
                {
                    this.vertexCount = 0;
                    this.quadCount = 0;
                    this.vertexs = new Int16Array(362 * 4).fill(0)
                    this.quads = new Int16Array(367 * 5).fill(0)
                    console.log("generateModel");

                    let p = 0;
                    let int16Table = new Array(4 * 15);
                    let float32Table = new Array(3 * 15);

                    for (let i = 0; i < 4; ++i)
                    {
                        for (let j = 0; j < 15; ++j)
                        {
                            for (let k = 0; k < 3; ++k)
                            {
                                const x = this.VERTEX_TABLE[j * 3 + k];
                                int16Table[j * 4 + k] = x;
                                float32Table[j * 3 + k] = x;
                            }
                            int16Table[j * 4 + 3] = 0x7F00;
                        }

                        while (true)
                        {
                            const a = this.MODEL_TABLE[p++];

                            if (a === 0xFF)
                                break;

                            const face = a & 0x0F;
                            const light = ((a << 8) & 0x7000) | 0x0F00;

                            for (let j = 0; j < 6; ++j)
                            {
                                let textureIndex;
                                if (j & 0x01)
                                    textureIndex = this.MODEL_TABLE[p++] & 0x0F;
                                else
                                    textureIndex = this.MODEL_TABLE[p] >> 4;

                                --textureIndex;

                                if (textureIndex < 0)
                                    continue;

                                this.quads[this.quadCount * 5 + 4] = textureIndex;

                                for (let k = 0; k < 4; ++k)
                                {
                                    const index = this.INDEX_TABLE[j * 4 + k] >> 3;
                                    let vertexIndex = 0;
                                    for (; vertexIndex < this.vertexCount; ++vertexIndex)
                                        if (int16Table[index * 4] === this.vertexs[vertexIndex * 4]
                                            && int16Table[index * 4 + 1] === this.vertexs[vertexIndex * 4 + 1]
                                            && int16Table[index * 4 + 2] === this.vertexs[vertexIndex * 4 + 2])
                                            break;

                                    if (vertexIndex === this.vertexCount)
                                    {
                                        this.vertexs[vertexIndex * 4] = int16Table[index * 4];
                                        this.vertexs[vertexIndex * 4 + 1] = int16Table[index * 4 + 1];
                                        this.vertexs[vertexIndex * 4 + 2] = int16Table[index * 4 + 2];
                                        this.vertexs[vertexIndex * 4 + 3] = int16Table[index * 4 + 3];
                                        ++this.vertexCount;
                                    }
                                    this.quads[this.quadCount * 5 + k] = vertexIndex;
                                }
                                ++this.quadCount;
                            }

                            for (let j = 0; j < 3; ++j)
                                float32Table[14 * 3 + j] += float32Table[(8 + face) * 3 + j];

                            if (a & 0x80)
                            {
                                let angle = (this.MODEL_TABLE[p] << 8) & 0xF000;

                                if (angle >= 0x8000) angle -= 0x10000;

                                let angles= [
                                    this.MODEL_TABLE[p] & 0x04 ? angle : 0,
                                    this.MODEL_TABLE[p] & 0x02 ? angle : 0,
                                    this.MODEL_TABLE[p] & 0x01 ? angle : 0,
                                ];
                                for (let j = 0; j < 14; ++j)
                                {
                                    const v = Util.rotateVector3([float32Table[j * 3],
                                        float32Table[j * 3 + 1],
                                        float32Table[j * 3 + 2],
                                    ], angles);
                                    float32Table[j * 3] = v[0];
                                    float32Table[j * 3 + 1] = v[1];
                                    float32Table[j * 3 + 2] = v[2];
                                }
                                ++p;
                            }
                            for (let j = 0; j < 4; ++j)
                            {
                                const index0 = this.INDEX_TABLE[face * 4 + j] >> 3;
                                const index1 = this.INDEX_TABLE[(face * 4 + j) ^ 0x7] >> 3;

                                for(let k = 0; k < 4; ++k)
                                    int16Table[index1 * 4 + k] = int16Table[index0 * 4 + k];

                                for(let k = 0; k < 3; ++k)
                                    int16Table[index0 * 4 + k] = Math.round(
                                        float32Table[index0 * 3 + k] + float32Table[14 * 3 + k]);

                                int16Table[index0 * 4 + 3] = light;
                            }
                        }
                    }
                }

                transformModel(camera)
                {
                    const cameraPosition = camera.position;
                    const cameraMatrix = camera.matrix1;
                    for (let i = 0; i < this.vertexCount; ++i)
                        for (let j = 0; j < 3; ++j)
                            this.transformedVertexs[i * 3 + j] = (this.vertexs[i * 4] - cameraPosition[0]) * cameraMatrix[j * 3]
                                + (this.vertexs[i * 4 + 1] - cameraPosition[1]) * cameraMatrix[j * 3 + 1]
                                + (this.vertexs[i * 4 + 2] - cameraPosition[2]) * cameraMatrix[j * 3 + 2];
                }
            }

            class Renderer
            {
                constructor(canvas)
                {
                    this.rendererCounter = 0;
                    this.TEXTURE_COORD_U_TABLE=[0, 0, 63, 63]
                    this.TEXTURE_COORD_V_TABLE=[63, 0, 0, 63]
                    console.log("Renderer constructor");
                    this.camera = new Camera();
                    this.model = new Model();
                    this.texture = new Texture();
                    this.background = new Uint8Array(320 * 200);
                    this.frameBuffer = new Uint8Array(320 * 200);
                    this.renderer = new THREE.WebGLRenderer({
                        canvas: canvas,
                        antialias: true
                    });
                    this.renderer.setPixelRatio(window.devicePixelRatio);
                    this.frameBufferScene = new THREE.Scene();
                    this.frameBufferMaterial = new THREE.MeshBasicMaterial({
                        depthTest: false,
                        side: THREE.DoubleSide
                    });
                    this.frameBufferGeometry = new THREE.PlaneGeometry(1, 1);
                    this.frameBufferMesh = new THREE.Mesh(this.frameBufferGeometry, this.frameBufferMaterial);
                    this.frameBufferScene.add(this.frameBufferMesh);
                    this.frameBufferCamera = new THREE.OrthographicCamera(-0.5, 0.5, -0.5, 0.5, 0.0, 1.0);
                    this.onResize();
                    this.reset();
                }

                reset()
                {
                    this.texture.reset();
                    this.rendererCounter = 0;
                }

                onTimer()
                {
                    this.rendererCounter = this.rendererCounter + 1 & 0x7;
                    if (this.rendererCounter === 0)
                        this.texture.onTimer();

                    this.camera.onTimer();
                }

                renderFrameBuffer()
                {
                    const size = new THREE.Vector2();
                    this.renderer.getSize(size);
                    const width = size.x,
                        height = size.y;
                    this.renderer.clear();
                    const frameBufferTexture = this.convertFrameBuffer(this.frameBuffer);
                    this.frameBufferMaterial.map = frameBufferTexture;
                    this.renderer.setViewport(0, 0, width, height);
                    this.renderer.render(this.frameBufferScene, this.frameBufferCamera);
                    frameBufferTexture.dispose();
                }
                drawPolygon(textureIndex, clippedVertexCount, clippedDataI)
                {
                    const lightMap = Generate.LightMap();
                    let maxX = -32767;
                    let minY = 32767,
                        maxY = -32767;
                    let indexL = 0,
                        indexR = 0;

                    for (let i = 0; i < clippedVertexCount; ++i)
                    {
                        const x = clippedDataI[4][i] >> 16;

                        if (maxX < x) maxX = x;

                        const y = Util.toInt16(clippedDataI[3][i]);

                        if (minY > y)
                        {
                            minY = y;
                            indexL = indexR = i;
                        }
                        if (maxY < y) maxY = y;
                    }

                    if (maxX < 0 || minY > 320 || maxY < 21 || minY > 179) return;

                    if (maxY > 179) maxY = 179;

                    if (minY === maxY) return;

                    let scanlineY = minY;
                    const t0 = new Int32Array(10);
                    const t1 = new Int32Array(10);
                    const t2 = new Int32Array(5);
                    const t3 = new Int32Array(5);

                    function interpolate(index0, index1, offset)
                    {
                        const y = Util.toInt16(clippedDataI[3][index1]);
                        const dy = y - scanlineY;
                        for (let i = 0; i < 5; ++i)
                        {
                            const x0 = clippedDataI[4 + i][index0];
                            t0[offset + i] = x0;
                            const x1 = clippedDataI[4 + i][index1];
                            let dx = x1 - x0;
                            if (dy !== 0)
                            {
                                dx = dx / dy | 0;
                                t1[offset + i] = dx;
                            }
                        }
                    }
                    const texture = this.texture.textures[textureIndex];

                    while (scanlineY <= maxY)
                    {
                        while (true)
                        {
                            const y = Util.toInt16(clippedDataI[3][indexL]);
                            if (scanlineY !== y) break;

                            const index0 = indexL;

                            if (--indexL < 0) indexL = clippedVertexCount - 1;

                            interpolate(index0, indexL, 0);
                        }
                        while (true)
                        {
                            const y = Util.toInt16(clippedDataI[3][indexR]);

                            if (scanlineY !== y) break;

                            const index0 = indexR;

                            if (++indexR === clippedVertexCount) indexR = 0;

                            interpolate(index0, indexR, 5);
                        }
                        if (scanlineY >= 21)
                        {
                            let l = t0[0] >> 16,
                                r = t0[5] >> 16;
                            const dx = r - l;
                            if (dx !== 0 && r > 0 && l <= 320)
                            {
                                let dl = -l;
                                if (dl < 0)
                                    dl = 0;else l = 0;

                                for (let i = 1; i < 5; ++i)
                                {
                                    const a0 = t0[i],
                                        a1 = t0[5 + i];
                                    const da = a1 - a0;
                                    if (dx !== 0) t2[i] = da / dx;
                                    t3[i] = t2[i] * dl + a0;
                                }
                                const dd = Util.toInt16(t2[4]);

                                if (r > 320)
                                    r = 320;

                                let p = scanlineY * 320 + l;
                                let u0 = Util.toInt16(t3[1] * 256 / t3[3]);
                                let v0 = Util.toInt16(t3[2] * 256 / t3[3]);
                                while (true)
                                {
                                    let d = r - l;
                                    if (d <= 0) break;
                                    if (d > 16) d = 16;
                                    t3[1] += t2[1] * d;
                                    t3[2] += t2[2] * d;
                                    t3[3] += t2[3] * d;
                                    let u1 = Util.toInt16(t3[1] * 256 / t3[3]);
                                    let v1 = Util.toInt16(t3[2] * 256 / t3[3]);
                                    const du = Util.toInt16((u1 - u0) / d);
                                    const dv = Util.toInt16((v1 - v0) / d);
                                    for (let i = 0; i < d; ++i)
                                    {
                                        const q = (v0 & 0xFF00) >> 2 | u0 >> 8;
                                        const value = texture[q];

                                        if (value)
                                            this.frameBuffer[p] = lightMap[value + (t3[4] & 0xFF00)];

                                        t3[4] += dd;
                                        u0 = Util.toInt16(u0 + du);
                                        v0 = Util.toInt16(v0 + dv);
                                        ++p;
                                    }
                                    u0 = u1;
                                    v0 = v1;
                                    l += 16;
                                }
                            }
                        }
                        for (let i = 0; i < 10; ++i) t0[i] += t1[i];
                        ++scanlineY;
                    }
                }

                drawQuad(quadIndex)
                {
                    const data = new Array(9),
                        dataI = new Array(9);

                    const clippedData = new Array(9),
                        clippedDataI = new Array(9);

                    for (let i = 0; i < 9; ++i)
                    {
                        data[i] = new Float32Array(4);
                        clippedData[i] = new Float32Array(5);
                    }
                    for (let i = 0; i < 9; ++i)
                    {
                        dataI[i] = new Int32Array(data[i].buffer);
                        clippedDataI[i] = new Int32Array(clippedData[i].buffer);
                    }
                    for (let i = 0; i < 4; ++i)
                    {
                        const vertexIndex = this.model.quads[quadIndex * 5 + i];
                        data[0][i] = this.model.transformedVertexs[vertexIndex * 3];
                        data[1][i] = this.model.transformedVertexs[vertexIndex * 3 + 1];
                        data[2][i] = this.model.transformedVertexs[vertexIndex * 3 + 2];
                        let z = Math.round(data[2][i]) + 512;

                        if (z < 0) return;

                        if (z > 511) z = 511;

                        dataI[8][i] = (z << 7) * this.model.vertexs[vertexIndex * 4 + 3] >> 16;
                        dataI[6][i] = this.TEXTURE_COORD_V_TABLE[i] << 16;
                        dataI[5][i] = this.TEXTURE_COORD_U_TABLE[i] << 16;
                    }
                    const textureIndex = this.model.quads[quadIndex * 5 + 4];
                    let clippedVertexCount = 0;
                    let neg = data[2][3] < 0;

                    function clip(i1)
                    {
                        let i0 = i1 - 1;
                        if (i0 < 0)
                            i0 = 3;

                        const z = data[2][i1] / (data[2][i1] - data[2][i0]);

                        for (let i of [0, 1, 2, 5, 6, 8])
                            clippedData[i][clippedVertexCount] = (data[i][i0] - data[i][i1]) * z + data[i][i1];

                        ++clippedVertexCount;
                    }

                    for (let i = 0; i < 4; ++i)
                    {
                        const z = data[2][i];
                        if (z < 0)
                        {
                            if (!neg)
                            {
                                clip(i);
                                neg = !neg;
                            }
                            for (let j = 0; j < 9; ++j) clippedDataI[j][clippedVertexCount] = dataI[j][i];
                            ++clippedVertexCount;
                        }
                        else
                        {
                            if (neg)
                            {
                                clip(i);
                                neg = !neg;
                            }
                        }
                    }

                    if (clippedVertexCount < 2)
                        return;

                    for (let i = 0; i < clippedVertexCount; ++i)
                    {
                        const z = (13 - clippedData[2][i]) / 160;
                        clippedDataI[3][i] = Math.round(clippedData[1][i] / z + 100);
                        clippedDataI[4][i] = Math.round(clippedData[0][i] * 1.2 / z + 160) * 65536;
                        clippedDataI[5][i] = Math.round(clippedDataI[5][i] / z);
                        clippedDataI[6][i] = Math.round(clippedDataI[6][i] / z);
                        clippedDataI[7][i] = Math.round(65536 / z);
                    }
                    this.drawPolygon(textureIndex, clippedVertexCount, clippedDataI);
                }

                render()
                {
                    this.renderer.clear();
                    this.texture.updateDoorTexture();

                    for (let i = 0; i < 320 * 200; ++i)
                        this.frameBuffer[i] = this.background[i];

                    this.model.transformModel(this.camera);

                    this.sortList = new Int16Array((this.model.quadCount + 1) * 2);

                    for (let i = 0; i < this.model.quadCount; ++i)
                    {
                        let z = 0;
                        for (let j = 0; j < 4; ++j)
                        {
                            const index = this.model.quads[i * 5 + j];
                            z -= this.model.transformedVertexs[index * 3 + 2];
                        }
                        this.sortList[i * 2] = z;
                        this.sortList[i * 2 + 1] = i;
                    }

                    Util.quickSort(this.sortList, 0, this.model.quadCount - 1);

                    for (let i = 0; i < this.model.quadCount; ++i)
                        this.drawQuad(this.sortList[i * 2 + 1]);

                    this.renderFrameBuffer();
                }

                onResize()
                {
                    const WIDTH = 320,
                        HEIGHT = 200;
                    const scale = Math.max(Math.floor(Math.min(window.innerWidth / WIDTH, window.innerHeight / HEIGHT) * window.devicePixelRatio * 0.8), 1) / window.devicePixelRatio;
                    this.renderer.setSize(WIDTH * scale, HEIGHT * scale);
                }

                convertFrameBuffer(data)
                {
                    const WIDTH = 320;
                    const HEIGHT = 200;
                    const palette = Generate.Palette();
                    const result = new Uint8Array(4 * WIDTH * HEIGHT);

                    for (let i = 0; i < WIDTH * HEIGHT; ++i)
                    {
                        const value = data[i];
                        result[i * 4] = palette[value * 3];
                        result[i * 4 + 1] = palette[value * 3 + 1];
                        result[i * 4 + 2] = palette[value * 3 + 2];
                        result[i * 4 + 3] = 0xFF;
                    }
                    const texture = new THREE.DataTexture(result, WIDTH, HEIGHT, THREE.RGBAFormat);
                    texture.needsUpdate = true;
                    return texture;
                }
            }

            class Omniscent
            {
                constructor(canvas)
                {
                    console.log(" constructor");
                    this.renderer = new Renderer(canvas);
                }

                onRender()
                {
                    this.renderer.render();
                }

                async start(speed)
                {
                    let count = speed;
                    function wait() {
                        return new Promise(resolve => {
                            setTimeout(resolve, 10);
                        });
                    }
                    while (true)
                    {
                        while (count-- > 0)
                            this.renderer.onTimer();

                        count = speed;
                        await wait();
                    }
                }
            }

            const canvas = document.getElementById('main-canvas');
            const OMNISCENT = new Omniscent(canvas);

            requestAnimationFrame(function onRender()
            {
                OMNISCENT.onRender();
                requestAnimationFrame(onRender);
            });

            OMNISCENT.start(60);
        </script>
    </body>
</html>

参考博客:Threejs简单介绍(含案例演示)_three.js-CSDN博客


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值