Basic selection working
This commit is contained in:
parent
1419290e7a
commit
eb6f502d96
21
index.html
21
index.html
@ -1,13 +1,30 @@
|
||||
<!doctype html>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>BittMapp</title>
|
||||
<link rel="stylesheet" href="./static/css/reset.css" />
|
||||
<link rel="stylesheet" href="./static/css/styles.css" />
|
||||
<script src="./static/js/serialisers.js"></script>
|
||||
<script src="./static/js/bmptools.js"></script>
|
||||
<script src="./static/js/bittmappeditor.js"></script>
|
||||
<script src="./static/js/main.js"></script>
|
||||
<link rel="stylesheet" href="./static/css/styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h2>Modes</h2>
|
||||
<ul id="modes">
|
||||
<li><a href="#" id="pencil_mode_button">Pencil Mode</a></li>
|
||||
<li><a href="#" id="eraser_mode_button">Eraser Mode</a></li>
|
||||
<li><a href="#" id="selection_mode_button">Selection Mode</a></li>
|
||||
</ul>
|
||||
<h2>File Options</h2>
|
||||
<ul id="files">
|
||||
<li><input type="text" id="open_file_pixelwidth_input" value="32" /> <input type="text" id="open_file_pixelheight_input" value="32" /> <a href="#" id="open_file_button">Open File</a></li>
|
||||
<li><input type="text" id="filename_input" /> <a href="#" id="save_file_button">Save File</a></li>
|
||||
</ul>
|
||||
</header>
|
||||
<section id="main">
|
||||
<h3>Editor</h3>
|
||||
<canvas id="editor"></canvas>
|
||||
</section>
|
||||
</body>
|
||||
|
@ -13,6 +13,13 @@ enum MouseButton {
|
||||
}
|
||||
|
||||
|
||||
enum Mode {
|
||||
PENCIL = 0,
|
||||
ERASER = 1,
|
||||
SELECTION = 2
|
||||
}
|
||||
|
||||
|
||||
class BittMappEditor {
|
||||
|
||||
|
||||
@ -33,7 +40,17 @@ class BittMappEditor {
|
||||
private _mouseDown: boolean = false;
|
||||
private _mouseButton: MouseButton;
|
||||
|
||||
private _selectionStartX: number = 0;
|
||||
private _selectionStartY: number = 0;
|
||||
private _selectionEndX: number = 0;
|
||||
private _selectionEndY: number = 0;
|
||||
|
||||
private _editorMode: Mode = Mode.PENCIL;
|
||||
|
||||
private _downloadHelper: HTMLAnchorElement;
|
||||
|
||||
private _data: Uint8Array;
|
||||
private _selection: Uint8Array;
|
||||
|
||||
|
||||
constructor (options: IBittMappEditorConstructorOptions) {
|
||||
@ -85,6 +102,9 @@ class BittMappEditor {
|
||||
|
||||
this._context.scale(this._scale, this._scale);
|
||||
|
||||
this._data = new Uint8Array((this._width / 8) * this._height);
|
||||
this._selection = new Uint8Array((this._width / 8) * this._height);
|
||||
|
||||
this.resize();
|
||||
|
||||
this.canvas.addEventListener("contextmenu", (event) => {
|
||||
@ -94,6 +114,12 @@ class BittMappEditor {
|
||||
this.canvas.addEventListener("mousedown", (event) => {
|
||||
this._mouseDown = true;
|
||||
this._mouseButton = event.button as MouseButton;
|
||||
this._selectionStartX = this._calculateXFromMouseCoords(event.offsetX);
|
||||
this._selectionStartY = this._calculateYFromMouseCoords(event.offsetY);
|
||||
this._selectionEndX = this._selectionStartX + 1;
|
||||
this._selectionEndY = this._selectionStartY + 1;
|
||||
// NK: Only wipe selection if Ctrl isn't pressed
|
||||
this._selection = new Uint8Array((this._width / 8) * this._height);
|
||||
this._handleMouseEvent(event, this._mouseButton);
|
||||
});
|
||||
|
||||
@ -107,31 +133,93 @@ class BittMappEditor {
|
||||
this._mouseDown = false;
|
||||
});
|
||||
|
||||
this._downloadHelper = document.createElement("a");
|
||||
document.body.appendChild(this._downloadHelper);
|
||||
(this._downloadHelper as any).style = "display: none";
|
||||
|
||||
}
|
||||
|
||||
|
||||
public pencilMode () {
|
||||
this._selection = new Uint8Array((this._width / 8) * this._height);
|
||||
this._editorMode = Mode.PENCIL;
|
||||
}
|
||||
|
||||
|
||||
public eraserMode () {
|
||||
this._selection = new Uint8Array((this._width / 8) * this._height);
|
||||
this._editorMode = Mode.ERASER;
|
||||
}
|
||||
|
||||
|
||||
public selectionMode () {
|
||||
this._editorMode = Mode.SELECTION;
|
||||
}
|
||||
|
||||
|
||||
public setPixel (x: number, y: number): void {
|
||||
const byte: number = ((y * (this._width / 8)) + Math.floor(x / 8));
|
||||
const mask: number = 1 << (x % 8);
|
||||
const byte: number = this._calculateByteFromCoords(x, y);
|
||||
// const byte: number = ((y * (this._width / 8)) + Math.floor(x / 8));
|
||||
const mask: number = this._calculateByteMask(x);
|
||||
this._data[byte] = this._data[byte] |= mask;
|
||||
}
|
||||
|
||||
|
||||
public unsetPixel (x: number, y: number): void {
|
||||
const byte: number = ((y * (this._width / 8)) + Math.floor(x / 8));
|
||||
const mask: number = 1 << (x % 8);
|
||||
const byte: number = this._calculateByteFromCoords(x, y);
|
||||
// const byte: number = ((y * (this._width / 8)) + Math.floor(x / 8));
|
||||
const mask: number = this._calculateByteMask(x);
|
||||
this._data[byte] = this._data[byte] &= ~mask;
|
||||
}
|
||||
|
||||
|
||||
public selectPixel (x: number, y: number): void {
|
||||
const byte: number = this._calculateByteFromCoords(x, y);
|
||||
// const byte: number = ((y * (this._width / 8)) + Math.floor(x / 8));
|
||||
const mask: number = this._calculateByteMask(x);
|
||||
this._selection[byte] = this._selection[byte] |= mask;
|
||||
}
|
||||
|
||||
|
||||
public deselectPixel (x: number, y: number): void {
|
||||
const byte: number = this._calculateByteFromCoords(x, y);
|
||||
// const byte: number = ((y * (this._width / 8)) + Math.floor(x / 8));
|
||||
const mask: number = this._calculateByteMask(x);
|
||||
this._selection[byte] = this._selection[byte] &= ~mask;
|
||||
}
|
||||
|
||||
|
||||
public deselectAll (): void {
|
||||
this._selection = new Uint8Array((this._width / 8) * this._height);
|
||||
}
|
||||
|
||||
|
||||
public resize (width: number = this._width, height: number = this._height): void {
|
||||
this._data = new Uint8Array((width / 8) * height);
|
||||
this._pixelWidth = this.canvasWidth / this._width;
|
||||
this._pixelHeight = this.canvasHeight / this._height;
|
||||
// TODO: Resize the data buffer
|
||||
this._width = width;
|
||||
this._height = height;
|
||||
this._pixelWidth = this.canvasWidth / width;
|
||||
this._pixelHeight = this.canvasHeight / height;
|
||||
this._redraw();
|
||||
}
|
||||
|
||||
|
||||
public loadFromData (data: Uint8Array, width: number, height: number) {
|
||||
this._data = data;
|
||||
this.resize(width, height);
|
||||
}
|
||||
|
||||
|
||||
public saveToFile (filename: string) {
|
||||
const blob: Blob = new Blob([this._data], {type: "octet/stream"});
|
||||
const url: string = window.URL.createObjectURL(blob);
|
||||
this._downloadHelper.href = url;
|
||||
this._downloadHelper.download = filename;
|
||||
this._downloadHelper.click();
|
||||
window.URL.revokeObjectURL(url);
|
||||
}
|
||||
|
||||
|
||||
get height (): number {
|
||||
return this._height;
|
||||
}
|
||||
@ -152,15 +240,67 @@ class BittMappEditor {
|
||||
}
|
||||
|
||||
|
||||
private _calculateByteFromCoords (x: number, y: number): number {
|
||||
return Math.floor(((y * this._width) + x) / 8);
|
||||
}
|
||||
|
||||
|
||||
private _calculateByteMask (x: number) {
|
||||
return 1 << (x % 8);
|
||||
}
|
||||
|
||||
|
||||
private _calculateXFromMouseCoords (mouseX: number, round: any = Math.floor): number {
|
||||
return round(mouseX / this._pixelWidth);
|
||||
}
|
||||
|
||||
|
||||
private _calculateYFromMouseCoords (mouseY: number, round: any = Math.floor): number {
|
||||
return round(mouseY / this._pixelHeight);
|
||||
}
|
||||
|
||||
|
||||
private _handleMouseEvent (event: MouseEvent, button: number): void {
|
||||
|
||||
const pixelX: number = Math.floor(event.offsetX / this._pixelWidth);
|
||||
const pixelY: number = Math.floor(event.offsetY / this._pixelHeight);
|
||||
let mouseX: number = this._calculateXFromMouseCoords(event.offsetX);
|
||||
let mouseY: number = this._calculateYFromMouseCoords(event.offsetY);
|
||||
|
||||
if (button === MouseButton.LEFT) {
|
||||
this.setPixel(pixelX, pixelY);
|
||||
} else if (button === MouseButton.RIGHT) {
|
||||
this.unsetPixel(pixelX, pixelY);
|
||||
switch (this._editorMode) {
|
||||
case Mode.PENCIL:
|
||||
|
||||
if (button === MouseButton.LEFT) {
|
||||
this.setPixel(mouseX, mouseY);
|
||||
} else if (button === MouseButton.RIGHT) {
|
||||
this.unsetPixel(mouseX, mouseY);
|
||||
}
|
||||
|
||||
break;
|
||||
case Mode.ERASER:
|
||||
|
||||
if (button === MouseButton.LEFT) {
|
||||
this.unsetPixel(mouseX, mouseY);
|
||||
} else if (button === MouseButton.RIGHT) {
|
||||
this.setPixel(mouseX, mouseY);
|
||||
}
|
||||
|
||||
break;
|
||||
case Mode.SELECTION:
|
||||
|
||||
// Only do this if Ctrl isn't pressed
|
||||
mouseX = this._calculateXFromMouseCoords(event.offsetX, Math.ceil);
|
||||
mouseY = this._calculateYFromMouseCoords(event.offsetY, Math.ceil);
|
||||
|
||||
this._selection = new Uint8Array((this._width / 8) * this._height);
|
||||
this._selectionEndX = mouseX;
|
||||
this._selectionEndY = mouseY;
|
||||
|
||||
for (let x: number = this._selectionStartX; x < this._selectionEndX; x++) {
|
||||
for (let y: number = this._selectionStartY; y < this._selectionEndY; y++) {
|
||||
this.selectPixel(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
this._redraw();
|
||||
@ -168,9 +308,31 @@ class BittMappEditor {
|
||||
}
|
||||
|
||||
|
||||
private _isSelected (x: number, y: number): boolean {
|
||||
if (x < 0 || y < 0) {
|
||||
return false;
|
||||
} else if (x > this._width - 1 || y > this._height - 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const byte: number = this._calculateByteFromCoords(x, y);
|
||||
const mask: number = this._calculateByteMask(x);
|
||||
|
||||
if ((this._selection[byte] & mask) >= 1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
|
||||
private _redraw (): void {
|
||||
this._drawGrid();
|
||||
this._drawPixels();
|
||||
if (this._editorMode === Mode.SELECTION) {
|
||||
this._drawSelection();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -243,4 +405,52 @@ class BittMappEditor {
|
||||
}
|
||||
|
||||
|
||||
private _drawSelection (): void {
|
||||
|
||||
this._context.strokeStyle = "#FF0000";
|
||||
|
||||
for (let x: number = 0; x < this._width; x++) {
|
||||
for (let y: number = 0; y < this._height; y++) {
|
||||
|
||||
const byte: number = this._calculateByteFromCoords(x, y);
|
||||
const mask: number = this._calculateByteMask(x);
|
||||
|
||||
if (this._isSelected(x, y)) {
|
||||
|
||||
if (!this._isSelected(x - 1, y)) {
|
||||
this._context.beginPath();
|
||||
this._context.moveTo(x * this._pixelWidth, y * this._pixelHeight);
|
||||
this._context.lineTo(x * this._pixelWidth, (y * this._pixelHeight) + this._pixelHeight);
|
||||
this._context.stroke();
|
||||
}
|
||||
|
||||
if (!this._isSelected(x, y - 1)) {
|
||||
this._context.beginPath();
|
||||
this._context.moveTo(x * this._pixelWidth, y * this._pixelHeight);
|
||||
this._context.lineTo((x * this._pixelWidth) + this._pixelWidth, y * this._pixelHeight);
|
||||
this._context.stroke();
|
||||
}
|
||||
|
||||
if (!this._isSelected(x + 1, y)) {
|
||||
this._context.beginPath();
|
||||
this._context.moveTo((x * this._pixelWidth) + this._pixelWidth, y * this._pixelHeight);
|
||||
this._context.lineTo((x * this._pixelWidth) + this._pixelWidth, (y * this._pixelHeight) + this._pixelHeight);
|
||||
this._context.stroke();
|
||||
}
|
||||
|
||||
if (!this._isSelected(x, y + 1)) {
|
||||
this._context.beginPath();
|
||||
this._context.moveTo(x * this._pixelWidth, (y * this._pixelHeight) + this._pixelHeight);
|
||||
this._context.lineTo((x * this._pixelWidth) + this._pixelWidth, (y * this._pixelHeight) + this._pixelHeight);
|
||||
this._context.stroke();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
151
src/bmptools.ts
Normal file
151
src/bmptools.ts
Normal file
@ -0,0 +1,151 @@
|
||||
interface IBMPHeaderData {
|
||||
fileLength: number;
|
||||
headerLength: number;
|
||||
pixelDataOffset: number;
|
||||
width: number;
|
||||
height: number;
|
||||
planes: number;
|
||||
bitsPerPixel: number;
|
||||
compressed: number;
|
||||
imageSize: number;
|
||||
numberColors: number;
|
||||
importantColors: number;
|
||||
bytesRead: number;
|
||||
}
|
||||
|
||||
|
||||
interface IBittMappData {
|
||||
|
||||
data: Uint8Array;
|
||||
width: number;
|
||||
height: number;
|
||||
|
||||
}
|
||||
|
||||
|
||||
class BMPTools {
|
||||
|
||||
|
||||
public static extractBitmap (inputData: Uint8Array): IBittMappData {
|
||||
|
||||
const headerData: IBMPHeaderData = BMPTools.extractHeaderData(inputData);
|
||||
const pixelData: Uint8Array = inputData.slice(headerData.pixelDataOffset, headerData.fileLength);
|
||||
const rowSize: number = (headerData.width - 1 - (headerData.width - 1) % 32 + 32) / 8;
|
||||
|
||||
// console.log(headerData);
|
||||
|
||||
const outputData: Uint8Array = new Uint8Array(Math.ceil((headerData.width * headerData.height) / 8));
|
||||
|
||||
if (headerData.height > 0) {
|
||||
let bitCount: number = 0;
|
||||
for (let y: number = headerData.height - 1; y >= 0; y--) {
|
||||
const rowStart: number = rowSize * y;
|
||||
for (let x: number = 0; x < headerData.width; x++) {
|
||||
const inputByte: number = Math.floor(x / 8);
|
||||
const outputByte: number = Math.floor((((headerData.height - 1 - y) * headerData.width) + x) / 8);
|
||||
const inputMask: number = 1 << (x % 8);
|
||||
const outputMask: number = 1 << (bitCount % 8);
|
||||
const val: number = pixelData[rowStart + inputByte] & inputMask;
|
||||
// console.log(val);
|
||||
outputData[outputByte] = val + outputData[outputByte];
|
||||
// console.log((rowStart + inputByte), inputMask, outputByte, outputMask);
|
||||
bitCount++;
|
||||
}
|
||||
}
|
||||
} /* else {
|
||||
let bitCount: number = 0;
|
||||
for (let y: number = 0; y < headerData.height; y++) {
|
||||
const rowStart: number = rowSize * y;
|
||||
console.log(pixelData[rowStart], pixelData[rowStart + 1], pixelData[rowStart + 2], pixelData[rowStart + 3]);
|
||||
for (let x: number = 0; x < headerData.width; x++) {
|
||||
const inputByte: number = Math.floor(x / 8);
|
||||
const outputByte: number = Math.floor(((y * headerData.width) + x) / 8);
|
||||
const inputMask: number = 1 << (x % 8);
|
||||
const outputMask: number = 1 << (bitCount % 8);
|
||||
let val: number = pixelData[rowStart + inputByte];
|
||||
console.log(val);
|
||||
//outputData[outputByte] = val |= outputMask;
|
||||
console.log((rowStart + inputByte), inputMask, outputByte, outputMask);
|
||||
bitCount++;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
return {
|
||||
data: outputData,
|
||||
height: headerData.height,
|
||||
width: headerData.width
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static extractHeaderData (inputData: Uint8Array): IBMPHeaderData {
|
||||
|
||||
const headerData = {} as any;
|
||||
|
||||
if (inputData.length < 54) {
|
||||
throw new Error("Data not valid (Not long enough, must be at least 54 bytes)");
|
||||
}
|
||||
|
||||
if (!(inputData[0] === 0x42 && inputData[1] === 0x4d)) {
|
||||
throw new Error("Data not valid (No BM header)");
|
||||
}
|
||||
|
||||
headerData.fileLength = Serialisers.readUint32(inputData, 2, true);
|
||||
if (headerData.fileLength !== inputData.length) {
|
||||
throw new Error("Data not valid (Length incorrect)");
|
||||
}
|
||||
|
||||
headerData.pixelDataOffset = Serialisers.readUint32(inputData, 10, true);
|
||||
headerData.headerLength = Serialisers.readUint32(inputData, 14, true);
|
||||
headerData.width = Serialisers.readUint32(inputData, 18, true);
|
||||
headerData.height = Serialisers.readInt32(inputData, 22, true);
|
||||
headerData.planes = Serialisers.readUint16(inputData, 26, true);
|
||||
if (headerData.planes !== 1) {
|
||||
throw new Error("Data not valid (Only one plane supported)");
|
||||
}
|
||||
|
||||
headerData.bitsPerPixel = Serialisers.readUint16(inputData, 28, true);
|
||||
if (headerData.bitsPerPixel !== 1) {
|
||||
throw new Error("Data not valid (Only monochrome BMP data supported)");
|
||||
}
|
||||
|
||||
headerData.compressed = Serialisers.readUint32(inputData, 30, true);
|
||||
if (headerData.compressed !== 0) {
|
||||
throw new Error("Data not valid (Only uncompressed data supported)");
|
||||
}
|
||||
|
||||
headerData.imageSize = Serialisers.readUint32(inputData, 34, true);
|
||||
headerData.imageSize = Serialisers.readUint32(inputData, 34, true);
|
||||
headerData.numberColors = Serialisers.readUint32(inputData, 46, true);
|
||||
headerData.importantColors = Serialisers.readUint32(inputData, 50, true);
|
||||
|
||||
headerData.bytesRead = headerData.headerLength + 14;
|
||||
|
||||
return (headerData as IBMPHeaderData);
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static isPossiblyBMPFormat (inputData: Uint8Array): boolean {
|
||||
|
||||
if (inputData.length < 54) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(inputData[0] === 0x42 && inputData[1] === 0x4d)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const fileLen: number = Serialisers.readUint32(inputData, 2, true);
|
||||
if (fileLen !== inputData.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
73
src/main.ts
73
src/main.ts
@ -2,10 +2,79 @@ window.onload = (): void => {
|
||||
|
||||
const editor: BittMappEditor = new BittMappEditor({
|
||||
canvas: document.getElementById("editor") as HTMLCanvasElement,
|
||||
canvasHeight: 640,
|
||||
canvasWidth: 640,
|
||||
canvasHeight: 480,
|
||||
canvasWidth: 480,
|
||||
height: 32,
|
||||
width: 32
|
||||
});
|
||||
|
||||
(document.getElementById("pencil_mode_button") as HTMLAnchorElement).addEventListener("click", (event: MouseEvent) => {
|
||||
event.preventDefault();
|
||||
editor.pencilMode();
|
||||
});
|
||||
|
||||
(document.getElementById("eraser_mode_button") as HTMLAnchorElement).addEventListener("click", (event: MouseEvent) => {
|
||||
event.preventDefault();
|
||||
editor.eraserMode();
|
||||
});
|
||||
|
||||
(document.getElementById("selection_mode_button") as HTMLAnchorElement).addEventListener("click", (event: MouseEvent) => {
|
||||
event.preventDefault();
|
||||
editor.selectionMode();
|
||||
});
|
||||
|
||||
(document.getElementById("save_file_button") as HTMLAnchorElement).addEventListener("click", (event: MouseEvent) => {
|
||||
event.preventDefault();
|
||||
const filename: string = (document.getElementById("filename_input") as HTMLInputElement).value;
|
||||
editor.saveToFile(filename);
|
||||
});
|
||||
|
||||
(document.getElementById("open_file_button") as HTMLAnchorElement).addEventListener("drop", (event: DragEvent) => {
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
const dataTransfer: DataTransfer = event.dataTransfer;
|
||||
|
||||
if (dataTransfer.items.length > 1) {
|
||||
alert("One file only!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (dataTransfer.items) {
|
||||
for (const item of (dataTransfer.items as any)) {
|
||||
|
||||
const file: File = item.getAsFile();
|
||||
const fileReader: FileReader = new FileReader();
|
||||
|
||||
fileReader.addEventListener("loadend", () => {
|
||||
|
||||
const data: Uint8Array = new Uint8Array(fileReader.result);
|
||||
|
||||
if (BMPTools.isPossiblyBMPFormat(data)) {
|
||||
const bittMappData: IBittMappData = BMPTools.extractBitmap(data);
|
||||
const pixelWidth = bittMappData.width;
|
||||
const pixelHeight = bittMappData.height;
|
||||
editor.loadFromData(bittMappData.data, pixelWidth, pixelHeight);
|
||||
} else {
|
||||
const pixelWidth = parseInt((document.getElementById("open_file_pixelwidth_input") as HTMLInputElement).value, 10);
|
||||
const pixelHeight = parseInt((document.getElementById("open_file_pixelheight_input") as HTMLInputElement).value, 10);
|
||||
editor.loadFromData(data, pixelWidth, pixelHeight);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
fileReader.readAsArrayBuffer(file);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
(document.getElementById("open_file_button") as HTMLAnchorElement).addEventListener("dragover", (event: DragEvent) => {
|
||||
event.preventDefault();
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
// const testData: Uint8Array = new Uint8Array([66, 77, 190, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0, 0, 40, 0, 0, 0, 32, 0, 0, 0, 32, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 128, 0, 0, 0, 116, 18, 0, 0, 116, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 15, 255, 255, 255, 247, 246, 142, 115, 183, 246, 181, 173, 183, 240, 141, 173, 183, 246, 181, 173, 183, 249, 142, 109, 23, 255, 255, 255, 247, 246, 141, 127, 247, 246, 189, 127, 247, 244, 138, 191, 247, 242, 186, 191, 247, 246, 138, 191, 247, 255, 255, 255, 247, 247, 139, 71, 247, 247, 187, 123, 247, 241, 184, 67, 247, 246, 187, 91, 247, 241, 188, 219, 247, 255, 255, 255, 247]);
|
||||
|
21
src/serialisers.ts
Normal file
21
src/serialisers.ts
Normal file
@ -0,0 +1,21 @@
|
||||
class Serialisers {
|
||||
|
||||
|
||||
public static readInt32 (data: Uint8Array, start: number, littleEndian: boolean = false): number {
|
||||
// console.log(new DataView(data.buffer.slice(start, start + 4)).getInt32(0));
|
||||
return new DataView(data.buffer).getInt32(start, littleEndian);
|
||||
}
|
||||
|
||||
|
||||
public static readUint32 (data: Uint8Array, start: number, littleEndian: boolean = false): number {
|
||||
// console.log(data.buffer.slice(start, start + 4));
|
||||
// console.log(new DataView(data.buffer).getUint32(start, littleEndian));
|
||||
return new DataView(data.buffer).getUint32(start, littleEndian);
|
||||
}
|
||||
|
||||
|
||||
public static readUint16 (data: Uint8Array, start: number, littleEndian: boolean = false): number {
|
||||
return new DataView(data.buffer).getUint16(start, littleEndian);
|
||||
}
|
||||
|
||||
}
|
48
static/css/reset.css
Normal file
48
static/css/reset.css
Normal file
@ -0,0 +1,48 @@
|
||||
/* http://meyerweb.com/eric/tools/css/reset/
|
||||
v2.0 | 20110126
|
||||
License: none (public domain)
|
||||
*/
|
||||
|
||||
html, body, div, span, applet, object, iframe,
|
||||
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
|
||||
a, abbr, acronym, address, big, cite, code,
|
||||
del, dfn, em, img, ins, kbd, q, s, samp,
|
||||
small, strike, strong, sub, sup, tt, var,
|
||||
b, u, i, center,
|
||||
dl, dt, dd, ol, ul, li,
|
||||
fieldset, form, label, legend,
|
||||
table, caption, tbody, tfoot, thead, tr, th, td,
|
||||
article, aside, canvas, details, embed,
|
||||
figure, figcaption, footer, header, hgroup,
|
||||
menu, nav, output, ruby, section, summary,
|
||||
time, mark, audio, video {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
font-size: 100%;
|
||||
font: inherit;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
/* HTML5 display-role reset for older browsers */
|
||||
article, aside, details, figcaption, figure,
|
||||
footer, header, hgroup, menu, nav, section {
|
||||
display: block;
|
||||
}
|
||||
body {
|
||||
line-height: 1;
|
||||
}
|
||||
ol, ul {
|
||||
list-style: none;
|
||||
}
|
||||
blockquote, q {
|
||||
quotes: none;
|
||||
}
|
||||
blockquote:before, blockquote:after,
|
||||
q:before, q:after {
|
||||
content: '';
|
||||
content: none;
|
||||
}
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
}
|
@ -3,13 +3,41 @@ html, body {
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: #1E1E1E;
|
||||
background-color: #2A2A2A;
|
||||
}
|
||||
|
||||
header {
|
||||
background-color: #3E3F40;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
header h2, section h3 {
|
||||
display: none;
|
||||
}
|
||||
|
||||
header ul {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
header ul#files {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
header ul li {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
|
||||
|
||||
section#main {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 50px;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
line-height: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
|
@ -9,6 +9,9 @@
|
||||
"space-before-function-paren": false,
|
||||
"no-bitwise": false,
|
||||
"trailing-comma": false,
|
||||
"max-line-length": false,
|
||||
"prefer-for-of": false,
|
||||
"typedef": true,
|
||||
"variable-name": [true, "ban-keywords", "check-format", "allow-leading-underscore"]
|
||||
},
|
||||
"rulesDirectory": []
|
||||
|
Loading…
x
Reference in New Issue
Block a user