novaparse
Version:
An EV Nova file parser for NovaJS
128 lines • 5.17 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const NovaResourceBase_1 = require("./NovaResourceBase");
const pngjs_1 = require("pngjs");
class RledResource extends NovaResourceBase_1.BaseResource {
constructor(resource, idSpace) {
super(resource, idSpace);
this.size = [this.data.getUint16(0), this.data.getUint16(2)];
}
get bitsPerPixel() {
var depth = this.data.getUint16(4);
if (depth !== 16) {
throw new Error("Only color depth of 16 bits / pixel supported but got " + this.bitsPerPixel);
}
return depth;
}
get numberOfFrames() {
return this.data.getUint16(8);
}
get bytesPerRow() {
return this.size[0] * 3;
}
get frames() {
var PNGSettings = { filterType: 4, width: this.size[0], height: this.size[1] };
var frames = [new pngjs_1.PNG(PNGSettings)];
var pointer = 16; //_data.position
var position = 0;
var rowStart = 0;
var currentLine = -1;
//var currentOffset = 0; for the storage, unneeded here
var col = 0;
var opcode = 0;
var count = 0;
var pixel = 0;
var currentFrame = 0;
var pixelRun = 0;
var lineLength = this.size[0];
var keep_going = true;
while (keep_going) { //rled has an opcode which says the end
position = pointer;
if ((rowStart != 0) && ((position - rowStart) & 0x03)) {
position += 4 - ((position - rowStart) & 0x03);
pointer += 4 - (count & 0x03);
}
count = this.data.getUint32(pointer);
pointer += 4;
opcode = (count & 0xFF000000) >> 24;
count &= 0x00FFFFFF;
switch (opcode) {
case 0: //RLEOpCode_EndOfFrame = 0x00;
if (currentLine != this.size[1] - 1) {
throw "wrong number of lines in frame!:" + currentLine + "≠" + (this.size[1] - 1);
}
if (++currentFrame >= this.numberOfFrames) {
keep_going = false;
break;
}
currentLine = -1;
frames[currentFrame] = new pngjs_1.PNG({
filterType: 4,
width: this.size[0],
height: this.size[1]
});
break;
case 1: //RLEOpCode_LineStart = 0x01;
++currentLine;
col = 0;
rowStart = pointer;
// frames[currentFrame][currentLine] = new Array(lineLength).fill(0); //default is clear
break;
case 2: //RLEOpCode_PixelData = 0x02;
for (var i = 0; i < count; i += 2) {
pixel = this.data.getUint16(pointer);
pointer += 2;
var offset = (currentLine * this.size[0] + col) << 2;
mapSetColor(frames[currentFrame], offset, pixel);
col++;
}
if (count & 0x03)
pointer += 4 - (count & 0x03); //realign
break;
case 3: //RLEOpCode_TransparentRun = 0x03;
col += (count >> ((this.bitsPerPixel >> 3) - 1));
break;
case 4: //RLEOpCode_PixelRun = 0x04;
pixelRun = this.data.getUint32(pointer);
pointer += 4;
for (var i = 0; i < count; i += 4) {
var offset = (currentLine * this.size[0] + col) << 2;
mapSetColor(frames[currentFrame], offset, pixel);
col++;
if (i + 2 < count) {
var offset = (currentLine * this.size[0] + col) << 2;
mapSetColor(frames[currentFrame], offset, pixel);
col++;
} // allignment
}
break;
}
}
return frames;
}
}
exports.RledResource = RledResource;
function mapSetColor(place, offset, color) {
var blue = color & 0x001F; //5 bits
var green = (color & 0x03E0) >> 5; //5 bits
var red = (color & 0x7C00) >> 10; //5 bits
var alpha = 0xFF; // * ((color & 0x8000) >> 15);
//scale
blue = blue << 3;
green = green << 3;
red = red << 3;
//refit
blue |= blue >> 5;
green |= green >> 5;
red |= red >> 5;
//avoid sign bit annoyance cause matt wants it positive, less efficient but doesn't matter after conversion to image
// var rgb = (red << 16) | (green << 8) | blue;
// console.log(green);
// console.log(red);
place.data[offset + 0] = 0xFF & red;
place.data[offset + 1] = 0xFF & green;
place.data[offset + 2] = 0xFF & blue;
place.data[offset + 3] = 0xFF & alpha;
// return rgb + (alpha * 0x01000000);
}
//# sourceMappingURL=RledResource.js.map