pixel editor palette selector, tilemap viewer
This commit is contained in:
parent
4469dd7e36
commit
f55da302ed
|
@ -457,6 +457,9 @@ div.asset_file {
|
|||
margin:0.5em;
|
||||
padding:1em;
|
||||
}
|
||||
div.asset_file select {
|
||||
color: #000;
|
||||
}
|
||||
div.asset_file_header {
|
||||
font-weight: bold;
|
||||
color: white;
|
||||
|
|
|
@ -100,6 +100,7 @@ TODO:
|
|||
- 'src is undefined' when committing old image editor
|
||||
- editor: select palette for chr, select charmap for map (dependencies?)
|
||||
- global undo/redo at checkpoints (when rom changes)
|
||||
- asset editor still refreshes twice
|
||||
|
||||
|
||||
WEB WORKER FORMAT
|
||||
|
|
|
@ -6,11 +6,13 @@
|
|||
// link the pattern table into CHR ROM
|
||||
//#link "chr_generic.s"
|
||||
|
||||
const char PALETTE[16] = { /*{pal:"nes",layout:"nes"}*/
|
||||
0x03,
|
||||
0x11,0x30,0x27, 0,
|
||||
0x1c,0x20,0x2c, 0,
|
||||
0x00,0x10,0x20, 0,
|
||||
/*{pal:"nes",layout:"nes"}*/
|
||||
const char PALETTE[16] = {
|
||||
0x03, // background color
|
||||
|
||||
0x25,0x30,0x27,0x00, // ladders and pickups
|
||||
0x1C,0x20,0x2C,0x00, // floor blocks
|
||||
0x00,0x10,0x20,0x00,
|
||||
0x06,0x16,0x26
|
||||
};
|
||||
|
||||
|
|
|
@ -726,17 +726,18 @@ void play_scene() {
|
|||
rescue_scene();
|
||||
}
|
||||
|
||||
const char PALETTE[32] = { /*{pal:"nes",layout:"nes"}*/
|
||||
/*{pal:"nes",layout:"nes"}*/
|
||||
const char PALETTE[32] = {
|
||||
0x03, // background color
|
||||
|
||||
0x11,0x30,0x27, 0, // ladders and pickups
|
||||
0x1c,0x20,0x2c, 0, // floor blocks
|
||||
0x00,0x10,0x20, 0,
|
||||
0x06,0x16,0x26, 0,
|
||||
0x11,0x30,0x27, 0x0, // ladders and pickups
|
||||
0x1c,0x20,0x2c, 0x0, // floor blocks
|
||||
0x00,0x10,0x20, 0x0,
|
||||
0x06,0x16,0x26, 0x0,
|
||||
|
||||
0x16,0x35,0x24, 0, // enemy sprites
|
||||
0x00,0x37,0x25, 0, // rescue person
|
||||
0x0d,0x2d,0x3a, 0,
|
||||
0x16,0x35,0x24, 0x0, // enemy sprites
|
||||
0x00,0x37,0x25, 0x0, // rescue person
|
||||
0x0d,0x2d,0x3a, 0x0,
|
||||
0x0d,0x27,0x2a // player sprites
|
||||
};
|
||||
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
.export _climbr_title_pal
|
||||
.export _climbr_title_rle
|
||||
|
||||
_climbr_title_pal:
|
||||
;;{pal:"nes",layout:"nes"};;
|
||||
_climbr_title_pal:
|
||||
.byte $0F,$11,$25,$35,$0F,$01,$21,$30
|
||||
.byte $0F,$06,$1C,$3C,$0F,$11,$28,$38
|
||||
;;
|
||||
_climbr_title_rle:
|
||||
;;{w:32,h:30,bpp:8,comp:"rletag",map:"nesnt"};;
|
||||
_climbr_title_rle:
|
||||
.byte $01,$00,$01,$10,$80,$01,$02,$00
|
||||
.byte $80,$00,$80,$00,$01,$1f,$80,$80
|
||||
.byte $00,$01,$07,$41,$4e,$00,$38,$42
|
||||
|
|
|
@ -58,18 +58,19 @@ const unsigned char* const playerRunSeq[16] = {
|
|||
playerRRun1, playerRRun2,
|
||||
};
|
||||
|
||||
const char PALETTE[32] = { /*{pal:"nes",layout:"nes"}*/
|
||||
/*{pal:"nes",layout:"nes"}*/
|
||||
const char PALETTE[32] = {
|
||||
0x03, // background color
|
||||
|
||||
0x11,0x30,0x27, 0, // ladders and pickups
|
||||
0x1c,0x20,0x2c, 0, // floor blocks
|
||||
0x00,0x10,0x20, 0,
|
||||
0x06,0x16,0x26, 0,
|
||||
0x25,0x30,0x27,0x00, // ladders and pickups
|
||||
0x1C,0x20,0x2C,0x00, // floor blocks
|
||||
0x00,0x10,0x20,0x00,
|
||||
0x06,0x16,0x26,0x00,
|
||||
|
||||
0x16,0x35,0x24, 0, // enemy sprites
|
||||
0x00,0x37,0x25, 0, // rescue person
|
||||
0x0d,0x2d,0x3a, 0,
|
||||
0x0d,0x27,0x2a // player sprites
|
||||
0x16,0x35,0x24,0x00, // enemy sprites
|
||||
0x00,0x37,0x25,0x00, // rescue person
|
||||
0x0D,0x2D,0x1A,0x00,
|
||||
0x0D,0x27,0x2A // player sprites
|
||||
};
|
||||
|
||||
// setup PPU and tables
|
||||
|
|
|
@ -102,18 +102,19 @@ void scroll_demo() {
|
|||
}
|
||||
}
|
||||
|
||||
const char PALETTE[32] = { /*{pal:"nes",layout:"nes"}*/
|
||||
/*{pal:"nes",layout:"nes"}*/
|
||||
const char PALETTE[32] = {
|
||||
0x03, // background color
|
||||
|
||||
0x11,0x30,0x27, 0, // background 0
|
||||
0x1c,0x20,0x2c, 0, // background 1
|
||||
0x00,0x10,0x20, 0, // background 2
|
||||
0x06,0x16,0x26, 0, // background 3
|
||||
0x25,0x30,0x27,0x00, // ladders and pickups
|
||||
0x1C,0x20,0x2C,0x00, // floor blocks
|
||||
0x00,0x10,0x20,0x00,
|
||||
0x06,0x16,0x26,0x00,
|
||||
|
||||
0x16,0x35,0x24, 0, // sprite 0
|
||||
0x00,0x37,0x25, 0, // sprite 1
|
||||
0x0d,0x2d,0x3a, 0, // sprite 2
|
||||
0x0d,0x27,0x2a // sprite 3
|
||||
0x16,0x35,0x24,0x00, // enemy sprites
|
||||
0x00,0x37,0x25,0x00, // rescue person
|
||||
0x0D,0x2D,0x1A,0x00,
|
||||
0x0D,0x27,0x2A // player sprites
|
||||
};
|
||||
|
||||
// main function, run after console reset
|
||||
|
|
|
@ -58,18 +58,19 @@ const unsigned char* const playerRunSeq[16] = {
|
|||
playerRRun1, playerRRun2,
|
||||
};
|
||||
|
||||
const char PALETTE[32] = { /*{pal:"nes",layout:"nes"}*/
|
||||
/*{pal:"nes",layout:"nes"}*/
|
||||
const char PALETTE[32] = {
|
||||
0x03, // background color
|
||||
|
||||
0x11,0x30,0x27, 0, // ladders and pickups
|
||||
0x1c,0x20,0x2c, 0, // floor blocks
|
||||
0x00,0x10,0x20, 0,
|
||||
0x06,0x16,0x26, 0,
|
||||
0x25,0x30,0x27,0x00, // ladders and pickups
|
||||
0x1C,0x20,0x2C,0x00, // floor blocks
|
||||
0x00,0x10,0x20,0x00,
|
||||
0x06,0x16,0x26,0x00,
|
||||
|
||||
0x16,0x35,0x24, 0, // enemy sprites
|
||||
0x00,0x37,0x25, 0, // rescue person
|
||||
0x0d,0x2d,0x3a, 0,
|
||||
0x0d,0x27,0x2a // player sprites
|
||||
0x16,0x35,0x24,0x00, // enemy sprites
|
||||
0x00,0x37,0x25,0x00, // rescue person
|
||||
0x0D,0x2D,0x1A,0x00,
|
||||
0x0D,0x27,0x2A // player sprites
|
||||
};
|
||||
|
||||
// setup PPU and tables
|
||||
|
|
|
@ -58,7 +58,8 @@ const unsigned char* const playerRunSeq[16] = {
|
|||
playerRRun1, playerRRun2,
|
||||
};
|
||||
|
||||
const char PALETTE[32] = { /*{pal:"nes",layout:"nes"}*/
|
||||
/*{pal:"nes",layout:"nes"}*/
|
||||
const char PALETTE[32] = {
|
||||
0x03, // background color
|
||||
|
||||
0x25,0x30,0x27,0x00, // ladders and pickups
|
||||
|
|
|
@ -58,18 +58,19 @@ const unsigned char* const playerRunSeq[16] = {
|
|||
playerRRun1, playerRRun2,
|
||||
};
|
||||
|
||||
const char PALETTE[32] = { /*{pal:"nes",layout:"nes"}*/
|
||||
/*{pal:"nes",layout:"nes"}*/
|
||||
const char PALETTE[32] = {
|
||||
0x03, // background color
|
||||
|
||||
0x11,0x30,0x27, 0, // ladders and pickups
|
||||
0x1c,0x20,0x2c, 0, // floor blocks
|
||||
0x00,0x10,0x20, 0,
|
||||
0x06,0x16,0x26, 0,
|
||||
0x25,0x30,0x27,0x00, // ladders and pickups
|
||||
0x1C,0x20,0x2C,0x00, // floor blocks
|
||||
0x00,0x10,0x20,0x00,
|
||||
0x06,0x16,0x26,0x00,
|
||||
|
||||
0x16,0x35,0x24, 0, // enemy sprites
|
||||
0x00,0x37,0x25, 0, // rescue person
|
||||
0x0d,0x2d,0x3a, 0,
|
||||
0x0d,0x27,0x2a // player sprites
|
||||
0x16,0x35,0x24,0x00, // enemy sprites
|
||||
0x00,0x37,0x25,0x00, // rescue person
|
||||
0x0D,0x2D,0x1A,0x00,
|
||||
0x0D,0x27,0x2A // player sprites
|
||||
};
|
||||
|
||||
// setup PPU and tables
|
||||
|
|
|
@ -25,17 +25,18 @@
|
|||
|
||||
//#define DEBUG_FRAMERATE
|
||||
|
||||
const char PALETTE[32] = { /*{pal:"nes",layout:"nes"}*/
|
||||
/*{pal:"nes",layout:"nes"}*/
|
||||
const char PALETTE[32] = {
|
||||
0x0f,
|
||||
|
||||
0x11,0x24,0x3c, 0,
|
||||
0x01,0x15,0x25, 0,
|
||||
0x01,0x10,0x20, 0,
|
||||
0x06,0x16,0x26, 0,
|
||||
0x11,0x24,0x3c, 0x0,
|
||||
0x01,0x15,0x25, 0x0,
|
||||
0x01,0x10,0x20, 0x0,
|
||||
0x06,0x16,0x26, 0x0,
|
||||
|
||||
0x11,0x24,0x3c, 0,
|
||||
0x01,0x15,0x25, 0,
|
||||
0x31,0x35,0x3c, 0,
|
||||
0x11,0x24,0x3c, 0x0,
|
||||
0x01,0x15,0x25, 0x0,
|
||||
0x31,0x35,0x3c, 0x0,
|
||||
0x01,0x17,0x30
|
||||
};
|
||||
|
||||
|
@ -47,7 +48,8 @@ const char PALETTE[32] = { /*{pal:"nes",layout:"nes"}*/
|
|||
#define COLOR_SCORE 2
|
||||
#define COLOR_EXPLOSION 3
|
||||
|
||||
const char TILESET[128*8*2] = {/*{w:8,h:8,bpp:1,count:128,brev:1,np:2,pofs:8,remap:[0,1,2,4,5,6,7,8,9,10,11,12]}*/
|
||||
/*{w:8,h:8,bpp:1,count:128,brev:1,np:2,pofs:8,remap:[0,1,2,4,5,6,7,8,9,10,11,12]}*/
|
||||
const char TILESET[128*8*2] = {
|
||||
// font (0..63)
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x7C,0x7C,0x7C,0x38,0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6C,0x6C,0x48,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6C,0xFE,0x6C,0xFE,0x6C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0xFE,0xD0,0xFE,0x16,0xFE,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xCE,0xDC,0x38,0x76,0xE6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x6C,0x7C,0xEC,0xEE,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x38,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x70,0x70,0x70,0x70,0x70,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x70,0x38,0x38,0x38,0x38,0x38,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x6C,0x38,0x6C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x38,0xFE,0x38,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0E,0x1E,0x3C,0x78,0xF0,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x7C,0xEE,0xEE,0xEE,0xEE,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x78,0x38,0x38,0x38,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0x0E,0x7C,0xE0,0xEE,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFC,0x0E,0x3C,0x0E,0x0E,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3E,0x7E,0xEE,0xEE,0xFE,0x0E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFC,0xE0,0xFC,0x0E,0xEE,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0xE0,0xFC,0xEE,0xEE,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0xEE,0x1C,0x1C,0x38,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0xEE,0x7C,0xEE,0xEE,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0xEE,0xEE,0x7E,0x0E,0x3C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x60,0x00,0x00,0x60,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x60,0x60,0x00,0x00,0x60,0x60,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x38,0x70,0x70,0x38,0x1C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0x00,0x00,0x7C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x70,0x38,0x1C,0x1C,0x38,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7C,0xEE,0x1C,0x38,0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
|
|
|
@ -250,8 +250,8 @@ AE(1,0,1,0),AE(0,0,0,0),AE(0,0,0,0),AE(0,0,0,0), AE(0,0,0,0),AE(0,0,0,0),AE(0,0,
|
|||
AE(1,1,1,1),AE(1,1,1,1),AE(1,1,1,1),AE(1,1,1,1), AE(1,1,1,1),AE(1,1,1,1),AE(1,1,1,1),AE(1,1,1,1),
|
||||
};
|
||||
|
||||
// this is palette data
|
||||
const unsigned char Palette_Table[16]={ /*{pal:"nes",layout:"nes"}*/
|
||||
/*{pal:"nes",layout:"nes"}*/
|
||||
const unsigned char Palette_Table[16]={
|
||||
0x02,
|
||||
0x31,0x31,0x31,0x00,
|
||||
0x34,0x34,0x34,0x00,
|
||||
|
|
|
@ -11,18 +11,18 @@
|
|||
// link the pattern table into CHR ROM
|
||||
//#link "chr_generic.s"
|
||||
|
||||
|
||||
const char PALETTE[32] = { /*{pal:"nes",layout:"nes"}*/
|
||||
/*{pal:"nes",layout:"nes"}*/
|
||||
const char PALETTE[32] = {
|
||||
0x03, // background color
|
||||
|
||||
0x11,0x30,0x27, 0, // ladders and pickups
|
||||
0x1c,0x20,0x2c, 0, // floor blocks
|
||||
0x00,0x10,0x20, 0,
|
||||
0x06,0x16,0x26, 0,
|
||||
0x11,0x30,0x27,0x0, // ladders and pickups
|
||||
0x1c,0x20,0x2c,0x0, // floor blocks
|
||||
0x00,0x10,0x20,0x0,
|
||||
0x06,0x16,0x26,0x0,
|
||||
|
||||
0x16,0x35,0x24, 0, // enemy sprites
|
||||
0x00,0x37,0x25, 0, // rescue person
|
||||
0x0d,0x2d,0x3a, 0,
|
||||
0x16,0x35,0x24,0x0, // enemy sprites
|
||||
0x00,0x37,0x25,0x0, // rescue person
|
||||
0x0d,0x2d,0x3a,0x0,
|
||||
0x0d,0x27,0x2a // player sprites
|
||||
};
|
||||
|
||||
|
|
|
@ -5,8 +5,24 @@ import { ProjectWindows } from "../windows";
|
|||
|
||||
export type UintArray = number[] | Uint8Array | Uint16Array | Uint32Array; //{[i:number]:number};
|
||||
|
||||
// TODO: separate view/controller
|
||||
export interface EditorContext {
|
||||
setCurrentEditor(div : JQuery, editing : JQuery) : void;
|
||||
setCurrentEditor(div:JQuery, editing:JQuery) : void;
|
||||
getPalettes(matchlen : number) : SelectablePalette[];
|
||||
getTilemaps(matchlen : number) : SelectableTilemap[];
|
||||
}
|
||||
|
||||
export type SelectablePalette = {
|
||||
node:PixNode
|
||||
name:string
|
||||
palette:Uint32Array
|
||||
}
|
||||
|
||||
export type SelectableTilemap = {
|
||||
node:PixNode
|
||||
name:string
|
||||
images:Uint8Array[]
|
||||
rgbimgs:Uint32Array[] // TODO: different palettes?
|
||||
}
|
||||
|
||||
export type PixelEditorImageFormat = {
|
||||
|
@ -599,7 +615,7 @@ function pixelEditorKeypress(e) {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: reversed?
|
||||
// TODO: illegal colors?
|
||||
var PREDEF_PALETTES = {
|
||||
'nes':[
|
||||
0x525252, 0xB40000, 0xA00000, 0xB1003D, 0x740069, 0x00005B, 0x00005F, 0x001840, 0x002F10, 0x084A08, 0x006700, 0x124200, 0x6D2800, 0x000000, 0x000000, 0x000000,
|
||||
|
@ -665,6 +681,7 @@ export abstract class PixNode {
|
|||
abstract class CodeProjectDataNode extends PixNode {
|
||||
project : ProjectWindows;
|
||||
fileid : string;
|
||||
label : string;
|
||||
words : UintArray;
|
||||
}
|
||||
|
||||
|
@ -674,6 +691,7 @@ export class FileDataNode extends CodeProjectDataNode {
|
|||
super();
|
||||
this.project = project;
|
||||
this.fileid = fileid;
|
||||
this.label = fileid;
|
||||
this.words = data;
|
||||
}
|
||||
updateLeft() {
|
||||
|
@ -690,10 +708,11 @@ export class TextDataNode extends CodeProjectDataNode {
|
|||
start : number;
|
||||
end : number;
|
||||
|
||||
constructor(project:ProjectWindows, fileid:string, text:string, start:number, end:number) {
|
||||
constructor(project:ProjectWindows, fileid:string, label:string, text:string, start:number, end:number) {
|
||||
super();
|
||||
this.project = project;
|
||||
this.fileid = fileid;
|
||||
this.label = label;
|
||||
this.text = text;
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
|
@ -762,6 +781,18 @@ export class Palettizer extends PixNode {
|
|||
rgbimgs : Uint32Array[];
|
||||
palette : Uint32Array;
|
||||
|
||||
ncolors : number;
|
||||
context : EditorContext;
|
||||
options : SelectablePalette[];
|
||||
selindex : number = 0;
|
||||
|
||||
// TODO: control to select palette for bitmaps
|
||||
|
||||
constructor(context:EditorContext, fmt:PixelEditorImageFormat) {
|
||||
super();
|
||||
this.context = context;
|
||||
this.ncolors = 1 << ((fmt.bpp||1) * (fmt.np||1));
|
||||
}
|
||||
updateLeft() {
|
||||
this.rgbimgs = this.right.rgbimgs;
|
||||
var pal = new RGBAPalette(this.palette);
|
||||
|
@ -774,6 +805,7 @@ export class Palettizer extends PixNode {
|
|||
});
|
||||
}
|
||||
updateRight() {
|
||||
this.updatePalette();
|
||||
this.images = this.left.images;
|
||||
var mask = this.palette.length - 1; // must be power of 2
|
||||
// for each image, map bytes to RGB colors
|
||||
|
@ -785,6 +817,20 @@ export class Palettizer extends PixNode {
|
|||
return out;
|
||||
});
|
||||
}
|
||||
updatePalette() {
|
||||
if (this.context != null) {
|
||||
this.options = this.context.getPalettes(this.ncolors);
|
||||
if (this.options && this.options.length > 0) {
|
||||
this.palette = this.options[this.selindex].palette;
|
||||
}
|
||||
}
|
||||
if (this.palette == null) {
|
||||
if (this.ncolors <= 2)
|
||||
this.palette = new Uint32Array([0xff000000, 0xffffffff]);
|
||||
else
|
||||
this.palette = new Uint32Array([0xff000000, 0xffff00ff, 0xffffff00, 0xffffffff]); // TODO: more palettes
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function dedupPalette(cols : UintArray) : Uint32Array {
|
||||
|
@ -830,6 +876,83 @@ export class PaletteFormatToRGB extends PixNode {
|
|||
}
|
||||
}
|
||||
|
||||
export class NESNametableConverter extends PixNode {
|
||||
|
||||
palette : Uint32Array;
|
||||
tilemap : Uint8Array[]; // tilemap images
|
||||
rgbimgs : Uint32Array[]; // output (1 image)
|
||||
width : number;
|
||||
height : number;
|
||||
cols : number;
|
||||
rows : number;
|
||||
baseofs : number;
|
||||
|
||||
context : EditorContext;
|
||||
paloptions : SelectablePalette[];
|
||||
tileoptions : SelectableTilemap[];
|
||||
palindex : number = 0;
|
||||
tileindex : number = 0;
|
||||
|
||||
constructor(context:EditorContext) {
|
||||
super();
|
||||
this.context = context;
|
||||
}
|
||||
updateLeft() {
|
||||
// TODO
|
||||
}
|
||||
updateRight() {
|
||||
this.words = this.left.words;
|
||||
this.updatePalette();
|
||||
this.cols = 32;
|
||||
this.rows = 30;
|
||||
this.width = this.cols * 8;
|
||||
this.height = this.rows * 8;
|
||||
this.baseofs = 0;
|
||||
var idata = new Uint32Array(this.width * this.height);
|
||||
this.rgbimgs = [idata];
|
||||
var a = 0;
|
||||
var attraddr;
|
||||
for (var row=0; row<this.rows; row++) {
|
||||
for (var col=0; col<this.cols; col++) {
|
||||
var name = this.words[this.baseofs + a];
|
||||
var t = this.tilemap[name];
|
||||
attraddr = (a & 0x2c00) | 0x3c0 | (a & 0x0C00) | ((a >> 4) & 0x38) | ((a >> 2) & 0x07);
|
||||
var attr = this.words[attraddr];
|
||||
var tag = name ^ (attr<<9) ^ 0x80000000;
|
||||
var i = row*this.cols*8*8 + col*8;
|
||||
var j = 0;
|
||||
var attrshift = (col&2) + ((a&0x40)>>4);
|
||||
var coloradd = ((attr >> attrshift) & 3) << 2;
|
||||
for (var y=0; y<8; y++) {
|
||||
for (var x=0; x<8; x++) {
|
||||
var color = t[j++];
|
||||
if (color) color += coloradd;
|
||||
var rgb = this.palette[color];
|
||||
idata[i++] = rgb | 0xff000000;
|
||||
}
|
||||
i += this.cols*8-8;
|
||||
}
|
||||
a++;
|
||||
}
|
||||
}
|
||||
// TODO
|
||||
}
|
||||
updatePalette() {
|
||||
if (this.context != null) {
|
||||
this.paloptions = this.context.getPalettes(16);
|
||||
if (this.paloptions && this.paloptions.length > 0) {
|
||||
this.palette = this.paloptions[this.palindex].palette;
|
||||
}
|
||||
this.tileoptions = this.context.getTilemaps(256);
|
||||
if (this.tileoptions && this.tileoptions.length > 0) {
|
||||
this.tilemap = this.tileoptions[this.tileindex].images;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///// UI CONTROLS
|
||||
|
||||
export class Viewer { // TODO: make PixNode
|
||||
|
||||
width : number;
|
||||
|
@ -933,6 +1056,7 @@ export class CharmapEditor extends PixNode {
|
|||
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();
|
||||
chooser.rgbimgs = this.rgbimgs;
|
||||
chooser.width = this.fmt.w || 1;
|
||||
|
@ -946,6 +1070,23 @@ export class CharmapEditor extends PixNode {
|
|||
aeditor.empty().append(editview.canvas);
|
||||
this.context.setCurrentEditor(aeditor, $(viewer.canvas));
|
||||
});
|
||||
// add palette selector
|
||||
// TODO: only view when editing?
|
||||
var palizer = this.left;
|
||||
if (palizer instanceof Palettizer && palizer.options.length > 1) {
|
||||
var palselect = $(document.createElement('select'));
|
||||
palizer.options.forEach((palopt, i) => {
|
||||
// TODO: full identifier
|
||||
var sel = $(document.createElement('option')).text(palopt.name).val(i).appendTo(palselect);
|
||||
if (i == (palizer as Palettizer).selindex)
|
||||
sel.attr('selected','selected');
|
||||
});
|
||||
palselect.appendTo(agrid).change((e) => {
|
||||
var index = $(e.target).val() as number;
|
||||
(palizer as Palettizer).selindex = index;
|
||||
palizer.refreshRight();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
123
src/views.ts
123
src/views.ts
|
@ -967,6 +967,7 @@ export class AssetEditorView implements ProjectView, pixed.EditorContext {
|
|||
cureditordiv : JQuery;
|
||||
cureditelem : JQuery;
|
||||
rootnodes : pixed.PixNode[];
|
||||
deferrednodes : pixed.PixNode[];
|
||||
|
||||
createDiv(parent : HTMLElement) {
|
||||
this.maindiv = newDiv(parent, "vertical-scroll");
|
||||
|
@ -975,10 +976,68 @@ export class AssetEditorView implements ProjectView, pixed.EditorContext {
|
|||
|
||||
clearAssets() {
|
||||
this.rootnodes = [];
|
||||
this.deferrednodes = [];
|
||||
}
|
||||
|
||||
registerAsset(type:string, node:pixed.PixNode) {
|
||||
registerAsset(type:string, node:pixed.PixNode, deferred:boolean) {
|
||||
this.rootnodes.push(node);
|
||||
if (deferred) {
|
||||
this.deferrednodes.push(node);
|
||||
} else {
|
||||
node.refreshRight();
|
||||
}
|
||||
}
|
||||
|
||||
getPalettes(matchlen : number) : pixed.SelectablePalette[] {
|
||||
var result = [];
|
||||
this.rootnodes.forEach((node) => {
|
||||
while (node != null) {
|
||||
if (node instanceof pixed.PaletteFormatToRGB) {
|
||||
// TODO: move to node class?
|
||||
var palette = node.palette;
|
||||
// match full palette length?
|
||||
if (matchlen == palette.length) {
|
||||
result.push({node:node, name:"Palette", palette:palette});
|
||||
}
|
||||
// look at palette slices
|
||||
if (node.layout) {
|
||||
node.layout.forEach(([name, start, len]) => {
|
||||
if (start < palette.length) {
|
||||
if (len == matchlen) {
|
||||
var rgbs = palette.slice(start, start+len);
|
||||
result.push({node:node, name:name, palette:rgbs});
|
||||
} else if (len+1 == matchlen) {
|
||||
var rgbs = new Uint32Array(matchlen);
|
||||
rgbs[0] = palette[0];
|
||||
rgbs.set(palette.slice(start, start+len), 1);
|
||||
result.push({node:node, name:name, palette:rgbs});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
node = node.right;
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
getTilemaps(matchlen : number) : pixed.SelectableTilemap[] {
|
||||
var result = [];
|
||||
this.rootnodes.forEach((node) => {
|
||||
while (node != null) {
|
||||
if (node instanceof pixed.Palettizer) {
|
||||
// TODO: move to node class?
|
||||
var rgbimgs = node.rgbimgs;
|
||||
if (rgbimgs.length >= matchlen) {
|
||||
result.push({node:node, name:"Tilemap", images:node.images, rgbimgs:rgbimgs}); // TODO
|
||||
}
|
||||
}
|
||||
node = node.right;
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
setCurrentEditor(div : JQuery, editing : JQuery) {
|
||||
|
@ -1087,11 +1146,7 @@ export class AssetEditorView implements ProjectView, pixed.EditorContext {
|
|||
// TODO: rotate node?
|
||||
firstnode.addRight(mapper);
|
||||
// pixels -> RGBA
|
||||
var palizer = new pixed.Palettizer();
|
||||
if (fmt.bpp*(fmt.np|1) == 1)
|
||||
palizer.palette = new Uint32Array([0xff000000, 0xffffffff]);
|
||||
else
|
||||
palizer.palette = new Uint32Array([0x00000000, 0xffff00ff, 0xffffff00, 0xffffffff]); // TODO
|
||||
var palizer = new pixed.Palettizer(this, fmt);
|
||||
mapper.addRight(palizer);
|
||||
// add view objects
|
||||
palizer.addRight(new pixed.CharmapEditor(this, newDiv(parentdiv), fmt));
|
||||
|
@ -1127,29 +1182,41 @@ export class AssetEditorView implements ProjectView, pixed.EditorContext {
|
|||
let node = new pixed.FileDataNode(projectWindows, fileid, data);
|
||||
const neschrfmt = {w:8,h:8,bpp:1,count:(data.length>>4),brev:true,np:2,pofs:8,remap:[0,1,2,4,5,6,7,8,9,10,11,12]}; // TODO
|
||||
this.addPixelEditor(filediv, node, neschrfmt);
|
||||
this.registerAsset("charmap", node);
|
||||
this.registerAsset("charmap", node, true);
|
||||
} else if (typeof data === 'string') {
|
||||
let textfrags = this.scanFileTextForAssets(fileid, data);
|
||||
for (let frag of textfrags) {
|
||||
let node : pixed.PixNode = new pixed.TextDataNode(projectWindows, fileid, data, frag.start, frag.end);
|
||||
let first = node;
|
||||
if (frag.fmt.comp == 'rletag') {
|
||||
node = node.addRight(new pixed.Compressor());
|
||||
}
|
||||
// is this a bitmap?
|
||||
if (frag.fmt && frag.fmt.w > 0 && frag.fmt.h > 0) {
|
||||
this.addPixelEditor(filediv, node, frag.fmt);
|
||||
this.registerAsset("charmap", first);
|
||||
nassets++;
|
||||
}
|
||||
// is this a palette?
|
||||
else if (frag.fmt && frag.fmt.pal) {
|
||||
this.addPaletteEditor(filediv, node, frag.fmt);
|
||||
this.registerAsset("palette", first);
|
||||
nassets++;
|
||||
}
|
||||
else {
|
||||
// TODO: other kinds of resources?
|
||||
if (frag.fmt) {
|
||||
let label = fileid; // TODO: label
|
||||
let node : pixed.PixNode = new pixed.TextDataNode(projectWindows, fileid, label, data, frag.start, frag.end);
|
||||
let first = node;
|
||||
// rle-compressed?
|
||||
if (frag.fmt.comp == 'rletag') {
|
||||
node = node.addRight(new pixed.Compressor());
|
||||
}
|
||||
// is this a nes nametable?
|
||||
if (frag.fmt.map == 'nesnt') {
|
||||
node = node.addRight(new pixed.NESNametableConverter(this)); // TODO?
|
||||
const fmt = {w:8*32,h:8*30,count:1}; // TODO
|
||||
node = node.addRight(new pixed.CharmapEditor(this, newDiv(filediv), fmt));
|
||||
this.registerAsset("nametable", first, true);
|
||||
nassets++;
|
||||
}
|
||||
// is this a bitmap?
|
||||
else if (frag.fmt.w > 0 && frag.fmt.h > 0) {
|
||||
this.addPixelEditor(filediv, node, frag.fmt);
|
||||
this.registerAsset("charmap", first, true);
|
||||
nassets++;
|
||||
}
|
||||
// is this a palette?
|
||||
else if (frag.fmt.pal) {
|
||||
this.addPaletteEditor(filediv, node, frag.fmt);
|
||||
this.registerAsset("palette", first, false);
|
||||
nassets++;
|
||||
}
|
||||
else {
|
||||
// TODO: other kinds of resources?
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1177,8 +1244,8 @@ export class AssetEditorView implements ProjectView, pixed.EditorContext {
|
|||
filediv.text(e+""); // TODO: error msg?
|
||||
}
|
||||
});
|
||||
// refresh all assets
|
||||
this.rootnodes.forEach((node) => { node.refreshRight(); });
|
||||
this.deferrednodes.forEach((node) => { node.refreshRight(); });
|
||||
this.deferrednodes = [];
|
||||
}
|
||||
|
||||
// TODO: scroll editors into view
|
||||
|
|
2
tss
2
tss
|
@ -1 +1 @@
|
|||
Subproject commit 5b5ee67fc06956bc7dce51726e98812d2d897eaa
|
||||
Subproject commit 61a1691a1de05dca3b694bf603db49ffbaf572cf
|
Loading…
Reference in New Issue