A compatibility update.
No, this isn't a late 'Fool's joke, I was just having fun and now I can target pure ES6/ES2015 if I wanted to. …except Chakra ('Edge <= 44), that thing never implemented `TextDecoder`/`TextEncoder` for some reason. We'll never know why... I'm researching what makes over-bright happen... give me time!
This commit is contained in:
parent
5738fbb09c
commit
98edefff2e
52
README.md
52
README.md
|
@ -1,7 +1,20 @@
|
|||
# icondumper2 (working title)
|
||||
A JavaScript library (sorta) to read PS2 icons, and their related formats.
|
||||
|
||||
## What it supports
|
||||
## What is a "PS2 icon"?
|
||||
A set of vertices with may or may not include a texture while defining colours for those vertices.
|
||||
|
||||
## Why?
|
||||
Current implementations had some issues with rendering some icons. These were mostly:
|
||||
* Not rendering any color for texture type 3.
|
||||
* Failing to decompress some specific RLE-compressed icons. (types above 8)
|
||||
* Requires writing/reading a specific format for successful output of data.
|
||||
|
||||
As of writing, there was no exporter that exists for the format that exhibited one of these problems.
|
||||
|
||||
**icondumper2** is the result of me trying to avoid these problems.
|
||||
|
||||
## What it supports:
|
||||
* EMS Memory Adapter export files (.psu)
|
||||
* PS3 virtual memory card export files (.psv)
|
||||
* SharkPort export files (.sps)
|
||||
|
@ -9,30 +22,41 @@ A JavaScript library (sorta) to read PS2 icons, and their related formats.
|
|||
* PS2 icons (.ico, .icn)
|
||||
* PS2D format (icon.sys)
|
||||
|
||||
## What can it do
|
||||
* Allow any file in a PSU's or SPS/XPS's virtual filesystem to be dumped.
|
||||
## What can it do:
|
||||
* Allow any file in a supported virtual filesystem (such as those from export files) to be read.
|
||||
* Warn of invalid icon.sys display names.
|
||||
* Read and parse an EMS MA export file.
|
||||
* Export the icon model, with all seperate shapes included to a JavaScript Object.
|
||||
* Node.js compatible (CommonJS) exporting while still being compatible with other JavaScript implementations.
|
||||
* Convert a 128x128x16 BGR5A1 bitmap to a RGB5A1 format.
|
||||
* Export the icon model, with all seperate shapes included as a JavaScript Object.
|
||||
* CommonJS (that includes node!) module exporting while still being compatible with other JavaScript implementations.
|
||||
* Convert a 128x128x16 BGR5A1 bitmap to a standard RGB5A1 format.
|
||||
* Convert an icon or a set of icons to glTF 2, with textures saved as PNG.
|
||||
|
||||
## What it doesn't do
|
||||
* (Re)build save files.
|
||||
* Modify the original input files.
|
||||
* Use any Node.js-exclusive features.
|
||||
## What it doesn't do:
|
||||
* Create, manipulate or otherwise taint save files.
|
||||
* Modify any original input files.
|
||||
* Use any implementation-specific features.
|
||||
|
||||
## Client compatibility
|
||||
(todo: write this)
|
||||
## Client compatibility:
|
||||
The library requires use of `const`, `let` and `class` declarations.
|
||||
|
||||
Any JavaScript implementation should work if they support all three of these declarations.
|
||||
|
||||
### Tested clients:
|
||||
* Chrome (or Blink-based browser) 49 (or higher) - HTML reference client
|
||||
* Firefox (or Gecko-based browser) 45 (or higher) - HTML reference client
|
||||
* Node.js 13 (or higher) - Example client and glTF 2 exporter.
|
||||
|
||||
## Why "icondumper2"?
|
||||
Because it replaced what *was* left of icondumper (1).
|
||||
|
||||
## Included files
|
||||
## Included files:
|
||||
| File | Description |
|
||||
| ---------------- | ----------------------------------------- |
|
||||
| icon.js | The library itself. |
|
||||
| index.js | Node.js example client. |
|
||||
| gltf-exporter.js | Node.js client to export icons to glTF 2. |
|
||||
| index.htm | HTML reference client. |
|
||||
|
||||
## Included example files:
|
||||
| Directory | Description | Formats |
|
||||
| ------------ | ----------------------------------------- | -------- |
|
||||
| /example_001 | A tetrahedron with all 3 base colors set. | PSU, SPS |
|
|
@ -249,7 +249,7 @@ function loadAndConvertIcon(inputData, attemptedFilename = "-") {
|
|||
if (inputData.hasOwnProperty("numberOfShapes") === false) {
|
||||
throw "Expected a icondumper2 Intermediate Model Format object.";
|
||||
}
|
||||
const filename = encodeURIComponent(attemptedFilename).replaceAll(/\%[0-9A-F]{2,2}/g, "").replaceAll(".", "_");
|
||||
const filename = encodeURIComponent(attemptedFilename).replace(/\%[0-9A-F]{2,2}/g, "").replace(/\./g, "_");
|
||||
const glTF_output = imf2gltf(inputData, filename);
|
||||
for (let index = 0; index < (inputData.numberOfShapes); index++) {
|
||||
(require("fs")).writeFileSync(`${filename}_${index}.gltf`, new TextEncoder().encode(JSON.stringify(glTF_output.objects[index])));
|
||||
|
|
30
icon.js
30
icon.js
|
@ -1,21 +1,22 @@
|
|||
//todo: Make this a module/mjs file. C6 compatibility can stay, if needed.
|
||||
//LOOKING FOR: LZARI implementation (for MAX), description of CBS compression (node zlib doesn't tackle it, even with RC4'ing the data)
|
||||
ICONJS_DEBUG = false;
|
||||
ICONJS_STRICT = true;
|
||||
var ICONJS_DEBUG = false;
|
||||
var ICONJS_STRICT = true;
|
||||
|
||||
/**
|
||||
* The current version of the library.
|
||||
* @constant {string}
|
||||
* @default
|
||||
*/
|
||||
const ICONJS_VERSION = "0.6.1";
|
||||
const ICONJS_VERSION = "0.6.1+u1";
|
||||
|
||||
/**
|
||||
* Extension of DataView to add shortcuts for datatypes that I use often.
|
||||
* @augments DataView
|
||||
* @constructor
|
||||
* @param {ArrayBuffer} buffer ArrayBuffer to base DataView from.
|
||||
* @returns {Object.<string, function(number): number>}
|
||||
* @returns {Object.<string, function(number): number>} [u16le, f16le, u32le, f32le]
|
||||
* @returns {Object.<string, function(number): Object.<string.number>>} [t64le]
|
||||
* @access protected
|
||||
*/
|
||||
class yellowDataReader extends DataView {
|
||||
|
@ -40,9 +41,16 @@ class yellowDataReader extends DataView {
|
|||
*/
|
||||
f32le(i){return super.getFloat32(i, 1)};
|
||||
/** 64-bit Timestamp structure, Little Endian.
|
||||
* Time returned is set for JST (UTC+09:00) instead of UTC.
|
||||
* Time returned is going to be offseted for JST (GMT+09:00).
|
||||
* @param {number} i Indice offset.
|
||||
* @returns {Object.<string, number>}
|
||||
* @property {number} seconds - Seconds.
|
||||
* @property {number} minutes - Minutes.
|
||||
* @property {number} hours - Hours.
|
||||
* @property {number} day - Day.
|
||||
* @property {number} month - Month.
|
||||
* @property {number} year - Year.
|
||||
*/
|
||||
t64le(i){return {
|
||||
seconds: super.getUint8(i+1),
|
||||
|
@ -78,7 +86,7 @@ function setDebug(value) {
|
|||
* Select if invalid characters in titles should be replaced with either spaces or nulls
|
||||
* @param {boolean} value - true: with nulls, false: with spaces
|
||||
* @default true
|
||||
* @deprecated unlikely to ever need this?
|
||||
* @deprecated Hasn't been needed for a while. Dropping support by ESM transition.
|
||||
* @public
|
||||
*/
|
||||
function setStrictness(value) {
|
||||
|
@ -182,7 +190,7 @@ function convertBGR5A1toRGB5A1(bgrData) {
|
|||
* @access protected
|
||||
*/
|
||||
function stringScrubber(dirty) {
|
||||
return dirty.replaceAll("\x00","").substring(0, (dirty.indexOf("\x00") === -1) ? dirty.length : dirty.indexOf("\x00"));
|
||||
return dirty.replace(/\0/g, "").substring(0, (dirty.indexOf("\x00") === -1) ? dirty.length : dirty.indexOf("\x00"));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -627,9 +635,9 @@ function readSharkXPortSxpsFile(input) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Define (module.)exports with all public functions
|
||||
* Define (module.)exports with all public functions.
|
||||
* @exports icondumper2/icon
|
||||
*/
|
||||
*/ // start c6js
|
||||
exports = {
|
||||
readers: {readIconFile, readPS2D, readEmsPsuFile, readPsvFile, readSharkXPortSxpsFile},
|
||||
helpers: {uncompressTexture, convertBGR5A1toRGB5A1},
|
||||
|
@ -640,3 +648,9 @@ exports = {
|
|||
if(typeof module !== "undefined") {
|
||||
module.exports = exports;
|
||||
}
|
||||
//end c6js
|
||||
//start esm
|
||||
/*export {
|
||||
readIconFile, readPS2D, readEmsPsuFile, readPsvFile, readSharkXPortSxpsFile, uncompressTexture, convertBGR5A1toRGB5A1, setDebug, ICONJS_VERSION
|
||||
};*/
|
||||
//end esm
|
98
index.htm
98
index.htm
|
@ -20,6 +20,13 @@
|
|||
input[type="file"] {line-height: 2em;}
|
||||
#version {text-shadow: 1px 1px 2px black;}
|
||||
a {color: #ccc;}
|
||||
.inputbox {
|
||||
display: inline-grid;
|
||||
margin-right: 0.25em;
|
||||
border: 1px gray solid;
|
||||
padding: 0.175em 0.25em 0 0.25em;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
</style>
|
||||
<meta data-comment="WebGL Shader: Icon">
|
||||
<script type="text/plain" id="shader-icon-v">
|
||||
|
@ -133,15 +140,18 @@
|
|||
<br>
|
||||
</div>
|
||||
<hr>
|
||||
<label for="psuinput">EMS Memory Adapter export file (.psu) goes here:</label>
|
||||
<input type="file" id="psuinput" name="psuinput" accept=".psu" />
|
||||
<br>
|
||||
<label for="psvinput">PS3 export file (.psv) goes here:</label>
|
||||
<input type="file" id="psvinput" name="psvinput" accept=".psv" />
|
||||
<br>
|
||||
<label for="spsinput">SharkPort/X-Port export file (.sps, .xps) goes here:</label>
|
||||
<input type="file" id="spsinput" name="spsinput" accept=".sps, .xps" />
|
||||
<br>
|
||||
<div class="inputbox">
|
||||
<label for="psuinput">EMS Memory Adapter export file (.psu) goes here:</label>
|
||||
<input type="file" id="psuinput" name="psuinput" accept=".psu" />
|
||||
</div>
|
||||
<div class="inputbox">
|
||||
<label for="psvinput">PS3 export file (.psv) goes here:</label>
|
||||
<input type="file" id="psvinput" name="psvinput" accept=".psv" />
|
||||
</div>
|
||||
<div class="inputbox">
|
||||
<label for="spsinput">SharkPort/X-Port export file (.sps, .xps) goes here:</label>
|
||||
<input type="file" id="spsinput" name="spsinput" accept=".sps, .xps" />
|
||||
</div>
|
||||
<p>
|
||||
<span>Date created: </span><span id="dateCreated">--:--:-- --/--/----</span><span> UTC+09:00</span>
|
||||
<wbr><span>–</span>
|
||||
|
@ -152,16 +162,19 @@
|
|||
</p>
|
||||
<script>
|
||||
// I usually don't do in-body <script>'s, but I didn't want to do an await onload() again
|
||||
const GlobalState = {rotations: 2, dataLength: 0, uniforms: {rotation: null, scale: null}, iconState: {source: null, currentIcon: null, currentSubmodel: 0, cachedIconSys: null}};
|
||||
const GlobalState = {rotations: 2, dataLength: 0, uniforms: {rotation: null, scale: null}, iconState: {source: null, currentIcon: null, currentSubmodel: 0, cachedIconSys: null}, fileReader: (new FileReader)};
|
||||
// I don't care HOW disgusting doing this is, I'm sick of pressing escape to clear these.
|
||||
let allInputs = document.querySelectorAll('input[type="file"]');
|
||||
allInputs.forEach(
|
||||
Array.from(allInputs).forEach(
|
||||
function(nodeObject) {
|
||||
nodeObject.onclick = function() {
|
||||
allInputs.forEach(function(elementObject) {elementObject.value = null;});
|
||||
Array.from(allInputs).forEach(function(elementObject) {elementObject.value = null;});
|
||||
}
|
||||
}
|
||||
);
|
||||
function p0in(input) { // "prefix 0 if needed"
|
||||
return ((input.length>=2) ? input : `0${input}`);
|
||||
};
|
||||
// rotation stuff
|
||||
const rotationDensity = 60;
|
||||
document.body.onkeydown = function(ev) {
|
||||
|
@ -394,7 +407,7 @@
|
|||
//.section LIGHTING
|
||||
let colours = fileMetadata.lighting.colors[0];
|
||||
//glFgContext.uniform3f(uniforms.ambientLighting, colours.r, colours.g, colours.b);
|
||||
glFgContext.uniform3f(uniforms.ambientLighting, 1, 1, 1);
|
||||
glFgContext.uniform3f(uniforms.ambientLighting, 0.75, 0.75, 0.75);
|
||||
|
||||
//.section SCALING
|
||||
GlobalState.uniforms.scale = uniforms.scale;
|
||||
|
@ -421,25 +434,30 @@
|
|||
if(filebox.files.length === 0) {
|
||||
return;
|
||||
}
|
||||
filebox.files[0].arrayBuffer().then(function(d){
|
||||
GlobalState.fileReader.readAsArrayBuffer(filebox.files[0]);
|
||||
GlobalState.fileReader.onloadend = function() {
|
||||
GlobalState.fileReader.onloadend = void(0);
|
||||
try {
|
||||
let output = readPS2D(d);
|
||||
let output = readPS2D(GlobalState.fileReader.result);
|
||||
console.info("icon.sys", output);
|
||||
updateDisplay(output);
|
||||
} catch(e) {
|
||||
if(glBgContext!==null){glBgContext.clear(glBgContext.COLOR_BUFFER_BIT);}
|
||||
console.error(e);
|
||||
alert(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
iconbox = document.getElementById("icon");
|
||||
iconbox.onchange = function(e) {
|
||||
if(iconbox.files.length === 0) {
|
||||
return;
|
||||
}
|
||||
iconbox.files[0].arrayBuffer().then(function(d){
|
||||
GlobalState.fileReader.readAsArrayBuffer(iconbox.files[0]);
|
||||
GlobalState.fileReader.onloadend = function() {
|
||||
GlobalState.fileReader.onloadend = void(0);
|
||||
try {
|
||||
let output = readIconFile(d);
|
||||
let output = readIconFile(GlobalState.fileReader.result);
|
||||
GlobalState.iconState.cachedIconSys = null;
|
||||
GlobalState.iconState.source = null;
|
||||
GlobalState.iconState.currentSubmodel = 0;
|
||||
|
@ -448,9 +466,10 @@
|
|||
console.info("model data (ic*)",output);
|
||||
} catch(e) {
|
||||
if(glFgContext!==null){glFgContext.clear(glFgContext.COLOR_BUFFER_BIT | glFgContext.DEPTH_BUFFER_BIT);}
|
||||
console.error(e);
|
||||
alert(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
psubox = document.getElementById("psuinput");
|
||||
psubox.onchange = function(e) {
|
||||
|
@ -458,9 +477,11 @@
|
|||
if(psubox.files.length === 0) {
|
||||
return;
|
||||
}
|
||||
psubox.files[0].arrayBuffer().then(function(d){
|
||||
GlobalState.fileReader.readAsArrayBuffer(psubox.files[0]);
|
||||
GlobalState.fileReader.onloadend = function() {
|
||||
GlobalState.fileReader.onloadend = void(0);
|
||||
try {
|
||||
let vFilesystem = readEmsPsuFile(d);
|
||||
let vFilesystem = readEmsPsuFile(GlobalState.fileReader.result);
|
||||
let output = readPS2D(vFilesystem[vFilesystem.rootDirectory]["icon.sys"].data);
|
||||
updateDisplay(output);
|
||||
let output2 = new Object();
|
||||
|
@ -475,16 +496,17 @@
|
|||
let cTime = vFilesystem.timestamps.created;
|
||||
let mTime = vFilesystem.timestamps.modified;
|
||||
//TODO: use Time() to align JST times to user-local timezone
|
||||
document.getElementById("dateCreated").textContent = `${cTime.hours.toString().padStart("2","0")}:${cTime.minutes.toString().padStart("2","0")}:${cTime.seconds.toString().padStart("2","0")} ${cTime.day.toString().padStart("2","0")}/${cTime.month.toString().padStart("2","0")}/${cTime.year}`;
|
||||
document.getElementById("dateModified").textContent = `${mTime.hours.toString().padStart("2","0")}:${mTime.minutes.toString().padStart("2","0")}:${mTime.seconds.toString().padStart("2","0")} ${mTime.day.toString().padStart("2","0")}/${mTime.month.toString().padStart("2","0")}/${mTime.year}`;
|
||||
document.getElementById("dateCreated").textContent = `${p0in(cTime.hours.toString())}:${p0in(cTime.minutes.toString())}:${p0in(cTime.seconds.toString())} ${p0in(cTime.day.toString())}/${p0in(cTime.month.toString())}/${cTime.year}`;
|
||||
document.getElementById("dateModified").textContent = `${p0in(mTime.hours.toString())}:${p0in(mTime.minutes.toString())}:${p0in(mTime.seconds.toString())} ${p0in(mTime.day.toString())}/${p0in(mTime.month.toString())}/${mTime.year}`;
|
||||
console.info("model files (psu)", output2);
|
||||
console.info("icon.sys (psu)", output);
|
||||
} catch(e) {
|
||||
if(glBgContext!==null){glBgContext.clear(glBgContext.COLOR_BUFFER_BIT);}
|
||||
if(glFgContext!==null){glFgContext.clear(glFgContext.COLOR_BUFFER_BIT | glFgContext.DEPTH_BUFFER_BIT);}
|
||||
console.error(e);
|
||||
alert(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
psvbox = document.getElementById("psvinput");
|
||||
psvbox.onchange = function(e) {
|
||||
|
@ -492,9 +514,11 @@
|
|||
if(psvbox.files.length === 0) {
|
||||
return;
|
||||
}
|
||||
psvbox.files[0].arrayBuffer().then(function(d){
|
||||
GlobalState.fileReader.readAsArrayBuffer(psvbox.files[0]);
|
||||
GlobalState.fileReader.onloadend = function() {
|
||||
GlobalState.fileReader.onloadend = void(0);
|
||||
try {
|
||||
let inputData = readPsvFile(d);
|
||||
let inputData = readPsvFile(GlobalState.fileReader.result);
|
||||
let output = readPS2D(inputData["icon.sys"]);
|
||||
updateDisplay(output);
|
||||
const icons = {
|
||||
|
@ -510,16 +534,17 @@
|
|||
let cTime = inputData.timestamps.created;
|
||||
let mTime = inputData.timestamps.modified;
|
||||
//TODO: use Time() to align JST times to user-local timezone
|
||||
document.getElementById("dateCreated").textContent = `${cTime.hours.toString().padStart("2","0")}:${cTime.minutes.toString().padStart("2","0")}:${cTime.seconds.toString().padStart("2","0")} ${cTime.day.toString().padStart("2","0")}/${cTime.month.toString().padStart("2","0")}/${cTime.year}`;
|
||||
document.getElementById("dateModified").textContent = `${mTime.hours.toString().padStart("2","0")}:${mTime.minutes.toString().padStart("2","0")}:${mTime.seconds.toString().padStart("2","0")} ${mTime.day.toString().padStart("2","0")}/${mTime.month.toString().padStart("2","0")}/${mTime.year}`;
|
||||
document.getElementById("dateCreated").textContent = `${p0in(cTime.hours.toString())}:${p0in(cTime.minutes.toString())}:${p0in(cTime.seconds.toString())} ${p0in(cTime.day.toString())}/${p0in(cTime.month.toString())}/${cTime.year}`;
|
||||
document.getElementById("dateModified").textContent = `${p0in(mTime.hours.toString())}:${p0in(mTime.minutes.toString())}:${p0in(mTime.seconds.toString())} ${p0in(mTime.day.toString())}/${p0in(mTime.month.toString())}/${mTime.year}`;
|
||||
console.info("model files (psv)", icons);
|
||||
console.info("icon.sys (psv)", output);
|
||||
} catch(e) {
|
||||
if(glBgContext!==null){glBgContext.clear(glBgContext.COLOR_BUFFER_BIT);}
|
||||
if(glFgContext!==null){glFgContext.clear(glFgContext.COLOR_BUFFER_BIT | glFgContext.DEPTH_BUFFER_BIT);}
|
||||
console.error(e);
|
||||
alert(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
spsbox = document.getElementById("spsinput");
|
||||
spsbox.onchange = function(e) {
|
||||
|
@ -527,9 +552,11 @@
|
|||
if(spsbox.files.length === 0) {
|
||||
return;
|
||||
}
|
||||
spsbox.files[0].arrayBuffer().then(function(d){
|
||||
GlobalState.fileReader.readAsArrayBuffer(spsbox.files[0]);
|
||||
GlobalState.fileReader.onloadend = function() {
|
||||
GlobalState.fileReader.onloadend = void(0);
|
||||
try {
|
||||
let vFilesystem = readSharkXPortSxpsFile(d);
|
||||
let vFilesystem = readSharkXPortSxpsFile(GlobalState.fileReader.result);
|
||||
let output = readPS2D(vFilesystem[vFilesystem.rootDirectory]["icon.sys"].data);
|
||||
updateDisplay(output);
|
||||
let output2 = new Object();
|
||||
|
@ -544,8 +571,8 @@
|
|||
let cTime = vFilesystem.timestamps.created;
|
||||
let mTime = vFilesystem.timestamps.modified;
|
||||
//TODO: use Time() to align JST times to user-local timezone
|
||||
document.getElementById("dateCreated").textContent = `${cTime.hours.toString().padStart("2","0")}:${cTime.minutes.toString().padStart("2","0")}:${cTime.seconds.toString().padStart("2","0")} ${cTime.day.toString().padStart("2","0")}/${cTime.month.toString().padStart("2","0")}/${cTime.year}`;
|
||||
document.getElementById("dateModified").textContent = `${mTime.hours.toString().padStart("2","0")}:${mTime.minutes.toString().padStart("2","0")}:${mTime.seconds.toString().padStart("2","0")} ${mTime.day.toString().padStart("2","0")}/${mTime.month.toString().padStart("2","0")}/${mTime.year}`;
|
||||
document.getElementById("dateCreated").textContent = `${p0in(cTime.hours.toString())}:${p0in(cTime.minutes.toString())}:${p0in(cTime.seconds.toString())} ${p0in(cTime.day.toString())}/${p0in(cTime.month.toString())}/${cTime.year}`;
|
||||
document.getElementById("dateModified").textContent = `${p0in(mTime.hours.toString())}:${p0in(mTime.minutes.toString())}:${p0in(mTime.seconds.toString())} ${p0in(mTime.day.toString())}/${p0in(mTime.month.toString())}/${mTime.year}`;
|
||||
document.getElementById("fileCommentGame").textContent = vFilesystem.comments.game;
|
||||
document.getElementById("fileCommentName").textContent = vFilesystem.comments.name;
|
||||
if(vFilesystem.comments.hasOwnProperty("desc")) {
|
||||
|
@ -556,9 +583,10 @@
|
|||
} catch(e) {
|
||||
if(glBgContext!==null){glBgContext.clear(glBgContext.COLOR_BUFFER_BIT);}
|
||||
if(glFgContext!==null){glFgContext.clear(glFgContext.COLOR_BUFFER_BIT | glFgContext.DEPTH_BUFFER_BIT);}
|
||||
console.error(e);
|
||||
alert(e);
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
function createShader(gl, type, source) {
|
||||
let shader = gl.createShader(type);
|
||||
|
@ -639,7 +667,7 @@
|
|||
<span id="version">icondumper2 <a href="./documentation" id="iconjsVersion">(unknown icon.js version)</a> [C: <span id="clientVersion">Loading...</span>] — © <span id="currentYear">2023</span> yellows111</span>
|
||||
<script>
|
||||
document.getElementById("iconjsVersion").textContent = exports.version;
|
||||
document.getElementById("clientVersion").textContent = "0.6.6";
|
||||
document.getElementById("clientVersion").textContent = "0.6.7";
|
||||
document.getElementById("currentYear").textContent = (new Date()).getFullYear().toString();
|
||||
</script>
|
||||
</body>
|
||||
|
|
Loading…
Reference in New Issue