From d59b30d3d76abeff3c9a26ccbd60da7a8b7c728b Mon Sep 17 00:00:00 2001 From: Joonas Yliaho Date: Thu, 27 Jan 2022 16:49:10 +0200 Subject: [PATCH 1/5] wip: use pixijs to render map --- package-lock.json | 277 ++++++++++++++++++++++++++++++++++- package.json | 1 + src/App.vue | 12 +- src/components/MapCanvas.vue | 70 +++------ src/draw.ts | 77 ++++++---- src/lib/app.ts | 29 ++++ src/lib/datas-bin.ts | 11 +- src/lib/renderer.ts | 168 +++++++++++++++++++++ 8 files changed, 553 insertions(+), 92 deletions(-) create mode 100644 src/lib/app.ts create mode 100644 src/lib/renderer.ts diff --git a/package-lock.json b/package-lock.json index 3190e0f..8f87f3d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -147,6 +147,199 @@ "fastq": "^1.6.0" } }, + "@pixi/accessibility": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/@pixi/accessibility/-/accessibility-6.2.2.tgz", + "integrity": "sha512-/mXRXCw67bmPY/OZ1Y1p747h3SSg7eqacIChAUJohjbcJK0R2EJRD2uVTspVIUpHPJA0ECNGBpKqk0C1Yzkj2w==" + }, + "@pixi/app": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/@pixi/app/-/app-6.2.2.tgz", + "integrity": "sha512-YBzVaSZGA842w2gsgqzxYwQMXeu2JZmSyiybi4raFsA35iOeMurXy7sEs5NP9JO+cjobJyx6echuHzZpKUjWsQ==" + }, + "@pixi/compressed-textures": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/@pixi/compressed-textures/-/compressed-textures-6.2.2.tgz", + "integrity": "sha512-ZjiqYCE6nGtsKTRa6w4W6Krh3vo4M3WT6lrP+VW6BfgUx3quEURt5GVFsFZrJpWF4yI1fShFmjBUOerrTLJGRQ==" + }, + "@pixi/constants": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/@pixi/constants/-/constants-6.2.2.tgz", + "integrity": "sha512-BKSoj/5SI+pQEatuCG5kXXWtCZmZZNMhfhXeqvYO/WNZ+LDxm6F4pllf0t7KjGs1ZBpNxVf6fyngF9Q5r3MgJQ==" + }, + "@pixi/core": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/@pixi/core/-/core-6.2.2.tgz", + "integrity": "sha512-XAqgdJ1w9k1ZUBXECm19rcnN2ngm+tOP74HkGw4qQay0biM3JS+wtX4fWQmZNGr8krf6lJrNbsghbtUy70uUaw==" + }, + "@pixi/display": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/@pixi/display/-/display-6.2.2.tgz", + "integrity": "sha512-8a0R+9rjlUUjb13nBA6ZNj9gygJqt38B63uIZ2inkhxpIQf0CLo2hNxkqCqXiMeRuGmOw1n6neEDMnHO1Ks+xA==" + }, + "@pixi/extract": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/@pixi/extract/-/extract-6.2.2.tgz", + "integrity": "sha512-w3gW1/VoHNqFEUNGRQBKm8dCdg816etbpbLExWctmPpNdyxos5N7DF44UMRFg40GPVBBNzYissrH/ojca4PFIA==" + }, + "@pixi/filter-alpha": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/@pixi/filter-alpha/-/filter-alpha-6.2.2.tgz", + "integrity": "sha512-CijLcgFdmivmSyZuM5Yyeo6R+PwalZp9OSoard1Oh5DBVvcRDn4m3cBM+nimR4YJbr0kiMbK4Ja8r+e2vwFVjA==" + }, + "@pixi/filter-blur": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/@pixi/filter-blur/-/filter-blur-6.2.2.tgz", + "integrity": "sha512-ApFqn2fMIipr3mRp/8dZ74qraGGzzPO/EzvltDqJLru9vGlbX6dKLXZ6w5H8D/uN6aQW1e4N1Nrtzk5mvJVQ3g==" + }, + "@pixi/filter-color-matrix": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/@pixi/filter-color-matrix/-/filter-color-matrix-6.2.2.tgz", + "integrity": "sha512-fQWbtKFWV29jKkq4d6TknEfQ5sF5OxcbJeZo0HJmgoV3FLZ0t21XE991CFI/TqDBo8U3wzUPZVbXxiFoDKmJ8w==" + }, + "@pixi/filter-displacement": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/@pixi/filter-displacement/-/filter-displacement-6.2.2.tgz", + "integrity": "sha512-cd9um4kNNIeqKA/wVZw+iha+XVbBOYBC8En5hk3ZXAIXxCHxOCz3KS+aOVejXH5EB/gMDPvNNwygn0SCpSGdKA==" + }, + "@pixi/filter-fxaa": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/@pixi/filter-fxaa/-/filter-fxaa-6.2.2.tgz", + "integrity": "sha512-e4qekMlsiEcjV0JRoqH3b34sk8yzT4jsROYPHzk0IiafE+nNNcF3vQmcmnfC0aGIyODzmNdzFLjlFkRRSviydA==" + }, + "@pixi/filter-noise": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/@pixi/filter-noise/-/filter-noise-6.2.2.tgz", + "integrity": "sha512-Jp4L6winS6ZGKpp76x3JyfEWnUMY44fQ90Ts3R3vKkZZFNDd3T4uisZ7YwvDKOhmSo5hY3lQkXaCg/YO5feXbw==" + }, + "@pixi/graphics": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/@pixi/graphics/-/graphics-6.2.2.tgz", + "integrity": "sha512-mQyd6ef6/EF5nt7M1OObBEb9FCXxIP6AT30H01Z2wnnCgu4qj8MHrJxTkQxSHynQ+eVVPswzpVizUQZHlIYZNw==" + }, + "@pixi/interaction": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/@pixi/interaction/-/interaction-6.2.2.tgz", + "integrity": "sha512-gpNLCPc+j+RZSZqbKbzVRf4fSlOlYm0xqUVn6JtNH1kc+d9AV7Nmw9but4osP/eodDWsWPQ+7sPKClHY36bKRA==" + }, + "@pixi/loaders": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/@pixi/loaders/-/loaders-6.2.2.tgz", + "integrity": "sha512-jwFM59GeMQpzuniw5PlC7kCoXZEaKrw31/ecR1sXKWDtHRyMtvXTuf+R+tSol/1ISQ55c0JBTuUbLPwp7hPvFQ==" + }, + "@pixi/math": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/@pixi/math/-/math-6.2.2.tgz", + "integrity": "sha512-TtsaooRRMc/WAZ4LKUDhP/d14BZElLjRNa2gopwTKUtrDa1KvzAMr8WJ8P+gaXl4DJ8B/MlgESdPhRUqVSUw0A==" + }, + "@pixi/mesh": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/@pixi/mesh/-/mesh-6.2.2.tgz", + "integrity": "sha512-CsKFgTu2MP756sHeoCr9s4tHy2VmnDZPnvZ0ThV8QMnb5w3Z2qRDKlXSSIdNaQOxoAPKkqxIu0JbLK8kyX0oqw==" + }, + "@pixi/mesh-extras": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/@pixi/mesh-extras/-/mesh-extras-6.2.2.tgz", + "integrity": "sha512-HFYWhWcV6gY7VYnMhz9OSEN14PPfVqLzWnglbegGEMqCbY/ZGsD8X99x/HLGQGd6L4FFto382q0Fj1xu+y/brg==" + }, + "@pixi/mixin-cache-as-bitmap": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/@pixi/mixin-cache-as-bitmap/-/mixin-cache-as-bitmap-6.2.2.tgz", + "integrity": "sha512-t3jZKGa/qoRMetMWmGkXz8Kp1Uzmb+2y4/adqu+RdIeG3D1oItuGux+R36ZQO6dVRv3R8s2/Dex0aACek171zw==" + }, + "@pixi/mixin-get-child-by-name": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/@pixi/mixin-get-child-by-name/-/mixin-get-child-by-name-6.2.2.tgz", + "integrity": "sha512-BBrniLAkzDex4HyvVdE/DjphzQu4pZ8Nc5aDRIbiS1s283/IXr2oTcoaW23kCjhX0xgu++XcJQQMMyv3mlblZQ==" + }, + "@pixi/mixin-get-global-position": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/@pixi/mixin-get-global-position/-/mixin-get-global-position-6.2.2.tgz", + "integrity": "sha512-Rz7DHn6koYFEeVG36rKiMwoTD+elJKqwQ24HHw0BAKz1VwGagBi0ZTcJ+nWplBOrw6ZPKfdOBwGQLXD7ODg8lQ==" + }, + "@pixi/particle-container": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/@pixi/particle-container/-/particle-container-6.2.2.tgz", + "integrity": "sha512-DYbSCcUiVLeM4sKZkzAp3F6dz3idyP1jecxbFqNmRjWRyMv7uXIO42rxGJMrd6BzA5j7DkywI3X0SqhhSZP7Ag==" + }, + "@pixi/polyfill": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/@pixi/polyfill/-/polyfill-6.2.2.tgz", + "integrity": "sha512-Fd5KnjrqG9Vwgl9sDfPvNeqW3/d+hG9Du7H3y5PmItBnu9wXldTtA+I5D0BLsL/wjjjCQLbPVFKwCJj511XfBw==", + "requires": { + "object-assign": "^4.1.1", + "promise-polyfill": "^8.2.0" + } + }, + "@pixi/prepare": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/@pixi/prepare/-/prepare-6.2.2.tgz", + "integrity": "sha512-kJojn/6zEcao+XQyU+zWkBmQr0Tgeju3F9JYBpPQ8MKIUJYvDQDtRxYo9A6Xzxk8FJ373s2Ext/OelX2FcR3HQ==" + }, + "@pixi/runner": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/@pixi/runner/-/runner-6.2.2.tgz", + "integrity": "sha512-q7bc6Eu2XplGzCQBOhbv32P0z48ixW/Su6epT9IOfDi2iTiPjB5Sxp9e+DZDFIzvkfLzgr67Ddy51YMvOp5sQg==" + }, + "@pixi/settings": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/@pixi/settings/-/settings-6.2.2.tgz", + "integrity": "sha512-eQv0ykSwnJUd/LF4MuaFoL+eBNG+EUPAVfsnlsez/Y09aqwIzJyAjRx+uGp9adQ3XHXwYt2l2wINn+foF1y/8A==", + "requires": { + "ismobilejs": "^1.1.0" + } + }, + "@pixi/sprite": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/@pixi/sprite/-/sprite-6.2.2.tgz", + "integrity": "sha512-Imr+sJWFh5GtarW3FBBUzedSexfijg7OL0A6qwMDHA011gjyVeRZ15uXP8fgIwUoHoMLsU6xk85jcucM9RfWuw==" + }, + "@pixi/sprite-animated": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/@pixi/sprite-animated/-/sprite-animated-6.2.2.tgz", + "integrity": "sha512-MNkVIuC06aXn8bgfWyqQE8vmclCVLgmHB//hssr/1IFCVmnEEYZLyeWErkIA87grY3iV7tGOILEYSa3pod4XEg==" + }, + "@pixi/sprite-tiling": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/@pixi/sprite-tiling/-/sprite-tiling-6.2.2.tgz", + "integrity": "sha512-HQ9RVObmwyPq+PM2wm2UEIMdsvWg96ymSz0NOh9bOfMSme18vSWv0Rbidv/FziQT8x6MpoLpYke0DYMGtbu0tA==" + }, + "@pixi/spritesheet": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/@pixi/spritesheet/-/spritesheet-6.2.2.tgz", + "integrity": "sha512-TZodC/pf+CW/8kZN+RPzObXWSPgYv1pp+foUnOHb7w8AyFnMljeqBPiUfLQaMzw91TI9AHLihoeeofqZ4wMpww==" + }, + "@pixi/text": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/@pixi/text/-/text-6.2.2.tgz", + "integrity": "sha512-Hi6MO/QhllZ4IWkr7MBzImzHB88XXKlF5E9xt1vUBhdZb3KsQD+cPx+bNCFWn6ZMWDmOloJekzRkkSl3KrfBSw==" + }, + "@pixi/text-bitmap": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/@pixi/text-bitmap/-/text-bitmap-6.2.2.tgz", + "integrity": "sha512-pJZM0o68n6cUFUdolvpuuloMccdQqvTc3CLzhLu9xW9HLx7NeFjZEQWTGQea8GXsGa1RhvlMd9x3AiVSNMI2FA==" + }, + "@pixi/ticker": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/@pixi/ticker/-/ticker-6.2.2.tgz", + "integrity": "sha512-tF3cRtcYnj3U3HFQ0IJKvAxFU1YUM96T0p8Qh478xZhvGxYGnjrQDPmjXePb4NocAdG5adb6//2uvQOd7o4rHg==" + }, + "@pixi/utils": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/@pixi/utils/-/utils-6.2.2.tgz", + "integrity": "sha512-rpS6QolFuRmm/QcKm5PYHOCkX6okl9a00u2osaMbmPP+l7XLATTxSsFhw64UbSNR+zmzsrhreRFBVFn3tf8K6w==", + "requires": { + "@types/earcut": "^2.1.0", + "earcut": "^2.2.2", + "eventemitter3": "^3.1.0", + "url": "^0.11.0" + } + }, + "@types/earcut": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@types/earcut/-/earcut-2.1.1.tgz", + "integrity": "sha512-w8oigUCDjElRHRRrMvn/spybSMyX8MTkKA5Dv+tS1IE/TgmNZPqUYtvYBXGY8cieSE66gm+szeK+bnbxC2xHTQ==" + }, "@types/parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", @@ -667,6 +860,11 @@ "domhandler": "^4.2.0" } }, + "earcut": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/earcut/-/earcut-2.2.3.tgz", + "integrity": "sha512-iRDI1QeCQIhMCZk48DRDMVgQSSBDmbzzNhnxIo+pwx3swkfjMh6vh0nWLq1NdvGHLKH6wIrAM3vQWeTj6qeoug==" + }, "electron-to-chromium": { "version": "1.4.46", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.46.tgz", @@ -859,6 +1057,11 @@ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==" }, + "eventemitter3": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz", + "integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==" + }, "fast-glob": { "version": "3.2.11", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", @@ -1063,6 +1266,11 @@ "has-tostringtag": "^1.0.0" } }, + "ismobilejs": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ismobilejs/-/ismobilejs-1.1.1.tgz", + "integrity": "sha512-VaFW53yt8QO61k2WJui0dHf4SlL8lxBofUuUmwBo0ljPk0Drz2TiuDW4jo3wDcv41qy/SxrJ+VAzJ/qYqsmzRw==" + }, "js-stringify": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/js-stringify/-/js-stringify-1.0.2.tgz", @@ -1174,8 +1382,7 @@ "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" }, "object-hash": { "version": "2.2.0", @@ -1227,6 +1434,48 @@ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true }, + "pixi.js": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/pixi.js/-/pixi.js-6.2.2.tgz", + "integrity": "sha512-/xCnJUsWTZuacR6JYTnRbUb+5grzlqpp2O1Ub7bCZCE3FApTCs7nMNYeLfdeP+np/MlGaM+SsPh2cXcafR3OZw==", + "requires": { + "@pixi/accessibility": "6.2.2", + "@pixi/app": "6.2.2", + "@pixi/compressed-textures": "6.2.2", + "@pixi/constants": "6.2.2", + "@pixi/core": "6.2.2", + "@pixi/display": "6.2.2", + "@pixi/extract": "6.2.2", + "@pixi/filter-alpha": "6.2.2", + "@pixi/filter-blur": "6.2.2", + "@pixi/filter-color-matrix": "6.2.2", + "@pixi/filter-displacement": "6.2.2", + "@pixi/filter-fxaa": "6.2.2", + "@pixi/filter-noise": "6.2.2", + "@pixi/graphics": "6.2.2", + "@pixi/interaction": "6.2.2", + "@pixi/loaders": "6.2.2", + "@pixi/math": "6.2.2", + "@pixi/mesh": "6.2.2", + "@pixi/mesh-extras": "6.2.2", + "@pixi/mixin-cache-as-bitmap": "6.2.2", + "@pixi/mixin-get-child-by-name": "6.2.2", + "@pixi/mixin-get-global-position": "6.2.2", + "@pixi/particle-container": "6.2.2", + "@pixi/polyfill": "6.2.2", + "@pixi/prepare": "6.2.2", + "@pixi/runner": "6.2.2", + "@pixi/settings": "6.2.2", + "@pixi/sprite": "6.2.2", + "@pixi/sprite-animated": "6.2.2", + "@pixi/sprite-tiling": "6.2.2", + "@pixi/spritesheet": "6.2.2", + "@pixi/text": "6.2.2", + "@pixi/text-bitmap": "6.2.2", + "@pixi/ticker": "6.2.2", + "@pixi/utils": "6.2.2" + } + }, "postcss": { "version": "8.4.5", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.5.tgz", @@ -1290,6 +1539,11 @@ "asap": "~2.0.3" } }, + "promise-polyfill": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/promise-polyfill/-/promise-polyfill-8.2.1.tgz", + "integrity": "sha512-3p9zj0cEHbp7NVUxEYUWjQlffXqnXaZIMPkAO7HhFh8u5636xLRDHOUo2vpWSK0T2mqm6fKLXYn1KP6PAZ2gKg==" + }, "pug": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/pug/-/pug-3.0.2.tgz", @@ -1414,6 +1668,16 @@ "integrity": "sha512-yYELe9Q5q9IQhuvqsZNwA5hfPkMJ8u92bQLIMcsMxf/VADjNtEYptU+inlufAFYcWdHlwNfZOEnOOQrZrcyJCQ==", "dev": true }, + "punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" + }, + "querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=" + }, "queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -1582,6 +1846,15 @@ "integrity": "sha512-1uEe95xksV1O0CYKXo8vQvN1JEbtJp7lb7C5U9HMsIp6IVwntkH/oNUzyVNQSd4S1sYk2FpSSW44FqMc8qee5w==", "dev": true }, + "url": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", + "requires": { + "punycode": "1.3.2", + "querystring": "0.2.0" + } + }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", diff --git a/package.json b/package.json index 822c16f..68554cb 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "preview": "vite preview" }, "dependencies": { + "pixi.js": "^6.2.2", "vue": "^3.2.25" }, "devDependencies": { diff --git a/src/App.vue b/src/App.vue index 6d05827..8e265b7 100644 --- a/src/App.vue +++ b/src/App.vue @@ -7,19 +7,19 @@ import { useDatasBin, datasBin } from "./useDatasBin"; import { createTileMapImageData, createTileSheetImageData } from "./draw"; import MapCanvas from "./components/MapCanvas.vue"; import TilesheetPalette from "./components/TilesheetPalette.vue"; +import { Tile } from "./lib/renderer"; useDatasBin(datasBin); const fileInputRef = ref(); -const mapIndexRef = ref(11); +const mapIndexRef = ref(234); const paletteIndexRef = ref(0); const mapCount = ref>(); const tilesheetImageDataRef = ref(); const tileMapImageDataRef = ref(); const tileSheetCanvasScaleRef = ref(0); -const tileMapImageDatasRef = - ref }>>(); +const tileMapImageDatasRef = ref(); const palettesRef = computed(() => { if (!datasBin) { return []; @@ -187,11 +187,7 @@ function drawTileMap(gameMap: GameMap) { v-if="tilesheetImageDataRef" >
- +
diff --git a/src/components/MapCanvas.vue b/src/components/MapCanvas.vue index dc125e8..1efad55 100644 --- a/src/components/MapCanvas.vue +++ b/src/components/MapCanvas.vue @@ -1,65 +1,29 @@ diff --git a/src/draw.ts b/src/draw.ts index cc1a609..7953c6a 100644 --- a/src/draw.ts +++ b/src/draw.ts @@ -1,4 +1,5 @@ import { Argb32, GameMap } from "./lib/datas-bin"; +import { Tile, Renderer } from "./lib/renderer"; export function createTileSheetImageData( buffer: Uint8Array, @@ -60,7 +61,7 @@ export function createTileMapImageData( scrollMap: { v: number; h: number }, mapWidth: number, scale: number -): Array<{ dx: number; dy: number; data: Promise }> { +): Tile[] { tileCache.clear(); const map = gameMap.map; @@ -69,8 +70,7 @@ export function createTileMapImageData( return []; } - const tiles: Array<{ dx: number; dy: number; data: Promise }> = - []; + const tiles: Array = []; for (let y = 0; y < map.height; y++) { for (let x = 0; x < map.width / scale; x++) { @@ -80,30 +80,57 @@ export function createTileMapImageData( const dy = (y - tile.height) * scale * 16; if (tile.tileId !== -1) { - const tileImageData = new ImageData(24 * scale, 16 * scale); - drawTo(tileImageData, getTile(tile.tileId, gameMap), 0, 0); - tiles.push({ dx, dy, data: createImageBitmap(tileImageData) }); + // const tileImageData = new ImageData(24 * scale, 16 * scale); + // drawTo(tileImageData, getTile(tile.tileId, gameMap), 0, 0); + // tiles.push({ dx, dy, data: createImageBitmap(tileImageData) }); + Renderer.createTexture(`${tile.tileId & 0x3ff}`, { + buffer: getTile(tile.tileId, gameMap), + width: 24, + height: 16, + }); + tiles.push( + new Tile({ + textureId: `${tile.tileId & 0x3ff}`, + x: dx, + y: dy, + z: 1, + }) + ); } - if (tile.wallTiles) { - for (let index = 0; index < tile.wallTiles.count; index++) { - if (tile.wallTiles.tiles[index] !== -1) { - const wallTileImageData = new ImageData(24 * scale, 16 * scale); - drawTo( - wallTileImageData, - getTile(tile.wallTiles.tiles[index], gameMap), - 0, - 0, - true - ); - tiles.push({ - dx, - dy: dy + (index - tile.wallTiles.offset + 1) * 16 * scale, - data: createImageBitmap(wallTileImageData), - }); - } - } - } + // if (tile.wallTiles) { + // for (let index = 0; index < tile.wallTiles.count; index++) { + // if (tile.wallTiles.tiles[index] !== -1) { + // // const wallTileImageData = new ImageData(24 * scale, 16 * scale); + // // drawTo( + // // wallTileImageData, + // // getTile(tile.wallTiles.tiles[index], gameMap), + // // 0, + // // 0, + // // true + // // ); + // // tiles.push({ + // // dx, + // // dy: dy + (index - tile.wallTiles.offset + 1) * 16 * scale, + // // data: createImageBitmap(wallTileImageData), + // // }); + + // Renderer.createTexture(`${tile.tileId & 0x3ff}_wall`, { + // buffer: getTile(tile.wallTiles.tiles[index], gameMap), + // width: 24, + // height: 16, + // }); + // tiles.push( + // new Tile({ + // textureId: `${tile.tileId & 0x3ff}`, + // x: dx, + // y: dy + (index - tile.wallTiles.offset + 1) * 16, + // z: 1, + // }) + // ); + // } + // } + // } } } diff --git a/src/lib/app.ts b/src/lib/app.ts new file mode 100644 index 0000000..53a113d --- /dev/null +++ b/src/lib/app.ts @@ -0,0 +1,29 @@ +import { DatasBin, GameMap } from "./datas-bin"; +import { NaiveBinaryReader } from "./naive-binary-reader"; + +export class App { + private readonly gameMaps: GameMap[]; + + constructor(private readonly arrayBuffer: ArrayBuffer) { + const datasBin = new DatasBin(NaiveBinaryReader); + datasBin.fromFile(arrayBuffer); + + this.gameMaps = datasBin.gameMaps!.map((gameMap, index) => + Object.assign(gameMap, { id: `map_${index}`, title: "" }) + ); + } + + private loadGameMap(gameMap: GameMap) { + gameMap.load(new NaiveBinaryReader(this.arrayBuffer), true); + } + + getGameMap(index: number) { + const gameMap = this.gameMaps[index]; + + if (!gameMap.loaded) { + this.loadGameMap(gameMap); + } + + return gameMap; + } +} diff --git a/src/lib/datas-bin.ts b/src/lib/datas-bin.ts index caae57e..9413741 100644 --- a/src/lib/datas-bin.ts +++ b/src/lib/datas-bin.ts @@ -58,7 +58,7 @@ export function fromPsxColor(c: number) { const b = (c & 0x1f) << 3; const a = c != 0 ? 255 : 0; - return new Argb32(b, g, r, a); + return new Argb32(g, r, a, b); } function deflate(data: Uint8Array, dest: Uint8Array) { @@ -186,7 +186,8 @@ export class GameMap { private memoryAddress: number = 0x153460; // + 0x260; public tilesheetImageData: Uint8Array | null = null; public tilesheetBitmap: any; - public map: AMap | null = null; + public map: TileMap | null = null; + public loaded: boolean = false; private tileCache: Map = new Map(); constructor(binaryReader: NaiveBinaryReader, dbHeader: DBHeader); @@ -224,7 +225,7 @@ export class GameMap { //map if (this.header.mapBlock != -1) { binaryReader.jumpPosition(this.binOffset + this.header.mapBlock); - this.map = new AMap( + this.map = new TileMap( binaryReader, this.memoryAddress + this.header.mapBlock ); @@ -244,6 +245,8 @@ export class GameMap { this.tilesheetImageData = createUInt8ArrayFrom((256 * 256 * 6) / 2); deflate(buffer, this.tilesheetImageData); } + + this.loaded = true; } public generateTileBitmap(tile: number, palette: Argb32[]) { @@ -306,7 +309,7 @@ export class GameMap { } } -class AMap { +class TileMap { private memoryAddress: number; public readonly width: number; public readonly height: number; diff --git a/src/lib/renderer.ts b/src/lib/renderer.ts new file mode 100644 index 0000000..e4a3b15 --- /dev/null +++ b/src/lib/renderer.ts @@ -0,0 +1,168 @@ +import * as PIXI from "pixi.js"; + +export type Engine = typeof PIXI; +export type EngineApplication = PIXI.Application; +export type Container = PIXI.Container; +export type Texture = PIXI.Texture; +export type Sprite = PIXI.Sprite; + +export class Renderer { + static readonly engine: Engine = PIXI; + readonly instance: EngineApplication; + + constructor( + options: { + targetSelector: string; + width?: number; + height?: number; + } = { targetSelector: "#target" } + ) { + Renderer.engine.settings.SCALE_MODE = Renderer.engine.SCALE_MODES.NEAREST; + Renderer.engine.settings.ROUND_PIXELS = true; + + this.instance = new Renderer.engine.Application({ + width: options.width ?? 200, + height: options.height ?? 200, + }); + + const targetHTMLElement = document.querySelector(options.targetSelector); + + if (!targetHTMLElement) { + throw new Error("No target element available."); + } + + targetHTMLElement.appendChild(this.instance.view); + } + + static readonly registered = new WeakMap(); + + static register(renderable: Renderable) { + Renderer.registered.set(renderable, (delta: number) => + renderable.update(delta, Date.now()) + ); + Renderer.engine.Ticker.shared.add(Renderer.registered.get(renderable)); + + return renderable; + } + + static unregister(renderable: Renderable) { + Renderer.engine.Ticker.shared.remove(Renderer.registered.get(renderable)); + Renderer.registered.delete(renderable); + + return renderable; + } + + static readonly textureCache = new Map(); + + static createTexture( + id: string, + options: { + buffer: Uint8Array; + width: number; + height: number; + } + ) { + if (!this.textureCache.get(id)) { + this.textureCache.set( + id, + this.engine.Texture.fromBuffer( + options.buffer, + options.width, + options.height + ) + ); + } + + return this.textureCache.get(id); + } + + static createContainer( + options: { + x?: number; + y?: number; + z?: number; + visible?: boolean; + } = {} + ) { + const container = new this.engine.Container(); + container.position.set(options.x ?? 0, options.y ?? 0); + container.zIndex = options.z ?? 1; + container.visible = options.visible ?? true; + + return container; + } + + static createSprite( + textureId: string, + options: { x?: number; y?: number; z?: number } = {} + ) { + const sprite = new Renderer.engine.Sprite( + this.textureCache.get(textureId) ?? Renderer.engine.Texture.EMPTY + ); + + sprite.position.set(options.x ?? 0, options.y ?? 0); + + return sprite; + } +} + +class Renderable { + readonly container: Container; + protected destroyed = false; + + constructor( + private readonly id: string = "", + options: { x?: number; y?: number; z?: number; visible?: boolean } = {} + ) { + this.container = Renderer.createContainer(options); + + Renderer.register(this); + } + + destructor() { + Renderer.unregister(this); + this.container.parent?.removeChild(this.container); + this.container.destroy({ children: true }); + this.destroyed = true; + } + + init(parent: Renderable | EngineApplication) { + if ("stage" in parent) { + // EngineApplication + parent.stage.addChild(this.container); + } else { + // Renderable + parent.container.addChild(this.container); + } + } + + update(delta: number, time: number) { + if (this.destroyed) { + return; + } + } +} + +export class Tile extends Renderable { + constructor(options: { + textureId: string; + x: number; + y: number; + z?: number; + }) { + super(); + this.container.addChild(Renderer.createSprite(options.textureId)); + + this.container.position.set(options.x, options.y); + this.container.zIndex = options.z ?? 1; + } +} + +export class TileMap extends Renderable { + constructor(tiles: Tile[]) { + super(); + tiles.forEach((tile) => { + this.container.addChild(tile.container); + }); + } +} From 8df7a5b74397bad80671792e0484ebfe64fdbded Mon Sep 17 00:00:00 2001 From: Joonas Yliaho Date: Fri, 28 Jan 2022 16:21:34 +0200 Subject: [PATCH 2/5] fix wall tiles not rendering --- src/draw.ts | 56 +++++++++++++++++++-------------------------- src/lib/renderer.ts | 7 ++++-- 2 files changed, 28 insertions(+), 35 deletions(-) diff --git a/src/draw.ts b/src/draw.ts index 7953c6a..2c5ad2c 100644 --- a/src/draw.ts +++ b/src/draw.ts @@ -72,6 +72,8 @@ export function createTileMapImageData( const tiles: Array = []; + console.time("tiles drawn"); + for (let y = 0; y < map.height; y++) { for (let x = 0; x < map.width / scale; x++) { const tile = map.mapTiles[y * map.width + x]; @@ -98,42 +100,30 @@ export function createTileMapImageData( ); } - // if (tile.wallTiles) { - // for (let index = 0; index < tile.wallTiles.count; index++) { - // if (tile.wallTiles.tiles[index] !== -1) { - // // const wallTileImageData = new ImageData(24 * scale, 16 * scale); - // // drawTo( - // // wallTileImageData, - // // getTile(tile.wallTiles.tiles[index], gameMap), - // // 0, - // // 0, - // // true - // // ); - // // tiles.push({ - // // dx, - // // dy: dy + (index - tile.wallTiles.offset + 1) * 16 * scale, - // // data: createImageBitmap(wallTileImageData), - // // }); - - // Renderer.createTexture(`${tile.tileId & 0x3ff}_wall`, { - // buffer: getTile(tile.wallTiles.tiles[index], gameMap), - // width: 24, - // height: 16, - // }); - // tiles.push( - // new Tile({ - // textureId: `${tile.tileId & 0x3ff}`, - // x: dx, - // y: dy + (index - tile.wallTiles.offset + 1) * 16, - // z: 1, - // }) - // ); - // } - // } - // } + if (tile.wallTiles) { + for (let index = 0; index < tile.wallTiles.count; index++) { + if (tile.wallTiles.tiles[index] !== -1) { + Renderer.createTexture(`${tile.wallTiles.tiles[index] & 0x3ff}`, { + buffer: getTile(tile.wallTiles.tiles[index], gameMap), + width: 24, + height: 16, + }); + tiles.push( + new Tile({ + textureId: `${tile.wallTiles.tiles[index] & 0x3ff}`, + x: dx, + y: dy + (index - tile.wallTiles.offset + 1) * 16, + z: 1, + }) + ); + } + } + } } } + console.timeEnd("tiles drawn"); + return tiles; } diff --git a/src/lib/renderer.ts b/src/lib/renderer.ts index e4a3b15..55af05f 100644 --- a/src/lib/renderer.ts +++ b/src/lib/renderer.ts @@ -62,7 +62,8 @@ export class Renderer { height: number; } ) { - if (!this.textureCache.get(id)) { + const cacheHit = this.textureCache.get(id); + if (!cacheHit) { this.textureCache.set( id, this.engine.Texture.fromBuffer( @@ -73,7 +74,8 @@ export class Renderer { ); } - return this.textureCache.get(id); + const texture = this.textureCache.get(id)!; + return texture; } static createContainer( @@ -150,6 +152,7 @@ export class Tile extends Renderable { y: number; z?: number; }) { + const timeId = `${Date.now()}`; super(); this.container.addChild(Renderer.createSprite(options.textureId)); From 73c8f7e00e278ff3bef13367c95c035c43347e2d Mon Sep 17 00:00:00 2001 From: Joonas Yliaho Date: Fri, 28 Jan 2022 17:28:46 +0200 Subject: [PATCH 3/5] sort zIndex for tiles by their height and other properties --- src/draw.ts | 8 ++------ src/lib/renderer.ts | 1 + 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/draw.ts b/src/draw.ts index 2c5ad2c..547ce8f 100644 --- a/src/draw.ts +++ b/src/draw.ts @@ -72,8 +72,6 @@ export function createTileMapImageData( const tiles: Array = []; - console.time("tiles drawn"); - for (let y = 0; y < map.height; y++) { for (let x = 0; x < map.width / scale; x++) { const tile = map.mapTiles[y * map.width + x]; @@ -95,7 +93,7 @@ export function createTileMapImageData( textureId: `${tile.tileId & 0x3ff}`, x: dx, y: dy, - z: 1, + z: (y - tile.height) * scale * 16, }) ); } @@ -113,7 +111,7 @@ export function createTileMapImageData( textureId: `${tile.wallTiles.tiles[index] & 0x3ff}`, x: dx, y: dy + (index - tile.wallTiles.offset + 1) * 16, - z: 1, + z: dy + (index - tile.wallTiles.offset + 1) * 16, }) ); } @@ -122,8 +120,6 @@ export function createTileMapImageData( } } - console.timeEnd("tiles drawn"); - return tiles; } diff --git a/src/lib/renderer.ts b/src/lib/renderer.ts index 55af05f..44c6a1d 100644 --- a/src/lib/renderer.ts +++ b/src/lib/renderer.ts @@ -164,6 +164,7 @@ export class Tile extends Renderable { export class TileMap extends Renderable { constructor(tiles: Tile[]) { super(); + this.container.sortableChildren = true; tiles.forEach((tile) => { this.container.addChild(tile.container); }); From 58060e07d4740ba114f36b741b47e449301c1bd9 Mon Sep 17 00:00:00 2001 From: Joonas Yliaho Date: Fri, 28 Jan 2022 17:29:17 +0200 Subject: [PATCH 4/5] cache tilemap as bitmap in hopes to increase performance --- src/lib/renderer.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/lib/renderer.ts b/src/lib/renderer.ts index 44c6a1d..a701530 100644 --- a/src/lib/renderer.ts +++ b/src/lib/renderer.ts @@ -168,5 +168,7 @@ export class TileMap extends Renderable { tiles.forEach((tile) => { this.container.addChild(tile.container); }); + + this.container.cacheAsBitmap = true; } } From d55dcf14a4c7ab107839b24525b41c599c9bdac2 Mon Sep 17 00:00:00 2001 From: Joonas Yliaho Date: Fri, 28 Jan 2022 17:29:47 +0200 Subject: [PATCH 5/5] increase tilemap render performance by not registering `Drawable` base class --- src/lib/renderer.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/lib/renderer.ts b/src/lib/renderer.ts index a701530..be7c4f1 100644 --- a/src/lib/renderer.ts +++ b/src/lib/renderer.ts @@ -117,8 +117,6 @@ class Renderable { options: { x?: number; y?: number; z?: number; visible?: boolean } = {} ) { this.container = Renderer.createContainer(options); - - Renderer.register(this); } destructor() { @@ -152,7 +150,6 @@ export class Tile extends Renderable { y: number; z?: number; }) { - const timeId = `${Date.now()}`; super(); this.container.addChild(Renderer.createSprite(options.textureId));