ersatzben

V8UI code for grid painting

Jul 4th, 2025
453
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.90 KB | None | 0 0
  1. // V8UI OBJECT CODE FOR PAINTING IN A GRID
  2.  
  3. inlets = 2; // inlet 0: bang for redraw, inlet 1: bang for random paint
  4. outlets = 1; // for outputting matrix data
  5.  
  6. mgraphics.init();
  7. mgraphics.autofill = 0;
  8. mgraphics.relative_coords = 0;
  9.  
  10. var gridSize = 32; // grid size
  11. var canvasSize = 450; // 450x450 pixels
  12. var cellSize = canvasSize / gridSize; // pixels per cell
  13. var fadeTime = 2500; // ms until stroke fully disappears
  14. var brushRadius = 2; // cells (radius from center)
  15. var fadeCurve = 2;
  16.  
  17. // Grid data: each cell stores array of {intensity, timestamp} values
  18. var grid = [];
  19. var maxIntensityPerCell = 1.0; // cap intensity accumulation
  20.  
  21. // Initialize grid
  22. function initGrid() {
  23. grid = [];
  24. for (var y = 0; y < gridSize; y++) {
  25. grid[y] = [];
  26. for (var x = 0; x < gridSize; x++) {
  27. grid[y][x] = []; // array of {intensity, t} objects
  28. }
  29. }
  30. }
  31.  
  32. function loadbang() {
  33. this.box.message("size", canvasSize, canvasSize);
  34. initGrid();
  35. post("Grid initialized: " + gridSize + "x" + gridSize + " cells\n");
  36. post("Fade curve: " + fadeCurve + " (try 'curve 1.0' for linear, 'curve 2.0' for quadratic, 'curve 3.0' for cubic)\n");
  37. post("Inlet 0: bang for redraw, Inlet 1: bang for random paint\n");
  38. }
  39.  
  40. // inlet 0: bang from [qmetro n] — forces redraw every n ms
  41. function bang() {
  42. if (inlet === 0) {
  43. mgraphics.redraw();
  44. } else if (inlet === 1) {
  45. // Generate random paint stroke
  46. var randomX = Math.random() * canvasSize;
  47. var randomY = Math.random() * canvasSize;
  48. paintGrid(randomX, randomY);
  49. // Optionally trigger a redraw immediately to see the stroke
  50. mgraphics.redraw();
  51. }
  52. }
  53.  
  54. // set fade duration with 'fade n'
  55. function fade(n) {
  56. fadeTime = Math.max(1, n);
  57. }
  58.  
  59. // set fade curve with 'curve n' (1.0 = linear, 2.0 = quadratic, 3.0 = cubic, etc.)
  60. function curve(n) {
  61. fadeCurve = Math.max(0.1, n);
  62. post("Fade curve: " + fadeCurve + " (1.0=linear, >1.0=exponential)\n");
  63. }
  64.  
  65. // set grid size with 'gridsize n'
  66. function gridsize(n) {
  67. gridSize = Math.max(1, Math.min(100, n)); // limit between 1-100
  68. cellSize = canvasSize / gridSize;
  69. initGrid();
  70. post("Grid size changed to: " + gridSize + "x" + gridSize + "\n");
  71. }
  72.  
  73. // set brush radius with 'radius n'
  74. function radius(n) {
  75. brushRadius = Math.max(1, n);
  76. post("Brush radius: " + brushRadius + " cells\n");
  77. }
  78.  
  79. // Convert pixel coordinates to grid coordinates
  80. function pixelToGrid(x, y) {
  81. return {
  82. x: Math.floor(x / cellSize),
  83. y: Math.floor(y / cellSize)
  84. };
  85. }
  86.  
  87. // Add intensity to grid cells in brush pattern
  88. function paintGrid(centerX, centerY) {
  89. // Safety check: ensure grid is initialised
  90. if (!grid || grid.length === 0) {
  91. initGrid();
  92. }
  93.  
  94. var now = Date.now();
  95. var gridPos = pixelToGrid(centerX, centerY);
  96.  
  97. // Paint center cell and surrounding cells based on distance
  98. for (var dy = -brushRadius; dy <= brushRadius; dy++) {
  99. for (var dx = -brushRadius; dx <= brushRadius; dx++) {
  100. var x = gridPos.x + dx;
  101. var y = gridPos.y + dy;
  102.  
  103. // Check bounds
  104. if (x >= 0 && x < gridSize && y >= 0 && y < gridSize) {
  105. // Calculate distance from center (using Euclidean distance)
  106. var distance = Math.sqrt(dx * dx + dy * dy);
  107.  
  108. if (distance <= brushRadius) {
  109. // Calculate intensity based on distance (1.0 at center, 0.0 at edge)
  110. var intensity = Math.max(0, 1.0 - (distance / brushRadius));
  111.  
  112. // Add this paint stroke to the cell
  113. grid[y][x].push({
  114. intensity: intensity,
  115. t: now
  116. });
  117. }
  118. }
  119. }
  120. }
  121. }
  122.  
  123. // v8ui mouse callbacks
  124. function onclick(x, y, button) {
  125. if (button) { // only paint if button is pressed
  126. paintGrid(x, y);
  127. }
  128. }
  129.  
  130. function ondrag(x, y, button) {
  131. if (button) { // only paint while button is held down
  132. paintGrid(x, y);
  133. }
  134. }
  135.  
  136. // Calculate current intensity for a cell (sum of all non-faded strokes)
  137. function getCurrentCellIntensity(x, y) {
  138. // Safety check: ensure grid is initialised
  139. if (!grid || !grid[y] || !grid[y][x]) {
  140. return 0;
  141. }
  142.  
  143. var now = Date.now();
  144. var totalIntensity = 0;
  145. var cell = grid[y][x];
  146.  
  147. // Remove faded strokes and sum remaining intensities
  148. grid[y][x] = cell.filter(function(stroke) {
  149. var age = now - stroke.t;
  150. if (age < fadeTime) {
  151. // Linear fade (0.0 to 1.0)
  152. var linearFade = 1 - (age / fadeTime);
  153.  
  154. // Apply exponential curve for more musical fade
  155. var ageAlpha = Math.pow(linearFade, fadeCurve);
  156.  
  157. totalIntensity += stroke.intensity * ageAlpha;
  158. return true;
  159. }
  160. return false;
  161. });
  162.  
  163. return Math.min(totalIntensity, maxIntensityPerCell);
  164. }
  165.  
  166. // Output current grid state as matrix
  167. function output() {
  168. // Safety check: ensure grid is initialised
  169. if (!grid || grid.length === 0) {
  170. post("Grid not initialized, cannot output matrix\n");
  171. return;
  172. }
  173.  
  174. var matrix = [];
  175. for (var y = 0; y < gridSize; y++) {
  176. var row = [];
  177. for (var x = 0; x < gridSize; x++) {
  178. row.push(getCurrentCellIntensity(x, y));
  179. }
  180. matrix.push(row);
  181. }
  182.  
  183. // Send matrix data out outlet 0
  184. outlet(0, "matrix", JSON.stringify(matrix));
  185. // post("Matrix output: " + gridSize + "x" + gridSize + " intensities\n");
  186. }
  187.  
  188. // Output current grid state as flat list
  189. function outputlist() {
  190. // Safety check: ensure grid is initialised
  191. if (!grid || grid.length === 0) {
  192. post("Grid not initialized, cannot output list\n");
  193. return;
  194. }
  195.  
  196. var flatList = [];
  197. for (var y = 0; y < gridSize; y++) {
  198. for (var x = 0; x < gridSize; x++) {
  199. flatList.push(getCurrentCellIntensity(x, y));
  200. }
  201. }
  202.  
  203. // Send as list out outlet 0 (row-major order: row0, row1, row2, ...)
  204. outlet(0, "list", flatList);
  205. // post("List output: " + flatList.length + " values (" + gridSize + "x" + gridSize + " grid)\n");
  206. }
  207.  
  208. // Clear the grid
  209. function clear() {
  210. initGrid();
  211. mgraphics.redraw();
  212. post("Grid cleared\n");
  213. }
  214.  
  215. function paint() {
  216. var w = this.box.rect[2];
  217. var h = this.box.rect[3];
  218.  
  219. // Background
  220. mgraphics.set_source_rgba(0, 0, 0, 1);
  221. mgraphics.rectangle(0, 0, w, h);
  222. mgraphics.fill();
  223.  
  224. // Safety check: ensure grid is initialized
  225. if (!grid || grid.length === 0) {
  226. initGrid();
  227. return;
  228. }
  229.  
  230. // Draw grid cells
  231. for (var y = 0; y < gridSize; y++) {
  232. for (var x = 0; x < gridSize; x++) {
  233. var intensity = getCurrentCellIntensity(x, y);
  234.  
  235. if (intensity > 0) {
  236. // Cell position in pixels
  237. var cellX = x * cellSize;
  238. var cellY = y * cellSize;
  239.  
  240. // Draw cell with intensity-based alpha
  241. mgraphics.set_source_rgba(0, 1, 1, intensity);
  242. mgraphics.rectangle(cellX, cellY, cellSize, cellSize);
  243. mgraphics.fill();
  244. }
  245. }
  246. }
  247.  
  248. // Draw grid lines
  249. mgraphics.set_source_rgba(0.2, 0.2, 0.2, 0.3);
  250. mgraphics.set_line_width(1);
  251. for (var i = 0; i <= gridSize; i++) {
  252. var pos = i * cellSize;
  253. // Vertical lines
  254. mgraphics.move_to(pos, 0);
  255. mgraphics.line_to(pos, h);
  256. // Horizontal lines
  257. mgraphics.move_to(0, pos);
  258. mgraphics.line_to(w, pos);
  259. }
  260. mgraphics.stroke();
  261.  
  262. }
Advertisement
Add Comment
Please, Sign In to add comment