parent
af1359ed5b
commit
4e27fcdc94
70
icon.js
70
icon.js
|
@ -1,7 +1,7 @@
|
||||||
//todo: Make this a module/mjs file. C6 compatibility can stay, if needed.
|
//todo: Make this a module/mjs file. C6 compatibility can stay, if needed.
|
||||||
ICONJS_DEBUG = false;
|
ICONJS_DEBUG = false;
|
||||||
ICONJS_STRICT = true;
|
ICONJS_STRICT = true;
|
||||||
ICONJS_VERSION = "0.3.5";
|
ICONJS_VERSION = "0.4.0";
|
||||||
|
|
||||||
function setDebug(value) {
|
function setDebug(value) {
|
||||||
ICONJS_DEBUG = !!value;
|
ICONJS_DEBUG = !!value;
|
||||||
|
@ -26,9 +26,60 @@ function getTextureFormat(i) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function BGR5A1(i) {
|
function uncompressTexture(texData) {
|
||||||
return {b: (i & 0b11111), g: ((i >> 5) & 0b11111), r: ((i >> 10) & 0b11111), a: (i >> 15)}
|
// for texture formats 8-14 (and maybe 15 but that's being weird)
|
||||||
// map this as *8 for each color and i+1*127 for alpha, GL-wise, float(i+1)
|
if (texData.length & 1) {
|
||||||
|
throw "Texture size isn't a multiple of 2 (was ${texData.length})";
|
||||||
|
}
|
||||||
|
const view = new DataView(texData);
|
||||||
|
const u16le = function(i){return view.getUint16(i, 1)}
|
||||||
|
let uncompressed = new Uint16Array(16384);
|
||||||
|
let offset = 0;
|
||||||
|
for (let index = 0; index < 16384; index++) {
|
||||||
|
currentValue = u16le(offset);
|
||||||
|
offset += 2;
|
||||||
|
if (currentValue >= 0xff00) {
|
||||||
|
//do a raw copy
|
||||||
|
let length = ((0x10000 - currentValue));
|
||||||
|
for (let enumerator = 0; enumerator < length; enumerator++) {
|
||||||
|
uncompressed[index] = u16le(offset);
|
||||||
|
offset += 2;
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//repeat next byte rleType times
|
||||||
|
uncompressed[index] = u16le(offset);
|
||||||
|
for (let indey = 0; indey < currentValue; indey++) {
|
||||||
|
uncompressed[index] = u16le(offset);
|
||||||
|
index++
|
||||||
|
}
|
||||||
|
offset += 2;
|
||||||
|
}
|
||||||
|
index--;
|
||||||
|
}
|
||||||
|
return uncompressed;
|
||||||
|
}
|
||||||
|
|
||||||
|
function convertBGR5A1toRGB5A1(bgrData) {
|
||||||
|
if(bgrData.byteLength !== 32768) {
|
||||||
|
throw `Not a 128x128x16 texture. (length was ${bgrData.length})`;
|
||||||
|
}
|
||||||
|
// converts 5-bit blue, green, red (in that order) with one alpha bit to GL-compatible RGB5A1
|
||||||
|
const view = new DataView(bgrData);
|
||||||
|
const u16le = function(i){return view.getUint16(i, 1)}
|
||||||
|
let converted = new Uint16Array(16384);
|
||||||
|
for (let index = 0; index < 16384; index++) {
|
||||||
|
let b = ( u16le(index*2) & 0b11111);
|
||||||
|
let g = (((u16le(index*2)) >> 5) & 0b11111);
|
||||||
|
let r = (((u16le(index*2)) >> 10) & 0b11111);
|
||||||
|
// rrrrrgggggbbbbba (a = 1 because 0 is 127 which is 1.0f opacity for the GS)
|
||||||
|
let newValue = 0b0000000000000001;
|
||||||
|
newValue |= (r << 1);
|
||||||
|
newValue |= (g << 6);
|
||||||
|
newValue |= (b << 11);
|
||||||
|
converted[index] = newValue;
|
||||||
|
}
|
||||||
|
return converted;
|
||||||
}
|
}
|
||||||
|
|
||||||
function stringScrubber(dirty) {
|
function stringScrubber(dirty) {
|
||||||
|
@ -107,7 +158,8 @@ function readIconFile(input) {
|
||||||
r: (i & 0xff),
|
r: (i & 0xff),
|
||||||
g: ((i & 0xff00) >> 8),
|
g: ((i & 0xff00) >> 8),
|
||||||
b: ((i & 0xff0000) >> 16),
|
b: ((i & 0xff0000) >> 16),
|
||||||
a: (i > 0x7fffffff ? 255 : (((i & 0xff000000) >>> 24) * 2)+1)
|
//a: (i > 0x7fffffff ? 255 : (((i & 0xff000000) >>> 24) * 2)+1)
|
||||||
|
a: 255 // I don't think alpha transparency is actually USED in icons?
|
||||||
}};
|
}};
|
||||||
const magic = u32le(0);
|
const magic = u32le(0);
|
||||||
if (magic !== 0x010000) {
|
if (magic !== 0x010000) {
|
||||||
|
@ -190,7 +242,7 @@ function readIconFile(input) {
|
||||||
* u16 rleType;
|
* u16 rleType;
|
||||||
* if (rleType >= 0xff00) {
|
* if (rleType >= 0xff00) {
|
||||||
* //do a raw copy
|
* //do a raw copy
|
||||||
* let length = (0xffff - rleType);
|
* let length = (0x10000 - rleType);
|
||||||
* byte data[length];
|
* byte data[length];
|
||||||
* } else {
|
* } else {
|
||||||
* //repeat next byte rleType times
|
* //repeat next byte rleType times
|
||||||
|
@ -201,7 +253,7 @@ function readIconFile(input) {
|
||||||
* }
|
* }
|
||||||
**/
|
**/
|
||||||
//output of this will be another u16[0x4000] of the decompressed texture
|
//output of this will be another u16[0x4000] of the decompressed texture
|
||||||
//after that just parse output as-if it was uncompressed, I think.
|
//after that just parse output as-if it was uncompressed.
|
||||||
size = u32le(offset);
|
size = u32le(offset);
|
||||||
texture = {size, data: input.slice(offset+4, offset+(4+size))};
|
texture = {size, data: input.slice(offset+4, offset+(4+size))};
|
||||||
}
|
}
|
||||||
|
@ -399,6 +451,9 @@ function readSharkXPortSxpsFile(input) {
|
||||||
const u32le = function(i){return view.getUint32(i, 1)};
|
const u32le = function(i){return view.getUint32(i, 1)};
|
||||||
//!pattern sps-xps_file.hexpat
|
//!pattern sps-xps_file.hexpat
|
||||||
const identLength = u32le(0);
|
const identLength = u32le(0);
|
||||||
|
if(identLength !== 13) {
|
||||||
|
throw `Not a SharkPort (SPS) or X-Port (XPS) export file (was ${identLength}, expected 13)`;
|
||||||
|
}
|
||||||
let offset = 4;
|
let offset = 4;
|
||||||
const ident = input.slice(offset, offset+identLength);
|
const ident = input.slice(offset, offset+identLength);
|
||||||
if((new TextDecoder("utf-8")).decode(ident) !== "SharkPortSave") {
|
if((new TextDecoder("utf-8")).decode(ident) !== "SharkPortSave") {
|
||||||
|
@ -445,6 +500,7 @@ function readSharkXPortSxpsFile(input) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fsOut[header.filename] = output;
|
fsOut[header.filename] = output;
|
||||||
|
//:skip 4 // then here lies, at offset (the end of file), a u32 checksum.
|
||||||
return fsOut;
|
return fsOut;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
95
input.htm
95
input.htm
|
@ -28,26 +28,7 @@
|
||||||
attribute vec4 a_color;
|
attribute vec4 a_color;
|
||||||
|
|
||||||
varying lowp vec4 v_color;
|
varying lowp vec4 v_color;
|
||||||
|
varying lowp vec2 v_textureCoords;
|
||||||
void main() {
|
|
||||||
// x, y, z, scale (w)
|
|
||||||
gl_Position = vec4(
|
|
||||||
a_position.x,
|
|
||||||
(0.0 - a_position.y) - 2.75, // invert the y position and move down -2.75, which will center the model
|
|
||||||
a_position.z,
|
|
||||||
3.0
|
|
||||||
);
|
|
||||||
// flip it, scale it
|
|
||||||
v_color = a_color;
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<script type="text/plain" id="shader-icon-v2">
|
|
||||||
attribute vec3 a_position;
|
|
||||||
attribute vec3 a_normal;
|
|
||||||
attribute vec2 a_textureCoords;
|
|
||||||
attribute vec4 a_color;
|
|
||||||
|
|
||||||
varying highp vec2 v_textureCoords;
|
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
// x, y, z, scale (w)
|
// x, y, z, scale (w)
|
||||||
|
@ -59,6 +40,7 @@
|
||||||
);
|
);
|
||||||
// flip it, scale it
|
// flip it, scale it
|
||||||
v_textureCoords = a_textureCoords;
|
v_textureCoords = a_textureCoords;
|
||||||
|
v_color = a_color;
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<script type="text/plain" id="shader-icon-f">
|
<script type="text/plain" id="shader-icon-f">
|
||||||
|
@ -69,7 +51,7 @@
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<script type="text/plain" id="shader-icon-f2">
|
<script type="text/plain" id="shader-icon-f2">
|
||||||
varying highp vec2 v_textureCoords;
|
varying lowp vec2 v_textureCoords;
|
||||||
uniform sampler2D u_sampler;
|
uniform sampler2D u_sampler;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
|
@ -179,68 +161,27 @@
|
||||||
document.getElementById("icond").textContent = "?";
|
document.getElementById("icond").textContent = "?";
|
||||||
document.getElementById("dateCreated").textContent = "--:--:-- --/--/----";
|
document.getElementById("dateCreated").textContent = "--:--:-- --/--/----";
|
||||||
document.getElementById("dateModified").textContent = "--:--:-- --/--/----";
|
document.getElementById("dateModified").textContent = "--:--:-- --/--/----";
|
||||||
}
|
document.getElementById("fileCommentGame").textContent = "(no title)";
|
||||||
function uncompressTexture(texData) {
|
document.getElementById("fileCommentName").textContent = "(no description)";
|
||||||
const view = new DataView(texData);
|
|
||||||
const u16le = function(i){return view.getUint16(i, 1)}
|
|
||||||
let uncompressed = new Uint16Array(16384);
|
|
||||||
for (let index = 0; index < 16384; index++) {
|
|
||||||
currentValue = u16le(index);
|
|
||||||
console.log(index, currentValue);
|
|
||||||
if (currentValue >= 0xff00) {
|
|
||||||
//do a raw copy
|
|
||||||
let length = ((0x10000 - currentValue));
|
|
||||||
for (let enumerator = 0; enumerator < length; enumerator++) {
|
|
||||||
console.log("i'm here", index, (index*2), u16le(index), u16le(index *2), ((index * 2) -2), u16le((index * 2) -2))
|
|
||||||
uncompressed[index-1] = u16le((index * 2) -2);
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
//repeat next byte rleType times
|
|
||||||
let original = index;
|
|
||||||
for (let indey = 0; indey < currentValue; indey++) {
|
|
||||||
uncompressed[index++] = u16le(original+2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return uncompressed;
|
|
||||||
}
|
}
|
||||||
function renderIcon(iconData) {
|
function renderIcon(iconData) {
|
||||||
if(glFgContext === null) {return -1;} else {
|
if(glFgContext === null) {return -1;} else {
|
||||||
const texture = glFgContext.createTexture();
|
const texture = glFgContext.createTexture();
|
||||||
glFgContext.bindTexture(glFgContext.TEXTURE_2D, texture);
|
glFgContext.bindTexture(glFgContext.TEXTURE_2D, texture);
|
||||||
if (iconData.textureFormat === "U") {
|
if (iconData.textureFormat !== "N") {
|
||||||
glFgContext.texImage2D(glFgContext.TEXTURE_2D, 0, glFgContext.RGBA, 128, 128, 0, glFgContext.RGBA, glFgContext.UNSIGNED_SHORT_5_5_5_1, iconData.texture);
|
let rgb5a1_converted;
|
||||||
glFgContext.generateMipmap(glFgContext.TEXTURE_2D);
|
if (iconData.textureFormat === "C") {
|
||||||
}
|
let uncompressed = uncompressTexture(iconData.texture.data);
|
||||||
if (iconData.textureFormat === "C") {
|
rgb5a1_converted = convertBGR5A1toRGB5A1(uncompressed.buffer);
|
||||||
let uncompressed = uncompressTexture(iconData.texture.data);
|
} else {
|
||||||
console.log(uncompressed);
|
rgb5a1_converted = convertBGR5A1toRGB5A1(iconData.texture.buffer);
|
||||||
/*
|
}
|
||||||
let uncompressed = new Uint16Array([
|
glFgContext.texImage2D(glFgContext.TEXTURE_2D, 0, glFgContext.RGBA, 128, 128, 0, glFgContext.RGBA, glFgContext.UNSIGNED_SHORT_5_5_5_1, rgb5a1_converted);
|
||||||
63551, 63551, 1, 1, 63551, 63551, 1, 1,
|
|
||||||
63551, 63551, 1, 1, 63551, 63551, 1, 1,
|
|
||||||
1, 1, 63551, 63551, 1, 1, 63551, 63551,
|
|
||||||
1, 1, 63551, 63551, 1, 1, 63551, 63551,
|
|
||||||
63551, 63551, 1, 1, 63551, 63551, 1, 1,
|
|
||||||
63551, 63551, 1, 1, 63551, 63551, 1, 1,
|
|
||||||
1, 1, 63551, 63551, 1, 1, 63551, 63551,
|
|
||||||
1, 1, 63551, 63551, 1, 1, 63551, 63551,
|
|
||||||
63551, 63551, 1, 1, 63551, 63551, 1, 1,
|
|
||||||
63551, 63551, 1, 1, 63551, 63551, 1, 1,
|
|
||||||
1, 1, 63551, 63551, 1, 1, 63551, 63551,
|
|
||||||
1, 1, 63551, 63551, 1, 1, 63551, 63551,
|
|
||||||
63551, 63551, 1, 1, 63551, 63551, 1, 1,
|
|
||||||
63551, 63551, 1, 1, 63551, 63551, 1, 1,
|
|
||||||
1, 1, 63551, 63551, 1, 1, 63551, 63551,
|
|
||||||
1, 1, 63551, 63551, 1, 1, 63551, 63551,
|
|
||||||
]);*/
|
|
||||||
glFgContext.texImage2D(glFgContext.TEXTURE_2D, 0, glFgContext.RGBA, 128, 128, 0, glFgContext.RGBA, glFgContext.UNSIGNED_SHORT_5_5_5_1, uncompressed);
|
|
||||||
glFgContext.generateMipmap(glFgContext.TEXTURE_2D);
|
glFgContext.generateMipmap(glFgContext.TEXTURE_2D);
|
||||||
}
|
}
|
||||||
//.section PROGRAM.icon
|
//.section PROGRAM.icon
|
||||||
if(iconData.textureFormat !== "N") {
|
if(iconData.textureFormat !== "N") {
|
||||||
var iconVertexShader = createShader(glFgContext, glFgContext.VERTEX_SHADER, document.getElementById("shader-icon-v2").text);
|
var iconVertexShader = createShader(glFgContext, glFgContext.VERTEX_SHADER, document.getElementById("shader-icon-v").text);
|
||||||
var iconFragmentShader = createShader(glFgContext, glFgContext.FRAGMENT_SHADER, document.getElementById("shader-icon-f2").text);
|
var iconFragmentShader = createShader(glFgContext, glFgContext.FRAGMENT_SHADER, document.getElementById("shader-icon-f2").text);
|
||||||
} else {
|
} else {
|
||||||
var iconVertexShader = createShader(glFgContext, glFgContext.VERTEX_SHADER, document.getElementById("shader-icon-v").text);
|
var iconVertexShader = createShader(glFgContext, glFgContext.VERTEX_SHADER, document.getElementById("shader-icon-v").text);
|
||||||
|
@ -385,7 +326,7 @@
|
||||||
let inputData = readPsvFile(d);
|
let inputData = readPsvFile(d);
|
||||||
let output = readPS2D(inputData["icon.sys"]);
|
let output = readPS2D(inputData["icon.sys"]);
|
||||||
updateDisplay(output);
|
updateDisplay(output);
|
||||||
renderIcon(inputData.icons.n);
|
renderIcon(readIconFile(inputData.icons.n));
|
||||||
let cTime = inputData.timestamps.created;
|
let cTime = inputData.timestamps.created;
|
||||||
let mTime = inputData.timestamps.modified;
|
let mTime = inputData.timestamps.modified;
|
||||||
//TODO: use Time() to align JST times to user-local timezone
|
//TODO: use Time() to align JST times to user-local timezone
|
||||||
|
@ -506,10 +447,10 @@
|
||||||
document.getElementById("showExtractedInputOption").onchange = function(e) {
|
document.getElementById("showExtractedInputOption").onchange = function(e) {
|
||||||
document.getElementById("advanced").style.display = ((e.target.checked) ? "block" : "none");
|
document.getElementById("advanced").style.display = ((e.target.checked) ? "block" : "none");
|
||||||
}
|
}
|
||||||
//todo: Texture parsing, Animation parsing, animation tweening
|
//todo: Animation parsing, animation tweening, whatever's going on with texture type 15
|
||||||
</script>
|
</script>
|
||||||
<span id="version">icondumper2 <span id="iconjsVersion">(unknown icon.js version)</span> [C: <span id="clientVersion">Loading...</span>] - © 2023 yellows111</span>
|
<span id="version">icondumper2 <span id="iconjsVersion">(unknown icon.js version)</span> [C: <span id="clientVersion">Loading...</span>] - © 2023 yellows111</span>
|
||||||
<script>document.getElementById("iconjsVersion").textContent = ICONJS_VERSION;</script>
|
<script>document.getElementById("iconjsVersion").textContent = ICONJS_VERSION;</script>
|
||||||
<script>document.getElementById("clientVersion").textContent = "0.4.3";</script>
|
<script>document.getElementById("clientVersion").textContent = "0.5.1";</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
Loading…
Reference in New Issue