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文字以内のものにしてください。

172 行
3.8KB

  1. import NESPalette from "/app/js/models/NESPalette.js";
  2. function BitMask(offset){
  3. switch(offset){
  4. case 0:
  5. return 63; // Mask '00111111'
  6. case 1:
  7. return 207; // Mask '11001111'
  8. case 2:
  9. return 243; // Mask '11110011'
  10. }
  11. return 252; // Mask '11111100'
  12. }
  13. function SetDataArrayColor(arr, x, y, ci){
  14. var index = (y*8)+x;
  15. var dindex = Math.floor(index*0.25);
  16. var bitoffset = (index % 4);
  17. arr[dindex] = (arr[dindex] & BitMask(bitoffset)) ^ (ci << ((3 - bitoffset)*2));
  18. //if (dindex === 1){
  19. // console.log("index: ", dindex, " | value: ", arr[dindex], " | (x,y): (", x, ",", y, ") | Bit Offset: ", bitoffset, "Color: ", ci);
  20. //}
  21. }
  22. function GetDataArrayColor(arr, x, y){
  23. var index = (y*8)+x;
  24. var dindex = Math.floor(index*0.25);
  25. var bitoffset = 6 - ((index % 4) * 2);
  26. return (arr[dindex] & (3 << bitoffset)) >> bitoffset;
  27. }
  28. export default class NESTile{
  29. constructor(){
  30. this.__palette = null;
  31. this.__paletteIndex = 0;
  32. this.__data = new Uint8Array(16);
  33. }
  34. get dataArray(){
  35. var d = [];
  36. for (var x = 0; x < 8; x++){
  37. for (var y = 0; y < 8; y++){
  38. d.push(this.getPixelIndex(x, y));
  39. }
  40. }
  41. return d;
  42. }
  43. get base64(){
  44. var b = ""
  45. for (var i = 0; i < this.__data.length; i++) {
  46. b += String.fromCharCode(this.__data[i]);
  47. }
  48. return window.btoa(b);
  49. }
  50. set base64(s){
  51. var b = window.atob(s);
  52. var len = b.length;
  53. if (b.length !== 16){
  54. throw new Error("Base64 string contains invalid byte count.");
  55. }
  56. var bytes = new Uint8Array(b.length);
  57. for (var i=0; i < b.length; i++){
  58. bytes[i] = b.charCodeAt(i);
  59. }
  60. this.__data = bytes;
  61. }
  62. get palette(){return this.__palette;}
  63. set palette(p){
  64. if (p !== null && !(p instanceof NESPalette)){
  65. throw new TypeError("Expected NESPalette instance or null.");
  66. }
  67. this.__palette = p;
  68. }
  69. setPixelIndex(x, y, ci){
  70. if (x < 0 || x >= 8 || y < 0 || y >= 8){
  71. throw new ValueError("Coordinates out of bounds.");
  72. }
  73. if (ci < 0 || ci >= 4){
  74. throw new ValueError("Color index out of bounds.");
  75. }
  76. SetDataArrayColor(this.__data, x, y, ci);
  77. return this;
  78. }
  79. getPixelIndex(x, y){
  80. if (x < 0 || x >= 8 || y < 0 || y >= 8){
  81. throw new ValueError("Coordinates out of bounds.");
  82. }
  83. return GetDataArrayColor(this.__data, x, y);
  84. }
  85. getPixel(x, y){
  86. var ci = 0;
  87. try {
  88. ci = this.getPixelIndex(x, y);
  89. } catch (e) {
  90. throw e;
  91. }
  92. if (this.__palette !== null){
  93. return this.__palette.get_palette_color(this.__paletteIndex, ci);
  94. }
  95. switch(ci){
  96. case 1:
  97. return "#555555";
  98. case 2:
  99. return "#AAAAAA";
  100. case 3:
  101. return "#FFFFFF";
  102. }
  103. return 0;
  104. }
  105. flip(flag){
  106. if (flag >= 1 && flag <= 3){
  107. var newData = new Uint8Array(16);
  108. for (var x = 0; x < 8; x++){
  109. for (var y = 0; y < 8; y++){
  110. var ci = GetDataArrayColor(this.__data, x, y);
  111. SetDataArrayColor(
  112. newData,
  113. (flag == 1 || flag == 3) ? 7 - x: x,
  114. (flag == 2 || flag == 3) ? 7 - y: y,
  115. ci
  116. );
  117. //console.log(newData);
  118. //newData[r[0]] = 2;
  119. //newData[r[0]] = r[1];
  120. }
  121. }
  122. //console.log(newData);
  123. this.__data = newData;
  124. }
  125. return this;
  126. }
  127. clone(){
  128. var t = new NESTile();
  129. t.base64 = this.base64;
  130. return t;
  131. }
  132. isEq(tile){
  133. if (!(tile instanceof NESTile)){
  134. throw new TypeError("Expected NESTile instance.");
  135. }
  136. var b64 = this.base64;
  137. if (tile.base64 === b64){
  138. return 0;
  139. }
  140. if (tile.clone().flip(1).base64 === b64){
  141. return 1;
  142. }
  143. if (tile.clone().flip(2).base64 === b64){
  144. return 2;
  145. }
  146. if (tile.clone().flip(3).base64 === b64){
  147. return 3;
  148. }
  149. return -1;
  150. }
  151. }