diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..09058da5 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,6 @@ +*.pal binary +*.chr binary +*.rle binary +*.lz4 binary +*.bin binary +*.nam binary diff --git a/doc/notes.txt b/doc/notes.txt index 50a154f0..ad8c3ff6 100644 --- a/doc/notes.txt +++ b/doc/notes.txt @@ -102,6 +102,7 @@ TODO: - throw errors when bad/no refs - per-View keyboard shortcuts - parse labels + - parse .incbin directives? - crt0.s compiled each time? - debug highlight doesn't go away when debugging -> running - show breakpoint of PC or highest address on stack diff --git a/presets/nes/climbr_title.nam.rle b/presets/nes/climbr_title.nam.rle new file mode 100644 index 00000000..f2444bca Binary files /dev/null and b/presets/nes/climbr_title.nam.rle differ diff --git a/presets/nes/climbr_title.pal b/presets/nes/climbr_title.pal new file mode 100644 index 00000000..df36a55a --- /dev/null +++ b/presets/nes/climbr_title.pal @@ -0,0 +1 @@ +%5!0<'8 \ No newline at end of file diff --git a/presets/nes/jroatch.chr.lz4 b/presets/nes/jroatch.chr.lz4 new file mode 100644 index 00000000..0eb2dc65 Binary files /dev/null and b/presets/nes/jroatch.chr.lz4 differ diff --git a/src/platform/nes.ts b/src/platform/nes.ts index 44cae22f..3f5be53f 100644 --- a/src/platform/nes.ts +++ b/src/platform/nes.ts @@ -19,7 +19,6 @@ const JSNES_PRESETS = [ {id:'rletitle.c', name:'Title Screen RLE'}, {id:'statusbar.c', name:'Split Status Bar'}, {id:'horizmask.c', name:'Offscreen Scrolling'}, - {id:'attributes.c', name:'Attribute Table + Pixels'}, {id:'monobitmap.c', name:'Monochrome Bitmap'}, {id:'aputest.c', name:'Sound Tester'}, {id:'music.c', name:'Music Player'}, diff --git a/src/project.ts b/src/project.ts index 8efd61f4..5d50ee25 100644 --- a/src/project.ts +++ b/src/project.ts @@ -73,43 +73,48 @@ export class CodeProject { } parseIncludeDependencies(text:string):string[] { - var files = []; - var m; + let files = []; + let m; if (this.platform_id.startsWith('verilog')) { // include verilog includes - var re1 = /^\s*(`include|[.]include)\s+"(.+?)"/gmi; + let re1 = /^\s*(`include|[.]include)\s+"(.+?)"/gmi; while (m = re1.exec(text)) { this.pushAllFiles(files, m[2]); } // include .arch (json) statements - var re2 = /^\s*([.]arch)\s+(\w+)/gmi; + let re2 = /^\s*([.]arch)\s+(\w+)/gmi; while (m = re2.exec(text)) { this.pushAllFiles(files, m[2]+".json"); } // include $readmem[bh] (TODO) - var re3 = /\b\$readmem[bh]\("(.+?)"/gmi; + let re3 = /\b\$readmem[bh]\("(.+?)"/gmi; while (m = re3.exec(text)) { this.pushAllFiles(files, m[2]); } } else { // for .asm -- [.]include "file" // for .c -- #include "file" - var re2 = /^\s*[.#]?(include|incbin)\s+"(.+?)"/gmi; + let re2 = /^\s*[.#]?(include|incbin)\s+"(.+?)"/gmi; while (m = re2.exec(text)) { this.pushAllFiles(files, m[2]); } + // for .c -- //#link "file" (or ;link or #link) + let re3 = /^\s*([;#]|[/][/][#])resource\s+"(.+?)"/gm; + while (m = re3.exec(text)) { + this.pushAllFiles(files, m[2]); + } } return files; } parseLinkDependencies(text:string):string[] { - var files = []; - var m; + let files = []; + let m; if (this.platform_id.startsWith('verilog')) { // } else { // for .c -- //#link "file" (or ;link or #link) - var re = /^\s*([;#]|[/][/][#])link\s+"(.+?)"/gm; + let re = /^\s*([;#]|[/][/][#])link\s+"(.+?)"/gm; while (m = re.exec(text)) { this.pushAllFiles(files, m[2]); } @@ -118,14 +123,16 @@ export class CodeProject { } loadFileDependencies(text:string, callback:LoadFilesCallback) { - var includes = this.parseIncludeDependencies(text); - var linkfiles = this.parseLinkDependencies(text); - var allfiles = includes.concat(linkfiles); + let includes = this.parseIncludeDependencies(text); + let linkfiles = this.parseLinkDependencies(text); + let allfiles = includes.concat(linkfiles); this.loadFiles(allfiles, (err:string, result?:Dependency[]) => { // set 'link' property on files that are link dependencies (must match filename) - if (result) - for (var dep of result) + if (result) { + for (let dep of result) { dep.link = linkfiles.indexOf(dep.path) >= 0; + } + } callback(err, result); }); } diff --git a/src/util.ts b/src/util.ts index 4dbea967..a7a3a8c2 100644 --- a/src/util.ts +++ b/src/util.ts @@ -320,8 +320,10 @@ export function isProbablyBinary(path:string, data?:number[] | Uint8Array) : boo // check extensions if (path) { path = path.toUpperCase(); - if (path.endsWith('.CHR') || path.endsWith('.BIN')) - score++; + const BINEXTS = ['.CHR','.BIN','.PAL','.NAM','.RLE','.LZ4']; + for (var ext of BINEXTS) { + if (path.endsWith(ext)) score++; + } } // decode as UTF-8 for (var i = 0; i < (data?data.length:0);) { diff --git a/src/views.ts b/src/views.ts index 2b3f8e12..e2050ea8 100644 --- a/src/views.ts +++ b/src/views.ts @@ -1171,13 +1171,20 @@ export class AssetEditorView implements ProjectView, pixed.EditorContext { // TODO: check fmt w/h/etc limits // TODO: defer editor creation // TODO: only refresh when needed - if (fileid.endsWith('.chr') && data instanceof Uint8Array) { + if (platform_id.startsWith('nes') && fileid.endsWith('.chr') && data instanceof Uint8Array) { // is this a NES CHR? let node = new pixed.FileDataNode(projectWindows, fileid); 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(this.ensureFileDiv(fileid), node, neschrfmt); this.registerAsset("charmap", node, true); nassets++; + } else if (platform_id.startsWith('nes') && fileid.endsWith('.pal') && data instanceof Uint8Array) { + // is this a NES PAL? + let node = new pixed.FileDataNode(projectWindows, fileid); + const nespalfmt = {pal:"nes",layout:"nes"}; + this.addPaletteEditor(this.ensureFileDiv(fileid), node, nespalfmt); + this.registerAsset("palette", node, false); + nassets++; } else if (typeof data === 'string') { let textfrags = this.scanFileTextForAssets(fileid, data); for (let frag of textfrags) {