From 36b8ed48a0357a07dee68b57a330adc1fb11aa51 Mon Sep 17 00:00:00 2001 From: Steven Hugg Date: Sat, 23 Mar 2019 10:37:49 -0400 Subject: [PATCH] integrated/replaced pixel editor, nes: updated presets --- css/ui.css | 2 +- index.html | 20 -- pixels.html | 113 ------- presets/nes/monobitmap.c | 117 +++++-- src/pixed/pixeleditor.ts | 631 ++++++++++++----------------------- src/ui.ts | 7 - src/views.ts | 142 ++------ test/cli/testpixelconvert.js | 22 +- tss | 2 +- 9 files changed, 352 insertions(+), 704 deletions(-) delete mode 100644 pixels.html diff --git a/css/ui.css b/css/ui.css index 83f5bf23..31dcab3d 100644 --- a/css/ui.css +++ b/css/ui.css @@ -257,7 +257,7 @@ canvas.pixelated { height:2em; border-style:none; } -.palbtn .selected { +.palbtn.selected { border-width:2px; border-color:white; border-style:dotted; diff --git a/index.html b/index.html index 5394fb6f..c0e7a7af 100644 --- a/index.html +++ b/index.html @@ -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%; -} - - - - - - - - - - - - - - diff --git a/presets/nes/monobitmap.c b/presets/nes/monobitmap.c index d7e5ccb3..12324507 100644 --- a/presets/nes/monobitmap.c +++ b/presets/nes/monobitmap.c @@ -1,16 +1,29 @@ #include "neslib.h" #include "nes.h" +#include #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 = x0dy ? 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'); - 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= 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= 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').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 = $(''); - 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= 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 = $('
'); // 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 number) { + var i = 0; + var pixels = new Uint32Array(this.rgbdata.length); + for (var y=0; 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); + }); + } + +} diff --git a/src/ui.ts b/src/ui.ts index d4b6ef19..7cdd58fe 100644 --- a/src/ui.ts +++ b/src/ui.ts @@ -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); diff --git a/src/views.ts b/src/views.ts index 3988d15a..35135c61 100644 --- a/src/views.ts +++ b/src/views.ts @@ -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 = $('
').appendTo(parentdiv); var aeditor = $('
').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 } - diff --git a/test/cli/testpixelconvert.js b/test/cli/testpixelconvert.js index d3f41286..da4f3871 100644 --- a/test/cli/testpixelconvert.js +++ b/test/cli/testpixelconvert.js @@ -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))); }); diff --git a/tss b/tss index 5b5ee67f..61a1691a 160000 --- a/tss +++ b/tss @@ -1 +1 @@ -Subproject commit 5b5ee67fc06956bc7dce51726e98812d2d897eaa +Subproject commit 61a1691a1de05dca3b694bf603db49ffbaf572cf