integrated/replaced pixel editor, nes: updated presets

This commit is contained in:
Steven Hugg 2019-03-23 10:37:49 -04:00
parent cc767eafd0
commit 36b8ed48a0
9 changed files with 352 additions and 704 deletions

View File

@ -257,7 +257,7 @@ canvas.pixelated {
height:2em;
border-style:none;
}
.palbtn .selected {
.palbtn.selected {
border-width:2px;
border-color:white;
border-style:dotted;

View File

@ -17,21 +17,6 @@ body {
overflow: hidden;
font-size: 11px;
}
.pixeditback {
position:absolute;
z-index:100;
width:100%;
height:100%;
padding:50px;
border-width:4px;
border-color:#333;
border-style:solid;
background-color:rgba(64, 64, 64, 0.5);
}
#pixeditframe {
width:100%;
height:100%;
}
</style>
<link rel="stylesheet" href="css/ui.css">
<script>
@ -166,7 +151,6 @@ if (window.location.host.endsWith('8bitworkshop.com')) {
<button id="dbg_disasm" type="button" title="Show Disassembly" style="display:none"><span class="glyphicon glyphicon-list" aria-hidden="true"></span></button>
<button id="dbg_memory" type="button" title="Show Memory" style="display:none"><span class="glyphicon glyphicon-sunglasses" aria-hidden="true"></span></button>
<button id="dbg_profile" type="button" title="Show Profile" style="display:none"><span class="glyphicon glyphicon-stats" aria-hidden="true"></span></button>
<button id="dbg_bitmap" type="button" title="Edit Bitmap"><span class="glyphicon glyphicon-camera" aria-hidden="true"></span></button>
<button id="dbg_record" type="button" title="Start/Stop Replay Recording" style="display:none"><span class="glyphicon glyphicon-record" aria-hidden="true"></span></button>
<button id="dbg_help" type="button" title="Help" style="display:none"><span class="glyphicon glyphicon-question-sign" aria-hidden="true"></span></button>
</span>
@ -243,10 +227,6 @@ if (window.location.host.endsWith('8bitworkshop.com')) {
<a target="_new" href="https://twitter.com/8bitworkshop" class="twitter-follow-button" data-show-count="false">Follow @8bitworkshop</a>-->
<!--<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>-->
<!--</div>-->
<div id="pixeditback" class="pixeditback" style="display:none">
<iframe id="pixeditframe" src="pixels.html">
</iframe>
</div>
<div id="pleaseWaitModal" class="modal fade">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">

View File

@ -1,113 +0,0 @@
<html lang="en">
<!DOCTYPE html>
<head>
<title>8bitworkshop Pixel Editor</title>
<style type="text/css" media="screen">
body {
overflow: hidden !important;
font-size: 11px;
}
.thumbdiv {
}
.fcontainer
{
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
height: 100vh;
}
.fitem
{
background-color: #f3f2ef;
border-radius: 3px;
width: 200px;
height: 100px;
}
</style>
<link rel="stylesheet" href="css/ui.css">
</head>
<body>
<div id="controls_top">
<span id="palette_group" class="palette_group">
</span>
<span style="float:right">
<button id="btn_cancel" type="submit" title="Cancel">Discard <span class="glyphicon glyphicon-remove" aria-hidden="true"></span></button>
<button id="btn_saveandclose" type="submit" title="Save and Close">Save and Close <span class="glyphicon glyphicon-save" aria-hidden="true"></span></button>
</span>
</div>
<div id="notebook">
<div style="width:60%;height:100%;position:absolute;left:0">
<div id="maineditor" class="fcontainer">
</div>
</div>
<div style="width:40%;height:100%;position:absolute;right:0">
<div id="thumbnaildiv" class="fcontainer">
</div>
</div>
</div>
<script src="jquery/jquery-3.3.1.min.js"></script>
<link rel="stylesheet" href="bootstrap/css/bootstrap.min.css">
<script src="bootstrap/js/bootstrap.min.js"></script>
<script src="FileSaver.js/FileSaver.min.js"></script>
<script>
var exports = {};
function require(modname) {
if (modname == 'jquery') return $;
else if (modname.startsWith('.')) return exports;
else { console.log("Unknown require()", modname); return exports; }
}
</script>
<script src="gen/util.js"></script>
<script src="gen/pixed/pixeleditor.js"></script>
<script>
if (window.self === window.top) {
/*
var datastr = "{ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, { 0x7e,0x81,0x95,0xb1,0xb1,0x95,0x81,0x7e }, { 0x7e,0xff,0xeb,0xcf,0xcf,0xeb,0xff,0x7e }, { 0x0e,0x1f,0x3f,0x7e,0x3f,0x1f,0x0e,0x00 }, { 0x08,0x1c,0x3e,0x7f,0x3e,0x1c,0x08,0x00 }, { 0x38,0x3a,0x9f,0xff,0x9f,0x3a,0x38,0x00 }, { 0x10,0x38,0xbc,0xff,0xbc,0x38,0x10,0x00 }, { 0x00,0x00,0x18,0x3c,0x3c,0x18,0x00,0x00 }, { 0xff,0xff,0xe7,0xc3,0xc3,0xe7,0xff,0xff }, { 0x00,0x3c,0x66,0x42,0x42,0x66,0x3c,0x00 }";
var fmt = {w:8,h:8,bpp:1,count:8};
var palette = [0xff000000, 0xffffffff];
*/
var paldatastr = " 0x00, 0x03, 0x19, 0x50, 0x52, 0x07, 0x1f, 0x37, 0xe0, 0xa4, 0xfd, 0xff, 0x38, 0x70, 0x7f, 0xf8, ";
var fmt = {w:14,h:16,bpp:4,brev:1,count:128};
var datastr = "0x00,0x00,0xef,0xef,0xe0,0x00,0x00, 0x00,0xee,0xee,0xfe,0xee,0xe0,0x00, 0x0e,0xed,0xef,0xef,0xed,0xee,0x00, 0x0e,0xee,0xdd,0xdd,0xde,0xee,0x00, 0x0e,0xee,0xed,0xde,0xee,0xee,0x00, 0x00,0xee,0xee,0xde,0xee,0xe0,0x00, 0x00,0xee,0xee,0xde,0xee,0xe0,0x00, 0x00,0x00,0xed,0xdd,0xe0,0x00,0x0d, 0xdd,0xdd,0xee,0xee,0xed,0xdd,0xd0, 0x0d,0xee,0xee,0xee,0xee,0xee,0x00, 0x0e,0xe0,0xee,0xee,0xe0,0xee,0x00, 0x0e,0xe0,0xee,0xee,0xe0,0xee,0x00, 0x0e,0xe0,0xdd,0xdd,0xd0,0xde,0x00, 0x0d,0x00,0xee,0x0e,0xe0,0x0d,0x00, 0x00,0x00,0xed,0x0e,0xe0,0x00,0x00, 0x00,0x0d,0xdd,0x0d,0xdd,0x00,0x18,";
/*
var datastr = "$00,0xfe,0x82,0x82,0x82,0xfe,0xfe,0x00,0x00,0x00,0xfe,0xfe,0xc0,0x00,0x00,0x00,0x00,0xf2,0xf2,0x92,0x92,0x9e,0x9e,0x00,0x00,0xfe,0xfe,0x92,0x92,0x82,0x00,0x00,0x08,0xfe,0xfe,0x88,0x88,0xf8,0xf8,0x00,0x00,0x9e,0x9e,0x92,0x92,0xf2,0xf2,0x00,0x00,0x9e,0x92,0x92,0x92,0xfe,0xfe,0x00,0x00,0xf0,0xf0,0x9e,0x9e,0x80,0x80,0x00,0x00,0xfe,0x92,0x92,0x92,0xfe,0xfe,0x00,0x00,0xfe,0x92,0x92,0x92,0xf2,0xf0,0x00,0x00,0xfe,0xc8,0x88,0x88,0xfe,0xfe,0x00,0x00,0xee,0x92,0x92,0x92,0xfe,0xfe,0x00,0x00,0x82,0x82,0x82,0x86,0xfe,0xfe,0x00,0x00,0xfc,0x86,0x82,0x82,0xfe,0xfe,0x00,0x00,0x82,0x92,0x92,0x92,0xfe,0xfe,0x00,0x00,0x80,0x90,0x90,0x90,0xfe,0xfe,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xc8,0x88,0x88,0xfe,0xfe,0x00,0x00,0xee,0x92,0x92,0x92,0xfe,0xfe,0x00,0x00,0x82,0x82,0x82,0x86,0xfe,0xfe,0x00,0x00,0xfc,0x86,0x82,0x82,0xfe,0xfe,0x00,0x00,0x82,0x92,0x92,0x92,0xfe,0xfe,0x00,0x80,0x90,0x90,0x90,0x90,0xfe,0xfe,0x00,0x00,0x9e,0x92,0x82,0x82,0xfe,0xfe,0x00,0xfe,0xfe,0x10,0x10,0x10,0xfe,0xfe,0x00,0x00,0x00,0xbe,0xbe,0x00,0x00,0x00,0x00,0xfc,0xfe,0x06,0x02,0x02,0x02,0x00,0x00,0x00,0x82,0x44,0x28,0x18,0xfe,0xfe,0x00,0x02,0x02,0x02,0x06,0xfe,0xfe,0x00,0x00,0xfe,0x40,0x20,0x18,0x20,0xfe,0xfe,0x00,0xfe,0x0c,0x08,0x10,0x20,0xfe,0xfe,0x00,0xfe,0x82,0x82,0x82,0x86,0xfe,0xfe,0x00,0x00,0xfe,0x82,0x82,0x82,0xfe,0xfe,0x00,0x00,0x00,0xfe,0xfe,0xc0,0x00,0x00,0x00,0x00,0xf2,0xf2,0x92,0x92,0x9e,0x9e,0x00,0x00,0xfe,0xfe,0x92,0x92,0x82,0x00,0x00,0x08,0xfe,0xfe,0x88,0x88,0xf8,0xf8,0x00,0x00,0x9e,0x9e,0x92,0x92,0xf2,0xf2,0x00,0x00,0x9e,0x92,0x92,0x92,0xfe,0xfe,0x00,0x00,0xf0,0xf0,0x9e,0x9e,0x80,0x80,0x00,0x00,0xfe,0x92,0x92,0x92,0xfe,0xfe,0x00,0x00,0xfe,0x92,0x92,0x92,0xf2,0xf0,0x00,0x00,0xfe,0xc8,0x88,0x88,0xfe,0xfe,0x00,0x00,0xee,0x92,0x92,0x92,0xfe,0xfe,0x00,0x00,0x82,0x82,0x82,0x86,0xfe,0xfe,0x00,0x00,0xfc,0x86,0x82,0x82,0xfe,0xfe,0x00,0x00,0x82,0x92,0x92,0x92,0xfe,0xfe,0x00,0x00,0x80,0x90,0x90,0x90,0xfe,0xfe,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xfe,0xc8,0x88,0x88,0xfe,0xfe,0x00,0x00,0xee,0x92,0x92,0x92,0xfe,0xfe,0x00,0x00,0x82,0x82,0x82,0x86,0xfe,0xfe,0x00,0x00,0xfc,0x86,0x82,0x82,0xfe,0xfe,0x00,0x00,0x82,0x92,0x92,0x92,0xfe,0xfe,0x00,0x80,0x90,0x90,0x90,0x90,0xfe,0xfe,0x00,0x00,0x9e,0x92,0x82,0x82,0xfe,0xfe,0x00,0xfe,0xfe,0x10,0x10,0x10,0xfe,0xfe,0x00,0x00,0x00,0xbe,0xbe,0x00,0x00,0x00,0x00,0xfc,0xfe,0x06,0x02,0x02,0x02,0x00,0x00,0x00,0x82,0x44,0x28,0x18,0xfe,0xfe,0x00,0x02,0x02,0x02,0x06,0xfe,0xfe,0x00,0x00,0xfe,0x40,0x20,0x18,0x20,0xfe,0xfe,0x00,0xfe,0x0c,0x08,0x10,0x20,0xfe,0xfe,0x00,0xfe,0x82,0x82,0x82,0x86,0xfe,0xfe,0x00,";
var fmt = {w:8,h:8,bpp:1,np:2,pofs:0x100,count:32,xform:"rotate(90deg) scaleX(-1)"};
var paldatastr = "0x00,0x30,0x4f,0xff,0x00,0xf0,0xc0,0x7f, 0x00,0xc0,0x04,0x1f,0x00,0xd0,0xd0,0x0f, 0x00,0xc0,0xc0,0x0f,0x00,0x04,0x04,0x0f, 0x00,0xff,0x0f,0xf0,0x00,0x7f,0x0f,0xdf,";
*/
pixelEditorReceiveMessage({data:{fmt:fmt,bytestr:datastr,palfmt:{pal:332,n:16},palstr:paldatastr}});
console.log(postToParentWindow({save:true}));
}
//
window.addEventListener("message", pixelEditorReceiveMessage, false);
window.addEventListener("resize", pixelEditorResize, false);
window.addEventListener("keypress", pixelEditorKeypress, false);
$("#btn_cancel").click(function(e) {
if (confirm("Sure you want to cancel and discard?")) {
postToParentWindow({close:true});
}
});
$("#btn_saveandclose").click(function(e) {
try {
postToParentWindow({close:true,save:true});
} catch (ex) {
alert("Could not convert to bytes: " + ex);
throw ex;
}
});
</script>
</body>
</html>

View File

@ -1,16 +1,29 @@
#include "neslib.h"
#include "nes.h"
#include <stdlib.h>
#define NES_MAPPER 2 // UxROM mapper
#define NES_CHR_BANKS 0 // CHR RAM
void set_pixel(byte x, byte y, byte color) {
// compute pattern table address
word a = (x/8)*16 + ((y&63)/8)*(16*32) + (y&7);
#define PPU_IS_ON() (PPU.mask & (MASK_BG|MASK_SPR))
void monobitmap_split() {
// split screen at line 128
split(0,0);
PPU.control = PPU.control ^ 0x10; // bg bank 1
}
void monobitmap_set_pixel(byte x, byte y, byte color) {
byte b;
// compute pattern table address
word a = (x/8)*16 | ((y&63)/8)*(16*32) | (y&7);
if (y & 64) a |= 8;
if (y & 128) a |= 0x1000;
// if PPU is active, wait for next frame
if (PPU_IS_ON()) {
ppu_wait_nmi();
}
// read old byte
vram_adr(a);
vram_read(&b, 1);
@ -22,41 +35,58 @@ void set_pixel(byte x, byte y, byte color) {
// write new byte
vram_adr(a);
vram_put(b);
// if PPU is active, reset PPU addr and split screen
if (PPU_IS_ON()) {
vram_adr(0);
monobitmap_split();
}
}
void monobitmap_draw_line(int x0, int y0, int x1, int y1, byte color) {
int dx = abs(x1-x0);
int sx = x0<x1 ? 1 : -1;
int dy = abs(y1-y0);
int sy = y0<y1 ? 1 : -1;
int err = (dx>dy ? dx : -dy)>>1;
int e2;
for(;;) {
monobitmap_set_pixel(x0, y0, color);
if (x0==x1 && y0==y1) break;
e2 = err;
if (e2 > -dx) { err -= dy; x0 += sx; }
if (e2 < dy) { err += dx; y0 += sy; }
}
}
// write values 0..255
void vram_put_256inc() {
void monobitmap_put_256inc() {
word i;
for (i=0; i<256; i++)
vram_put(i);
}
void vram_put_attrib() {
void monobitmap_put_attrib() {
vram_fill(0x00, 0x10); // first palette
vram_fill(0x55, 0x10); // second palette
}
void setup_monobitmap() {
void monobitmap_clear() {
// clear pattern table
vram_adr(0x0);
vram_fill(0x0, 0x2000);
}
void monobitmap_setup() {
monobitmap_clear();
// setup nametable A and B
vram_adr(NAMETABLE_A);
vram_put_256inc();
vram_put_256inc();
vram_put_256inc();
vram_put_256inc();
vram_adr(NAMETABLE_B);
vram_put_256inc();
vram_put_256inc();
vram_put_256inc();
vram_put_256inc();
monobitmap_put_256inc();
monobitmap_put_256inc();
monobitmap_put_256inc();
monobitmap_put_256inc();
vram_adr(NAMETABLE_A + 0x3c0);
vram_put_attrib();
vram_put_attrib();
vram_adr(NAMETABLE_B + 0x3c0);
vram_put_attrib();
vram_put_attrib();
monobitmap_put_attrib();
monobitmap_put_attrib();
bank_bg(0);
// setup sprite 0
oam_clear();
@ -68,7 +98,7 @@ void setup_monobitmap() {
vram_fill(0xff, 0x10);
}
/*{pal:"nes"}*/
/*{pal:"nes",layout:"nes"}*/
const byte MONOBMP_PALETTE[16] = {
0x03,
0x30, 0x03, 0x30, 0x00,
@ -77,29 +107,44 @@ const byte MONOBMP_PALETTE[16] = {
0x03, 0x30, 0x30
};
void demo() {
void monobitmap_demo() {
byte i;
for (i=16; i<220; i++) {
set_pixel(i,16,1);
set_pixel(16,i,1);
set_pixel(i,220,1);
set_pixel(220,i,1);
set_pixel(i,i,1);
static const byte x1 = 16;
static const byte y1 = 16;
static const byte x2 = 240;
static const byte y2 = 208;
for (i=x1; i<=x2; i++) {
monobitmap_set_pixel(i,y1,1);
monobitmap_set_pixel(i,y2,1);
}
for (i=y1; i<=y2; i++) {
monobitmap_set_pixel(x1,i,1);
monobitmap_set_pixel(x2,i,1);
}
for (i=x1; i<x2; i+=16) {
monobitmap_draw_line(x1,y1,i,y2,1);
}
for (i=y1; i<=y2; i+=16) {
monobitmap_draw_line(x1,y1,x2,i,1);
}
}
void main(void)
{
byte ctrl;
setup_monobitmap();
monobitmap_setup();
pal_bg(MONOBMP_PALETTE);
demo();
ppu_on_all();//enable rendering
monobitmap_demo();
ppu_on_all();
while (!pad_trigger(0)) {
ppu_wait_nmi();
monobitmap_split();
}
ppu_off();
monobitmap_setup();
ppu_on_all();
monobitmap_demo();
while(1) {
ppu_wait_nmi();
// split screen at line 128
ctrl = PPU.control;
split(0,0);
PPU.control = ctrl ^ 0x10; // bg bank 1
monobitmap_split();
}
}

View File

@ -56,215 +56,6 @@ type PixelEditorMessage = {
palstr : string
};
export function PixelEditor(parentDiv:HTMLElement,
fmt:PixelEditorImageFormat,
palette:Uint32Array,
initialData:Uint32Array,
thumbnails?) {
var width = fmt.w;
var height = fmt.h;
function createCanvas() {
var c = document.createElement('canvas');
c.width = width;
c.height = height;
if (fmt.xform) c.style.transform = fmt.xform;
c.classList.add("pixels");
c.classList.add("pixelated");
//canvas.tabIndex = "-1"; // Make it focusable
$(parentDiv).empty().append(c);
return c;
}
function updateImage() {
ctx.putImageData(pixdata, 0, 0);
}
function commit() {
if (!thumbnails) return;
for (var i=0; i<thumbnails.length; i++) {
thumbnails[i].copyImageFrom(this);
}
initialData.set(this.getImageColors());
}
this.copyImageFrom = function(src) {
pixints.set(src.getImageData());
updateImage();
}
this.getImageData = function() { return pixints.slice(0); }
function fitCanvas() {
pixcanvas.style.height = '50%'; // TODO?
return;
}
this.resize = fitCanvas;
var pixcanvas = createCanvas();
var ctx = pixcanvas.getContext('2d');
var pixdata = ctx.createImageData(width, height);
var pixints = new Uint32Array(pixdata.data.buffer);
for (var i=0; i<pixints.length; i++) {
pixints[i] = initialData ? palette[initialData[i]] : palette[0];
}
this.canvas = pixcanvas;
updateImage();
this.createPaletteButtons = function() {
var span = $("#palette_group").empty();
for (var i=0; i<palette.length; i++) {
var btn = $('<button class="palbtn">');
var rgb = palette[i] & 0xffffff;
var color = "#" + hex(rgb2bgr(rgb), 6);
btn.click(this.setCurrentColor.bind(this, i));
btn.attr('id', 'palcol_' + i);
btn.css('backgroundColor', color).text(i.toString(16));
if ((rgb & 0x808080) != 0x808080) { btn.css('color', 'white'); }
span.append(btn);
}
this.setCurrentColor(1);
}
function getPixelByOffset(ofs) {
var oldrgba = pixints[ofs] & 0xffffff;
for (var i=0; i<palette.length; i++) {
if (oldrgba == (palette[i] & 0xffffff)) return i;
}
return 0;
}
function getPixel(x, y) {
var ofs = x+y*width;
return getPixelByOffset(ofs);
}
function setPixel(x, y, col) {
if (x < 0 || x >= width || y < 0 || y >= height) return;
var ofs = x+y*width;
var oldrgba = pixints[ofs];
var rgba = palette[col];
if (oldrgba != rgba) {
pixints[ofs] = rgba;
updateImage();
}
}
this.getImageColors = function() {
var pixcols = new Uint8Array(pixints.length);
for (var i=0; i<pixints.length; i++)
pixcols[i] = getPixelByOffset(i);
return pixcols;
}
///
this.makeEditable = function() {
var curpalcol = -1;
setCurrentColor(1);
function getPositionFromEvent(e) {
var x = Math.floor(e.offsetX * width / pxls.width());
var y = Math.floor(e.offsetY * height / pxls.height());
return {x:x, y:y};
}
function setCurrentColor(col) {
if (curpalcol != col) {
if (curpalcol >= 0)
$("#palcol_" + curpalcol).removeClass('selected');
curpalcol = col;
$("#palcol_" + col).addClass('selected');
}
}
this.setCurrentColor = setCurrentColor;
var dragcol = 1;
var dragging = false;
var pxls = $(pixcanvas);
pxls.mousedown( (e) => {
var pos = getPositionFromEvent(e);
dragcol = getPixel(pos.x, pos.y) == curpalcol ? 0 : curpalcol;
setPixel(pos.x, pos.y, curpalcol);
dragging = true;
// TODO: pixcanvas.setCapture();
})
.mousemove( (e) => {
var pos = getPositionFromEvent(e);
if (dragging) {
setPixel(pos.x, pos.y, dragcol);
}
})
.mouseup( (e) => {
var pos = getPositionFromEvent(e);
setPixel(pos.x, pos.y, dragcol);
dragging = false;
commit();
// TODO: pixcanvas.releaseCapture();
});
}
function setPixels(p) {
var i = 0;
for (var y=0; y<height; y++) {
for (var x=0; x<width; x++) {
setPixel(x, y, p[i++]);
}
}
}
this.rotate = function(deg) {
console.log("rotate " + deg);
var s1 = Math.sin(deg * Math.PI / 180);
var c1 = Math.cos(deg * Math.PI / 180);
var p = this.getImageColors();
var i = 0;
for (var y=0; y<height; y++) {
for (var x=0; x<width; x++) {
var xx = x + 0.5 - width/2.0;
var yy = y + 0.5 - height/2.0;
var xx2 = xx*c1 - yy*s1 + width/2.0 - 0.5;
var yy2 = yy*c1 + xx*s1 + height/2.0 - 0.5;
var col = getPixel(Math.round(xx2), Math.round(yy2));
p[i++] = col;
}
}
setPixels(p);
commit();
}
this.flipy = function() {
console.log("flipy");
var p = this.getImageColors();
var i = 0;
for (var y=0; y<height; y++) {
for (var x=0; x<width; x++) {
var col = getPixel(x, height-1-y);
p[i++] = col;
}
}
setPixels(p);
commit();
}
this.flipx = function() {
console.log("flipx");
var p = this.getImageColors();
var i = 0;
for (var y=0; y<height; y++) {
for (var x=0; x<width; x++) {
var col = getPixel(width-1-x, y);
p[i++] = col;
}
}
setPixels(p);
commit();
}
}
/////////////////
var pixel_re = /([0#]?)([x$%]|\d'[bh])([0-9a-f]+)/gi;
@ -435,19 +226,6 @@ function convertPaletteBytes(arr:UintArray,r0,r1,g0,g1,b0,b1) : number[] {
return result;
}
export var palette : Uint32Array;
export var paletteSets;
export var paletteSetIndex=0;
export var currentPixelEditor;
export var parentSource;
export var parentOrigin;
export var allimages;
export var currentFormat : PixelEditorImageFormat;
export var currentByteStr : string;
export var currentPaletteStr : string;
export var currentPaletteFmt : PixelEditorPaletteFormat;
export var allthumbs;
export function getPaletteLength(palfmt: PixelEditorPaletteFormat) : number {
var pal = palfmt.pal;
if (typeof pal === 'number') {
@ -488,136 +266,6 @@ function convertPaletteFormat(palbytes:UintArray, palfmt: PixelEditorPaletteForm
return newpalette;
}
export function pixelEditorDecodeMessage(e) {
parentSource = e.source;
parentOrigin = e.origin;
let data : PixelEditorMessage = e.data;
currentFormat = e.data.fmt;
currentPaletteFmt = data.palfmt;
currentPaletteStr = data.palstr;
currentByteStr = convertToHexStatements(data.bytestr);
var words = parseHexWords(currentByteStr);
allimages = convertWordsToImages(words, data.fmt);
var newpalette = [0xff000000, 0xffffffff]; // TODO
if (currentPaletteStr) {
var palbytes = parseHexWords(data.palstr);
newpalette = convertPaletteFormat(palbytes, currentPaletteFmt) || newpalette;
if (currentPaletteFmt.n) {
paletteSets = [];
for (var i=0; i<newpalette.length; i+=currentPaletteFmt.n) {
paletteSets.push(newpalette.slice(i, i+currentPaletteFmt.n));
}
newpalette = paletteSets[paletteSetIndex = 0];
// TODO: swap palettes
}
} else {
var ncols = (currentFormat.bpp || 1) * (currentFormat.np || 1);
switch (ncols) {
case 2:
newpalette = [0xff000000, 0xffff00ff, 0xffffff00, 0xffffffff];
break;
// TODO
}
// TODO: default palette?
}
palette = new Uint32Array(newpalette);
}
function pixelEditorCreateThumbnails(e) {
// create thumbnail for all images
$("#thumbnaildiv").empty();
var parentdiv;
var count = e.data.fmt.count || 1;
allthumbs = [];
for (var i=0; i<count; i++) {
if ((i & 15) == 0) {
parentdiv = $('<div class="thumbdiv">').appendTo("#thumbnaildiv");
}
allthumbs.push(createThumbnailForImage(parentdiv, i));
}
}
function pixelEditorReceiveMessage(e) {
pixelEditorDecodeMessage(e);
pixelEditorCreateThumbnails(e);
// create initial editor
createEditorForImage(0);
}
function createThumbnailForImage(parentdiv, i) {
var span = $('<span class="thumb">');
var thumb = new PixelEditor(span[0] as HTMLElement, currentFormat, palette, allimages[i]);
// double size of canvas thumbnail
thumb.canvas.style.height = currentFormat.h*2+"px";
thumb.canvas.style.width = currentFormat.w*2+"px";
parentdiv.append(span);
span.click(() => { createEditorForImage(i) });
return thumb;
}
function createEditorForImage(i) {
currentPixelEditor = new PixelEditor(document.getElementById('maineditor'), currentFormat, palette, allimages[i], [allthumbs[i]]);
currentPixelEditor.resize();
currentPixelEditor.makeEditable();
currentPixelEditor.createPaletteButtons();
}
function postToParentWindow(data) {
if (data.save) {
var allimgs = [];
for (var i=0; i<allthumbs.length; i++) {
allimgs.push(allthumbs[i].getImageColors());
}
data.bytes = convertImagesToWords(allimgs, currentFormat);
data.bytestr = replaceHexWords(currentByteStr, data.bytes);
}
if (parentSource) parentSource.postMessage(data, "*");
return data;
}
function pixelEditorResize(e) {
if (currentPixelEditor) {
currentPixelEditor.resize();
}
}
function pixelEditorKeypress(e) {
if (!currentPixelEditor) return;
//console.log(e);
var c = e.charCode;
if (c >= 48 && c <= 57) {
currentPixelEditor.setCurrentColor(c-48);
} else if (c >= 97 && c <= 102) {
currentPixelEditor.setCurrentColor(c-97+10);
} else {
switch (e.keyCode) {
case 82: // 'R'
currentPixelEditor.rotate(-90);
break;
case 114: // 'r'
currentPixelEditor.rotate(90);
break;
case 84: // 'T'
currentPixelEditor.rotate(-45);
break;
case 116: // 't'
currentPixelEditor.rotate(45);
break;
}
switch (e.charCode) {
case 104:
currentPixelEditor.flipx();
break;
currentPixelEditor.flipy();
break;
default:
console.log(e);
break;
}
}
}
// TODO: illegal colors?
var PREDEF_PALETTES = {
'nes':[
@ -655,10 +303,11 @@ export abstract class PixNode {
words? : UintArray; // file data
images? : Uint8Array[]; // array of indexed image data
rgbimgs? : Uint32Array[]; // array of rgba imgages
palette? : Uint32Array; // array of rgba
abstract updateLeft(); // update coming from right
abstract updateRight(); // update coming from left
refreshLeft() {
var p : PixNode = this;
while (p) {
@ -693,7 +342,7 @@ abstract class CodeProjectDataNode extends PixNode {
}
export class FileDataNode extends CodeProjectDataNode {
constructor(project:ProjectWindows, fileid:string, data:Uint8Array) {
super();
this.project = project;
@ -702,6 +351,7 @@ export class FileDataNode extends CodeProjectDataNode {
this.words = data;
}
updateLeft() {
this.words = this.right.words;
if (this.project) {
this.project.updateFile(this.fileid, this.words as Uint8Array);
}
@ -723,8 +373,9 @@ export class TextDataNode extends CodeProjectDataNode {
this.text = text;
this.start = start;
this.end = end;
}
}
updateLeft() {
this.words = this.right.words;
// TODO: reload editors?
var datastr = this.text.substring(this.start, this.end);
datastr = replaceHexWords(datastr, this.words);
@ -760,7 +411,11 @@ export class Mapper extends PixNode {
fmt : PixelEditorImageFormat;
words : UintArray;
images : Uint8Array[];
constructor(fmt) {
super();
this.fmt = fmt;
}
updateLeft() {
this.images = this.right.images;
this.words = convertImagesToWords(this.images, this.fmt);
@ -778,7 +433,7 @@ class RGBAPalette {
this.palcols = palcols;
}
indexOf(rgba : number) : number {
return this.palcols.find(rgba);
return this.palcols.indexOf(rgba);
}
}
@ -787,12 +442,12 @@ export class Palettizer extends PixNode {
images : Uint8Array[];
rgbimgs : Uint32Array[];
palette : Uint32Array;
ncolors : number;
context : EditorContext;
paloptions : SelectablePalette[];
palindex : number = 0;
// TODO: control to select palette for bitmaps
constructor(context:EditorContext, fmt:PixelEditorImageFormat) {
@ -863,6 +518,10 @@ export class PaletteFormatToRGB extends PixNode {
palfmt : PixelEditorPaletteFormat;
layout : PixelEditorPaletteLayout;
constructor(palfmt) {
super();
this.palfmt = palfmt;
}
updateLeft() {
//TODO
}
@ -889,7 +548,7 @@ export abstract class Compositor extends PixNode {
images : Uint8Array[]; // output (1 image)
width : number;
height : number;
context : EditorContext;
tileoptions : SelectableTilemap[];
tileindex : number = 0;
@ -922,7 +581,7 @@ export class MetaspriteCompositor extends Compositor {
}
updateLeft() {
// TODO
}
}
updateRight() {
this.updateRefs();
this.width = 16; // TODO
@ -945,7 +604,7 @@ export class NESNametableConverter extends Compositor {
}
updateLeft() {
// TODO
}
}
updateRight() {
this.words = this.left.words;
this.updateRefs();
@ -986,51 +645,12 @@ export class NESNametableConverter extends Compositor {
///// UI CONTROLS
export class Viewer { // TODO: make PixNode
width : number;
height : number;
canvas : HTMLCanvasElement;
ctx : CanvasRenderingContext2D;
pixdata : ImageData;
recreate() {
this.canvas = this.newCanvas();
this.pixdata = this.ctx.createImageData(this.width, this.height);
}
createWith(pv : Viewer) {
this.width = pv.width;
this.height = pv.height;
this.pixdata = pv.pixdata;
this.canvas = this.newCanvas();
}
newCanvas() : HTMLCanvasElement {
var c = document.createElement('canvas');
c.width = this.width;
c.height = this.height;
//if (fmt.xform) c.style.transform = fmt.xform;
c.classList.add("pixels");
c.classList.add("pixelated");
this.ctx = c.getContext('2d');
return c;
}
updateImage(imdata : Uint32Array) {
if (imdata) {
new Uint32Array(this.pixdata.data.buffer).set(imdata);
}
this.ctx.putImageData(this.pixdata, 0, 0);
}
}
export class ImageChooser {
rgbimgs : Uint32Array[];
width : number;
height : number;
recreate(parentdiv:JQuery, onclick) {
var agrid = $('<div class="asset_grid"/>'); // grid (or 1) of preview images
parentdiv.empty().append(agrid);
@ -1059,7 +679,7 @@ export class ImageChooser {
span = null;
}
});
}
}
}
function newDiv(parent?, cls? : string) {
@ -1074,6 +694,7 @@ export class CharmapEditor extends PixNode {
context;
parentdiv;
fmt;
chooser;
constructor(context:EditorContext, parentdiv:JQuery, fmt:PixelEditorImageFormat) {
super();
@ -1081,27 +702,25 @@ export class CharmapEditor extends PixNode {
this.parentdiv = parentdiv;
this.fmt = fmt;
}
updateLeft() { } // TODO
updateLeft() {
}
updateRight() {
this.rgbimgs = this.left.rgbimgs;
var adual = newDiv(this.parentdiv.empty(), "asset_dual"); // contains grid and editor
var agrid = newDiv(adual);
var aeditor = newDiv(adual, "asset_editor").hide(); // contains editor, when selected
// add image chooser grid
var chooser = new ImageChooser();
var chooser = this.chooser = new ImageChooser();
chooser.rgbimgs = this.rgbimgs;
chooser.width = this.fmt.w || 1;
chooser.height = this.fmt.h || 1;
chooser.recreate(agrid, (index, viewer) => {
var escale = Math.ceil(192 / this.fmt.w);
var editview = new Viewer();
editview.createWith(viewer);
editview.updateImage(null);
editview.canvas.style.width = (viewer.width*escale)+'px'; // TODO
aeditor.empty().append(editview.canvas);
var editview = this.createEditor(aeditor, viewer, escale);
this.context.setCurrentEditor(aeditor, $(viewer.canvas));
this.rgbimgs[index] = viewer.rgbdata;
});
// add palette selector
// TODO: only view when editing?
@ -1122,5 +741,191 @@ export class CharmapEditor extends PixNode {
}
}
createEditor(aeditor : JQuery, viewer : Viewer, escale : number) : PixEditor {
var im = new PixEditor();
im.createWith(viewer);
im.updateImage();
im.canvas.style.width = (viewer.width*escale)+'px'; // TODO
im.makeEditable(this, aeditor, this.left.palette);
return im;
}
}
export class Viewer {
width : number;
height : number;
canvas : HTMLCanvasElement;
ctx : CanvasRenderingContext2D;
imagedata : ImageData;
rgbdata : Uint32Array;
peerviewers : Viewer[];
recreate() {
this.canvas = this.newCanvas();
this.imagedata = this.ctx.createImageData(this.width, this.height);
this.rgbdata = new Uint32Array(this.imagedata.data.buffer);
this.peerviewers = [this];
}
createWith(pv : Viewer) {
this.width = pv.width;
this.height = pv.height;
this.imagedata = pv.imagedata;
this.rgbdata = pv.rgbdata;
this.canvas = this.newCanvas();
this.peerviewers = [this, pv];
}
newCanvas() : HTMLCanvasElement {
var c = document.createElement('canvas');
c.width = this.width;
c.height = this.height;
//if (fmt.xform) c.style.transform = fmt.xform;
c.classList.add("pixels");
c.classList.add("pixelated");
this.ctx = c.getContext('2d');
return c;
}
updateImage(imdata? : Uint32Array) {
if (imdata) {
this.rgbdata.set(imdata);
}
for (let v of this.peerviewers) {
v.ctx.putImageData(this.imagedata, 0, 0);
}
}
}
class PixEditor extends Viewer {
left : PixNode;
palette : Uint32Array;
curpalcol : number = -1;
currgba : number;
palbtns : JQuery[];
getPositionFromEvent(e) {
var x = Math.floor(e.offsetX * this.width / $(this.canvas).width());
var y = Math.floor(e.offsetY * this.height / $(this.canvas).height());
return {x:x, y:y};
}
setPaletteColor(col: number) {
col &= this.palette.length-1;
if (this.curpalcol != col) {
if (this.curpalcol >= 0)
this.palbtns[this.curpalcol].removeClass('selected');
this.curpalcol = col;
this.currgba = this.palette[col & this.palette.length-1];
this.palbtns[col].addClass('selected');
}
}
makeEditable(leftnode:PixNode, aeditor:JQuery, palette:Uint32Array) {
this.left = leftnode;
this.palette = palette;
var dragcol;
var dragging = false;
var pxls = $(this.canvas);
pxls.mousedown( (e) => {
var pos = this.getPositionFromEvent(e);
dragcol = this.getPixel(pos.x, pos.y) == this.currgba ? this.palette[0] : this.currgba;
this.setPixel(pos.x, pos.y, this.currgba);
dragging = true;
// TODO: pixcanvas.setCapture();
})
.mousemove( (e) => {
var pos = this.getPositionFromEvent(e);
if (dragging) {
this.setPixel(pos.x, pos.y, dragcol);
}
})
.mouseup( (e) => {
var pos = this.getPositionFromEvent(e);
this.setPixel(pos.x, pos.y, dragcol);
dragging = false;
this.commit();
// TODO: pixcanvas.releaseCapture();
});
aeditor.empty();
aeditor.append(this.canvas);
aeditor.append(this.createPaletteButtons());
this.setPaletteColor(1);
}
getPixel(x, y) {
var ofs = x+y*this.width;
return this.rgbdata[ofs];
}
setPixel(x, y, rgba) {
if (x < 0 || x >= this.width || y < 0 || y >= this.height) return;
var ofs = x+y*this.width;
var oldrgba = this.rgbdata[ofs];
if (oldrgba != rgba) {
this.rgbdata[ofs] = rgba;
this.updateImage();
}
}
createPaletteButtons() {
this.palbtns = [];
var span = $(document.createElement('div'));
for (var i=0; i<this.palette.length; i++) {
var btn = $(document.createElement('button')).addClass('palbtn');
var rgb = this.palette[i] & 0xffffff;
var color = "#" + hex(rgb2bgr(rgb), 6);
btn.click(this.setPaletteColor.bind(this, i));
btn.css('backgroundColor', color).text(i.toString(16));
btn.css('color', (rgb & 0x008000) ? 'black' : 'white');
span.append(btn);
this.palbtns.push(btn);
}
return span;
}
commit() {
this.left.refreshLeft();
}
remapPixels(mapfn : (x:number,y:number) => number) {
var i = 0;
var pixels = new Uint32Array(this.rgbdata.length);
for (var y=0; y<this.height; y++) {
for (var x=0; x<this.width; x++) {
pixels[i] = mapfn(x, y);
i++;
}
}
this.rgbdata.set(pixels);
this.commit();
}
rotate(deg:number) {
var s1 = Math.sin(deg * Math.PI / 180);
var c1 = Math.cos(deg * Math.PI / 180);
this.remapPixels((x,y) => {
var xx = x + 0.5 - this.width/2.0;
var yy = y + 0.5 - this.height/2.0;
var xx2 = xx*c1 - yy*s1 + this.width/2.0 - 0.5;
var yy2 = yy*c1 + xx*s1 + this.height/2.0 - 0.5;
return this.getPixel(xx, yy);
});
}
flipx() {
this.remapPixels((x,y) => {
return this.getPixel(this.width-1-x, y);
});
}
flipy() {
this.remapPixels((x,y) => {
return this.getPixel(x, this.height-1-y);
});
}
}

View File

@ -967,12 +967,6 @@ function _fastestFrameRate() {
setFrameRateUI(60);
}
function _openBitmapEditor() {
var wnd = projectWindows.getActive();
if (wnd && wnd.openBitmapEditorAtCursor)
wnd.openBitmapEditorAtCursor();
}
function traceTiming() {
projectWindows.refresh(false);
var wnd = projectWindows.getActive();
@ -1112,7 +1106,6 @@ function setupDebugControls(){
$("#dbg_timing").click(traceTiming).show();
}
$("#disassembly").hide();
$("#dbg_bitmap").click(_openBitmapEditor);
$(".dropdown-menu").collapse({toggle: false});
$("#item_new_file").click(_createNewFile);
$("#item_upload_file").click(_uploadNewFile);

View File

@ -21,7 +21,6 @@ export interface ProjectView {
getCursorPC?() : number;
getSourceFile?() : SourceFile;
setGutterBytes?(line:number, s:string) : void;
openBitmapEditorAtCursor?() : void;
markErrors?(errors:WorkerError[]) : void;
clearErrors?() : void;
setTimingResult?(result:CodeAnalyzer) : void;
@ -349,86 +348,12 @@ export class SourceEditor implements ProjectView {
}
return -1;
}
replaceSelection(start:number, end:number, text:string) {
this.editor.setSelection(end, start);
this.editor.replaceSelection(text);
}
// bitmap editor (TODO: refactor)
openBitmapEditorWithParams(fmt, bytestr, palfmt, palstr) {
var handleWindowMessage = (e) => {
//console.log("window message", e.data);
if (e.data.bytes) {
this.editor.replaceSelection(e.data.bytestr);
}
if (e.data.close) {
$("#pixeditback").hide();
}
e.target.removeEventListener("message", handleWindowMessage);
}
$("#pixeditback").show();
window.addEventListener("message", handleWindowMessage, false); // TODO: remove listener
window['pixeditframe'].contentWindow.postMessage({fmt:fmt, bytestr:bytestr, palfmt:palfmt, palstr:palstr}, '*');
}
lookBackwardsForJSONComment(line, req) {
var re = /[/;][*;]([{].+[}])[*;][/;]/;
while (--line >= 0) {
var s = this.editor.getLine(line);
var m = re.exec(s);
if (m) {
var jsontxt = m[1].replace(/([A-Za-z]+):/g, '"$1":'); // fix lenient JSON
var obj = JSON.parse(jsontxt);
if (obj[req]) {
var start = {obj:obj, line:line, ch:s.indexOf(m[0])+m[0].length};
var line0 = line;
var pos0 = start.ch;
line--;
while (++line < this.editor.lineCount()) {
var l = this.editor.getLine(line);
var endsection;
if (platform_id == 'verilog')
endsection = l.indexOf('end') >= pos0;
else if (s.startsWith(';;'))
endsection = l.indexOf(';;') >= pos0;
else
endsection = l.indexOf(';') >= pos0;
if (endsection) {
var end = {line:line, ch:this.editor.getLine(line).length};
return {obj:obj, start:start, end:end};
}
pos0 = 0;
}
line = line0;
}
}
}
}
openBitmapEditorAtCursor() {
if ($("#pixeditback").is(":visible")) {
$("#pixeditback").hide(250);
return;
}
var line = this.editor.getCursor().line + 1;
var data = this.lookBackwardsForJSONComment(this.getCurrentLine(), 'w');
if (data && data.obj && data.obj.w>0 && data.obj.h>0) {
var paldata = this.lookBackwardsForJSONComment(data.start.line-1, 'pal');
var palbytestr;
if (paldata) {
palbytestr = this.editor.getRange(paldata.start, paldata.end);
paldata = paldata.obj;
}
this.editor.setSelection(data.end, data.start);
this.openBitmapEditorWithParams(data.obj, this.editor.getSelection(), paldata, palbytestr);
} else {
alert("To edit graphics, move cursor to a constant array preceded by a comment in the format:\n\n/*{w:,h:,bpp:,count:...}*/\n\n(See code examples)");
}
}
}
///
@ -679,7 +604,7 @@ export class MemoryView implements ProjectView {
if (sym) s += ' ' + sym;
return s;
}
readAddress(n : number) {
return platform.readAddress(n);
}
@ -973,12 +898,12 @@ export class AssetEditorView implements ProjectView, pixed.EditorContext {
this.maindiv = newDiv(parent, "vertical-scroll");
return this.maindiv[0];
}
clearAssets() {
this.rootnodes = [];
this.deferrednodes = [];
}
registerAsset(type:string, node:pixed.PixNode, deferred:boolean) {
this.rootnodes.push(node);
if (deferred) {
@ -987,7 +912,7 @@ export class AssetEditorView implements ProjectView, pixed.EditorContext {
node.refreshRight();
}
}
getPalettes(matchlen : number) : pixed.SelectablePalette[] {
var result = [];
this.rootnodes.forEach((node) => {
@ -1039,7 +964,7 @@ export class AssetEditorView implements ProjectView, pixed.EditorContext {
});
return result;
}
setCurrentEditor(div : JQuery, editing : JQuery) {
if (this.cureditordiv != div) {
if (this.cureditordiv) {
@ -1060,7 +985,7 @@ export class AssetEditorView implements ProjectView, pixed.EditorContext {
this.cureditelem.addClass('asset_editing');
}
}
scanFileTextForAssets(id : string, data : string) {
// scan file for assets
// /*{json}*/ or ;;{json};;
@ -1111,7 +1036,7 @@ export class AssetEditorView implements ProjectView, pixed.EditorContext {
}
return result;
}
addPaletteEditorViews(parentdiv:JQuery, words, palette, layout, allcolors, callback) {
var adual = $('<div class="asset_dual"/>').appendTo(parentdiv);
var aeditor = $('<div class="asset_editor"/>').hide(); // contains editor, when selected
@ -1157,12 +1082,11 @@ export class AssetEditorView implements ProjectView, pixed.EditorContext {
}
});
}
addPixelEditor(parentdiv:JQuery, firstnode:pixed.PixNode, fmt:pixed.PixelEditorImageFormat) {
// data -> pixels
var mapper = new pixed.Mapper();
fmt.xform = 'scale(2)';
mapper.fmt = fmt;
var mapper = new pixed.Mapper(fmt);
// TODO: rotate node?
firstnode.addRight(mapper);
// pixels -> RGBA
@ -1174,8 +1098,7 @@ export class AssetEditorView implements ProjectView, pixed.EditorContext {
addPaletteEditor(parentdiv:JQuery, firstnode:pixed.PixNode, palfmt?) {
// palette -> RGBA
var pal2rgb = new pixed.PaletteFormatToRGB();
pal2rgb.palfmt = palfmt;
var pal2rgb = new pixed.PaletteFormatToRGB(palfmt);
firstnode.addRight(pal2rgb);
// TODO: refresh twice?
firstnode.refreshRight();
@ -1190,7 +1113,7 @@ export class AssetEditorView implements ProjectView, pixed.EditorContext {
firstnode.refreshLeft();
});
}
refreshAssetsInFile(fileid : string, data : FileData) : number {
let nassets = 0;
let filediv = $('#'+this.getFileDivId(fileid)).empty();
@ -1243,33 +1166,34 @@ export class AssetEditorView implements ProjectView, pixed.EditorContext {
}
return nassets;
}
getFileDivId(id : string) {
return '__asset__' + safeident(id);
}
// TODO: recreate editors when refreshing
refresh() {
this.maindiv.empty();
this.clearAssets();
current_project.iterateFiles((id, data) => {
var divid = this.getFileDivId(id);
var filediv = newDiv(this.maindiv, 'asset_file');
var header = newDiv(filediv, 'asset_file_header').text(id);
var body = newDiv(filediv).attr('id',divid);
try {
var nassets = this.refreshAssetsInFile(id, data);
if (nassets == 0) filediv.hide();
} catch (e) {
console.log(e);
filediv.text(e+""); // TODO: error msg?
}
});
this.deferrednodes.forEach((node) => { node.refreshRight(); });
this.deferrednodes = [];
refresh(moveCursor : boolean) {
if (moveCursor) {
this.maindiv.empty();
this.clearAssets();
current_project.iterateFiles((id, data) => {
var divid = this.getFileDivId(id);
var filediv = newDiv(this.maindiv, 'asset_file');
var header = newDiv(filediv, 'asset_file_header').text(id);
var body = newDiv(filediv).attr('id',divid);
try {
var nassets = this.refreshAssetsInFile(id, data);
if (nassets == 0) filediv.hide();
} catch (e) {
console.log(e);
filediv.text(e+""); // TODO: error msg?
}
});
this.deferrednodes.forEach((node) => { node.refreshRight(); });
this.deferrednodes = [];
}
}
// TODO: scroll editors into view
}

View File

@ -8,11 +8,25 @@ var pixed = require("gen/pixed/pixeleditor.js");
describe('Pixel editor', function() {
it('Should decode', function() {
var paldatastr = " 0x00, 0x03, 0x19, 0x50, 0x52, 0x07, 0x1f, 0x37, 0xe0, 0xa4, 0xfd, 0xff, 0x38, 0x70, 0x7f, 0xf8, ";
var fmt = {w:14,h:16,bpp:4,brev:1};
var palfmt = {pal:332,n:16};
var paldatastr = " 0x00, 0x03, 0x19, 0x50, 0x52, 0x07, 0x1f, 0x37, 0xe0, 0xa4, 0xfd, 0xff, 0x38, 0x70, 0x7f, 0xf8, ";
var node4 = new pixed.TextDataNode(null, null, null, paldatastr, 0, paldatastr.length);
var node5 = new pixed.PaletteFormatToRGB(palfmt);
node4.addRight(node5);
node4.refreshRight();
var datastr = "1,2, 0x00,0x00,0xef,0xef,0xe0,0x00,0x00, 0x00,0xee,0xee,0xfe,0xee,0xe0,0x00, 0x0e,0xed,0xef,0xef,0xed,0xee,0x00, 0x0e,0xee,0xdd,0xdd,0xde,0xee,0x00, 0x0e,0xee,0xed,0xde,0xee,0xee,0x00, 0x00,0xee,0xee,0xde,0xee,0xe0,0x00, 0x00,0xee,0xee,0xde,0xee,0xe0,0x00, 0x00,0x00,0xed,0xdd,0xe0,0x00,0x0d, 0xdd,0xdd,0xee,0xee,0xed,0xdd,0xd0, 0x0d,0xee,0xee,0xee,0xee,0xee,0x00, 0x0e,0xe0,0xee,0xee,0xe0,0xee,0x00, 0x0e,0xe0,0xee,0xee,0xe0,0xee,0x00, 0x0e,0xe0,0xdd,0xdd,0xd0,0xde,0x00, 0x0d,0x00,0xee,0x0e,0xe0,0x0d,0x00, 0x00,0x00,0xed,0x0e,0xe0,0x00,0x00, 0x00,0x0d,0xdd,0x0d,0xdd,0x00,0x18,";
pixed.pixelEditorDecodeMessage({data:{fmt:fmt,bytestr:datastr,palfmt:{pal:332,n:16},palstr:paldatastr}});
assert.deepEqual(pixed.palette, [0xff000000,
var node1 = new pixed.TextDataNode(null, null, null, datastr, 0, datastr.length);
var node2 = new pixed.Mapper(fmt);
node1.addRight(node2);
var node3 = new pixed.Palettizer(null, fmt);
node2.addRight(node3);
node1.refreshRight();
assert.deepEqual(node5.palette, [0xff000000,
0xff000060,
0xff006020,
0xff404000,
@ -29,7 +43,7 @@ describe('Pixel editor', function() {
0xff40e0e0,
0xffc0e000,
]);
assert.deepEqual(pixed.allimages, [[0,0,0,0,14,15,14,15,14,0,0,0,0,0,0,0,14,14,14,14,15,14,14,14,14,0,0,0,0,14,14,13,14,15,14,15,14,13,14,14,0,0,0,14,14,14,13,13,13,13,13,14,14,14,0,0,0,14,14,14,14,13,13,14,14,14,14,14,0,0,0,0,14,14,14,14,13,14,14,14,14,0,0,0,0,0,14,14,14,14,13,14,14,14,14,0,0,0,0,0,0,0,14,13,13,13,14,0,0,0,0,13,13,13,13,13,14,14,14,14,14,13,13,13,13,0,0,13,14,14,14,14,14,14,14,14,14,14,0,0,0,14,14,0,14,14,14,14,14,0,14,14,0,0,0,14,14,0,14,14,14,14,14,0,14,14,0,0,0,14,14,0,13,13,13,13,13,0,13,14,0,0,0,13,0,0,14,14,0,14,14,0,0,13,0,0,0,0,0,0,14,13,0,14,14,0,0,0,0,0,0,0,0,13,13,13,0,13,13,13,0,0,1,8]]);
assert.deepEqual(node2.images, [[0,0,0,0,14,15,14,15,14,0,0,0,0,0,0,0,14,14,14,14,15,14,14,14,14,0,0,0,0,14,14,13,14,15,14,15,14,13,14,14,0,0,0,14,14,14,13,13,13,13,13,14,14,14,0,0,0,14,14,14,14,13,13,14,14,14,14,14,0,0,0,0,14,14,14,14,13,14,14,14,14,0,0,0,0,0,14,14,14,14,13,14,14,14,14,0,0,0,0,0,0,0,14,13,13,13,14,0,0,0,0,13,13,13,13,13,14,14,14,14,14,13,13,13,13,0,0,13,14,14,14,14,14,14,14,14,14,14,0,0,0,14,14,0,14,14,14,14,14,0,14,14,0,0,0,14,14,0,14,14,14,14,14,0,14,14,0,0,0,14,14,0,13,13,13,13,13,0,13,14,0,0,0,13,0,0,14,14,0,14,14,0,0,13,0,0,0,0,0,0,14,13,0,14,14,0,0,0,0,0,0,0,0,13,13,13,0,13,13,13,0,0,1,8]]);
assert.equal(" 0x00, 0x03, 0x19, 0x50, 0x52, 0x07, 0x1F, 0x37, 0xE0, 0xA4, 0xFD, 0xFF, 0x38, 0x70, 0x7F, 0xF8, ",
pixed.replaceHexWords(paldatastr, pixed.parseHexWords(paldatastr)));
});

2
tss

@ -1 +1 @@
Subproject commit 5b5ee67fc06956bc7dce51726e98812d2d897eaa
Subproject commit 61a1691a1de05dca3b694bf603db49ffbaf572cf