A pixel art painter geared specifically at NES pixel art. Includes export for .chr binary file as well as palette and namespace data.
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

246 行
6.7KB

  1. import {EventCaller} from "/app/js/common/EventCaller.js"
  2. /**
  3. * Object for manipulating the eight NES palettes.
  4. * @extends EventCaller
  5. */
  6. export default class NESPalette extends EventCaller{
  7. constructor(){
  8. super();
  9. this.__BGColor = 63; // Index to the background color ALL palettes MUST share.
  10. this.__palette = [
  11. // Tile/Background Palettes
  12. 0,0,0,
  13. 0,0,0,
  14. 0,0,0,
  15. 0,0,0,
  16. // Sprite Palettes
  17. 0,0,0,
  18. 0,0,0,
  19. 0,0,0,
  20. 0,0,0
  21. ];
  22. }
  23. /**
  24. * Sets one or all of the eight color palettes to the values given. By default, function
  25. * assumes the given array is for all eight palettes (or 25 total color indexes, 3 per palette
  26. * and 1 background/transparency color used by ALL palettes).
  27. * If a single palette is being set, the array must only contain 3 entries.
  28. * @param {Array} apci - Array of color indexes to store into the palette(s)
  29. * @param {number} [p=8] - Zero-based index of the palette being set. Any value outside the range of 0 - 7 will set ALL palettes.
  30. * @returns {this}
  31. */
  32. set_palette(apci, p=8){
  33. if (typeof(p) != 'number')
  34. throw new TypeError("First argument expected to be a number.");
  35. if (!(apci instanceof Array))
  36. throw new TypeError("Expected an array of color index values.");
  37. if (p < 0 || p >= 8){ // Setting ALL palettes!
  38. if (apci.length != 25)
  39. throw new RangeError("Color array must contain 25 color values to fill all palettes.");
  40. this.__BGColor = apci[0];
  41. for (var i=0; i < 24; i++){
  42. if (typeof(apci[i+1]) == 'number'){
  43. this.__palette[i] = apci[i+1]
  44. }
  45. }
  46. } else { // Setting a specific palette.
  47. if (apci.length != 3)
  48. throw new RangeError("Color array must contain three color values.");
  49. p *= 3;
  50. for (var i=0; i < 4; i++){
  51. if (typeof(apci[i]) === 'number'){
  52. this.__palette[p+i] = apci[i];
  53. }
  54. }
  55. }
  56. this.emit("palettes_changed", {type:"ALL"});
  57. return this;
  58. }
  59. /**
  60. * Sets a palette's color index value to a given system color index.
  61. * NOTE: Setting palette color index 0 for ANY palette changes that index for ALL palettes.
  62. * @param {number} p - The index of the palette being set.
  63. * @param {number} pci - The palette color index (0 - 3) to set.
  64. * @param {number} sci - The system color index (0 - 63) value to set to.
  65. * @returns {this}
  66. */
  67. set_palette_syscolor_index(p, pci, sci){
  68. if (typeof(p) != 'number' || typeof(pci) != 'number' || typeof(sci) != 'number')
  69. throw new TypeError("Palette, palette color, and system color index expected to be numbers.");
  70. if (p < 0 || p >= 8){
  71. throw new RangeError("Palette index is out of bounds.");
  72. }
  73. if (pci < 0 || pci >= 4){
  74. throw new RangeError("Palette color index is out of bounds.");
  75. }
  76. if (sci < 0 || sci >= 64){
  77. throw new RangeError("System color index is out of bounds.");
  78. }
  79. if (pci == 0){
  80. this.__BGColor = sci;
  81. this.emit("palettes_changed", {type:"ALL", cindex:0});
  82. } else {
  83. this.__palette[(p*3) + (pci-1)] = sci;
  84. this.emit("palettes_changed", {type:(p < 4) ? "TILE" : "SPRITE", pindex:p, cindex:pci});
  85. }
  86. return this;
  87. }
  88. /**
  89. * Returns the system color index at the given palette color index.
  90. * @param {number} p - The index (0 - 7) of the palette.
  91. * @param {number} pci - The palette color index (0 - 3).
  92. * @returns {number} - The index of the system color used.
  93. */
  94. get_palette_syscolor_index(p, pci){
  95. if (typeof(p) != 'number' || typeof(pci) != 'number')
  96. throw new TypeError("Palette and color index expected to be numbers.");
  97. if (p < 0 || p >= 8){
  98. throw new RangeError("Palette index is out of bounds.");
  99. }
  100. if (pci < 0 || pci >= 4){
  101. throw new RangeError("Palette color index is out of bounds.");
  102. }
  103. return (pci === 0) ? this.__BGColor : this.__palette[(p*3)+(pci-1)];
  104. }
  105. /**
  106. * Returns a hex string color value used by the NES system at the index stored at the given
  107. * palette color index.
  108. * @param {number} p - The index (0 - 7) of the palette.
  109. * @param {number} pci - The palette color index (0 - 3).
  110. * @returns {string}
  111. */
  112. get_palette_color(p, pci){
  113. if (typeof(p) != 'number' || typeof(pci) != 'number')
  114. throw new TypeError("Palette and color index expected to be numbers.");
  115. if (p < 0 || p >= 8){
  116. throw new RangeError("Palette index is out of bounds.");
  117. }
  118. if (pci < 0 || pci >= 4){
  119. throw new RangeError("Palette color index is out of bounds.");
  120. }
  121. return NESPalette.SystemColor[this.get_palette_syscolor_index(p, pci)];
  122. }
  123. /**
  124. * Generates a small 6502 assembly block string containing the current palette data.
  125. * @param {string} [memname="PaletteData"] The label named under which to store the data.
  126. * @returns {string}
  127. */
  128. to_asm(memname="PaletteData"){
  129. var NumToHex=function(n){
  130. var h = n.toString(16);
  131. if (h.length %2)
  132. h = '0' + h;
  133. return '$' + h;
  134. };
  135. var BGHex = NumToHex(this.__BGColor);
  136. var s = memname + ":\n\t.db ";
  137. // Storing background palette data.
  138. for (var i=0; i < 12; i++){
  139. if (i % 3 == 0)
  140. s += ((i == 0) ? "" : " ") + BGHex;
  141. s += " " + NumToHex(this.__palette[i]);
  142. }
  143. s += "\t; Background palette data.\n\t.db ";
  144. // Storing foreground palette data.
  145. for (var i=12; i < 24; i++){
  146. if (i % 3 == 0)
  147. s += ((i == 12) ? "" : " ") + BGHex;
  148. s += " " + NumToHex(this.__palette[i]);
  149. }
  150. s += "\t; Foreground palette data.";
  151. return s;
  152. }
  153. }
  154. // NES Palette color information comes from the following site...
  155. // http://www.thealmightyguru.com/Games/Hacking/Wiki/index.php/NES_Palette
  156. /**
  157. * Hex string color values representing the NES system palette.
  158. */
  159. NESPalette.SystemColor = [
  160. "#7C7C7C",
  161. "#0000FC",
  162. "#0000BC",
  163. "#4428BC",
  164. "#940084",
  165. "#A80020",
  166. "#A81000",
  167. "#881400",
  168. "#503000",
  169. "#007800",
  170. "#006800",
  171. "#005800",
  172. "#004058",
  173. "#000000",
  174. "#000000",
  175. "#000000",
  176. "#BCBCBC",
  177. "#0078F8",
  178. "#0058F8",
  179. "#6844FC",
  180. "#D800CC",
  181. "#E40058",
  182. "#F83800",
  183. "#E45C10",
  184. "#AC7C00",
  185. "#00B800",
  186. "#00A800",
  187. "#00A844",
  188. "#008888",
  189. "#000000",
  190. "#000000",
  191. "#000000",
  192. "#F8F8F8",
  193. "#3CBCFC",
  194. "#6888FC",
  195. "#9878F8",
  196. "#F878F8",
  197. "#F85898",
  198. "#F87858",
  199. "#FCA044",
  200. "#F8B800",
  201. "#B8F818",
  202. "#58D854",
  203. "#58F898",
  204. "#00E8D8",
  205. "#787878",
  206. "#000000",
  207. "#000000",
  208. "#FCFCFC",
  209. "#A4E4FC",
  210. "#B8B8F8",
  211. "#D8B8F8",
  212. "#F8B8F8",
  213. "#F8A4C0",
  214. "#F0D0B0",
  215. "#FCE0A8",
  216. "#F8D878",
  217. "#D8F878",
  218. "#B8F8B8",
  219. "#B8F8D8",
  220. "#00FCFC",
  221. "#F8D8F8",
  222. "#000000",
  223. "#000000"
  224. ];
  225. NESPalette.Default = [
  226. "#080808",
  227. "#343434",
  228. "#a2a2a2",
  229. "#efefef",
  230. "#666666" // Out of bounds color.
  231. ];