maze.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699
  1. /* $Id$
  2. * This is a plug-in for the GIMP.
  3. * It draws mazes...
  4. *
  5. * Implemented as a GIMP 0.99 Plugin by
  6. * Kevin Turner <acapnotic@users.sourceforge.net>
  7. * http://gimp-plug-ins.sourceforge.net/maze/
  8. *
  9. * Code generously borrowed from assorted GIMP plugins
  10. * and used as a template to get me started on this one. :)
  11. *
  12. * TO DO:
  13. * maze_face.c: Rework the divboxes to be more like spinbuttons.
  14. *
  15. * Maybe add an option to kill the outer border.
  16. *
  17. * Fix that stray line down there between maze wall and dead space border...
  18. *
  19. * handy.c: Make get_colors() work with indexed. * HELP! *
  20. *
  21. */
  22. /*
  23. * This program is free software; you can redistribute it and/or modify
  24. * it under the terms of the GNU General Public License as published by
  25. * the Free Software Foundation; either version 2 of the License, or
  26. * (at your option) any later version.
  27. *
  28. * This program is distributed in the hope that it will be useful,
  29. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  30. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  31. * GNU General Public License for more details.
  32. *
  33. * You should have received a copy of the GNU General Public License
  34. * along with this program; if not, write to the Free Software
  35. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  36. *
  37. */
  38. #ifndef SOLO_COMPILE
  39. #include "config.h"
  40. #endif
  41. #include <stdio.h>
  42. #include <stdlib.h>
  43. #ifdef MAZE_DEBUG
  44. #ifdef HAVE_UNISTD_H
  45. #include <unistd.h>
  46. #endif
  47. #endif
  48. #include <gtk/gtk.h>
  49. #include "libgimp/gimp.h"
  50. #include "libgimp/stdplugins-intl.h"
  51. #include "maze.h"
  52. extern gint maze_dialog (void);
  53. static void query (void);
  54. static void run (const gchar *name,
  55. gint nparams,
  56. const GimpParam *param,
  57. gint *nreturn_vals,
  58. GimpParam **return_vals);
  59. static void maze (GimpDrawable *drawable);
  60. static void mask_maze (gint32 selection_ID,
  61. guchar *maz,
  62. guint mw,
  63. guint mh,
  64. gint x1,
  65. gint x2,
  66. gint y1,
  67. gint y2,
  68. gint deadx,
  69. gint deady);
  70. /* In algorithms.c */
  71. extern void mazegen (gint pos,
  72. guchar *maz,
  73. gint x,
  74. gint y,
  75. gint rnd);
  76. extern void mazegen_tileable (gint pos,
  77. guchar *maz,
  78. gint x,
  79. gint y,
  80. gint rnd);
  81. extern void prim (guint pos,
  82. guchar *maz,
  83. guint x,
  84. guint y);
  85. extern void prim_tileable (guchar *maz,
  86. guint x,
  87. guint y);
  88. /* In handy.c */
  89. extern void get_colors (GimpDrawable *drawable,
  90. guint8 *fg,
  91. guint8 *bg);
  92. extern void drawbox (GimpPixelRgn *dest_rgn,
  93. guint x,
  94. guint y,
  95. guint w,
  96. guint h,
  97. guint8 clr[4]);
  98. GimpPlugInInfo PLUG_IN_INFO =
  99. {
  100. NULL, /* init_proc */
  101. NULL, /* quit_proc */
  102. query, /* query_proc */
  103. run, /* run_proc */
  104. };
  105. MazeValues mvals =
  106. {
  107. /* Calling parameters */
  108. 5, /* Passage width */
  109. 5, /* Passage height */
  110. 0, /* seed */
  111. FALSE, /* Tileable? */
  112. 57, /* multiple * These two had "Experiment with this?" comments */
  113. 1, /* offset * in the maz.c source, so, lets expiriment. :) */
  114. DEPTH_FIRST, /* Algorithm */
  115. };
  116. GRand *gr;
  117. guint sel_w, sel_h;
  118. MAIN () /*;*/
  119. static void
  120. query ()
  121. {
  122. static GimpParamDef args[] =
  123. {
  124. { GIMP_PDB_INT32, "run_mode", "Interactive, non-interactive" },
  125. { GIMP_PDB_IMAGE, "image_ID", "(unused)" },
  126. { GIMP_PDB_DRAWABLE, "drawable_ID", "ID of drawable" },
  127. /* If we did have parameters, these be them: */
  128. { GIMP_PDB_INT16, "width", "Width of the passages" },
  129. { GIMP_PDB_INT16, "height", "Height of the passages"},
  130. { GIMP_PDB_INT8, "tileable", "Tileable maze?"},
  131. { GIMP_PDB_INT8, "algorithm", "Generation algorithm"
  132. "(0=DEPTH FIRST, 1=PRIM'S ALGORITHM)" },
  133. { GIMP_PDB_INT32, "seed", "Random Seed"},
  134. { GIMP_PDB_INT16, "multiple", "Multiple (use 57)" },
  135. { GIMP_PDB_INT16, "offset", "Offset (use 1)" }
  136. };
  137. static GimpParamDef *return_vals = NULL;
  138. static int nreturn_vals = 0;
  139. gchar *help;
  140. help = g_strdup_printf ( "Generates a maze using either the depth-first search method or Prim's algorithm. Can make tileable mazes too. See %s for more help.", MAZE_URL);
  141. gimp_install_procedure ("plug_in_maze",
  142. "Draws a maze.",
  143. help,
  144. "Kevin Turner <kevint@poboxes.com>",
  145. "Kevin Turner",
  146. "1997, 1998",
  147. N_("<Image>/Filters/Render/Pattern/Maze..."),
  148. "RGB*, GRAY*, INDEXED*",
  149. GIMP_PLUGIN,
  150. G_N_ELEMENTS (args), nreturn_vals,
  151. args, return_vals);
  152. g_free (help);
  153. }
  154. static void
  155. run (const gchar *name,
  156. gint nparams,
  157. const GimpParam *param,
  158. gint *nreturn_vals,
  159. GimpParam **return_vals)
  160. {
  161. static GimpParam values[1];
  162. GimpDrawable *drawable;
  163. GimpRunMode run_mode;
  164. GimpPDBStatusType status = GIMP_PDB_SUCCESS;
  165. gint x1, y1, x2, y2;
  166. #ifdef MAZE_DEBUG
  167. g_print("maze PID: %d\n",getpid());
  168. #endif
  169. run_mode = param[0].data.d_int32;
  170. *nreturn_vals = 1;
  171. *return_vals = values;
  172. INIT_I18N ();
  173. gr = g_rand_new ();
  174. values[0].type = GIMP_PDB_STATUS;
  175. values[0].data.d_status = status;
  176. drawable = gimp_drawable_get (param[2].data.d_drawable);
  177. switch (run_mode)
  178. {
  179. case GIMP_RUN_INTERACTIVE:
  180. /* Possibly retrieve data */
  181. gimp_get_data ("plug_in_maze", &mvals);
  182. /* The interface needs to know the dimensions of the image... */
  183. gimp_drawable_mask_bounds (drawable->drawable_id, &x1, &y1, &x2, &y2);
  184. sel_w=x2-x1; sel_h=y2-y1;
  185. /* Acquire info with a dialog */
  186. if (! maze_dialog ()) {
  187. gimp_drawable_detach (drawable);
  188. return;
  189. }
  190. break;
  191. case GIMP_RUN_NONINTERACTIVE:
  192. if (nparams != 10)
  193. {
  194. status = GIMP_PDB_CALLING_ERROR;
  195. }
  196. if (status == GIMP_PDB_SUCCESS)
  197. {
  198. mvals.width = (gint16) param[3].data.d_int16;
  199. mvals.height = (gint16) param[4].data.d_int16;
  200. mvals.tile = (gint8) param[5].data.d_int8;
  201. mvals.algorithm = (gint8) param[6].data.d_int8;
  202. mvals.seed = (guint32) param[7].data.d_int32;
  203. mvals.multiple = (gint16) param[8].data.d_int16;
  204. mvals.offset = (gint16) param[9].data.d_int16;
  205. }
  206. break;
  207. case GIMP_RUN_WITH_LAST_VALS:
  208. /* Possibly retrieve data */
  209. gimp_get_data ("plug_in_maze", &mvals);
  210. break;
  211. default:
  212. break;
  213. }
  214. /* color, gray, or indexed... hmm, miss anything? ;) */
  215. if (gimp_drawable_is_rgb (drawable->drawable_id) ||
  216. gimp_drawable_is_gray (drawable->drawable_id) ||
  217. gimp_drawable_is_indexed (drawable->drawable_id))
  218. {
  219. maze (drawable);
  220. if (run_mode != GIMP_RUN_NONINTERACTIVE)
  221. gimp_displays_flush ();
  222. if (run_mode == GIMP_RUN_INTERACTIVE ||
  223. (run_mode == GIMP_RUN_WITH_LAST_VALS))
  224. gimp_set_data ("plug_in_maze", &mvals, sizeof (MazeValues));
  225. }
  226. else
  227. {
  228. status = GIMP_PDB_EXECUTION_ERROR;
  229. }
  230. values[0].data.d_status = status;
  231. g_rand_free (gr);
  232. gimp_drawable_detach (drawable);
  233. }
  234. #ifdef MAZE_DEBUG
  235. void
  236. maze_dump(guchar *maz, gint mw, gint mh)
  237. {
  238. short xx, yy;
  239. int foo=0;
  240. for(yy=0;yy<mh;yy++) {
  241. for(xx=0;xx<mw;xx++)
  242. g_print("%3d ",maz[foo++]);
  243. g_print("\n");
  244. }
  245. }
  246. void
  247. maze_dumpX(guchar *maz, gint mw, gint mh)
  248. {
  249. short xx, yy;
  250. int foo=0;
  251. for(yy=0;yy<mh;yy++) {
  252. for(xx=0;xx<mw;xx++)
  253. g_print("%c",maz[foo++] ? 'X' : '.');
  254. g_print("\n");
  255. }
  256. }
  257. #endif
  258. static void
  259. maze( GimpDrawable * drawable)
  260. {
  261. GimpPixelRgn dest_rgn;
  262. guint mw, mh;
  263. gint deadx, deady;
  264. guint progress, max_progress;
  265. gint x1, y1, x2, y2, x, y;
  266. gint dx, dy, xx, yy;
  267. gint maz_x, maz_xx, maz_row, maz_yy;
  268. guint8 fg[4],bg[4];
  269. gpointer pr;
  270. gboolean active_selection;
  271. guchar *maz;
  272. guint pos;
  273. /* Gets the input area... */
  274. active_selection = gimp_drawable_mask_bounds (drawable->drawable_id,
  275. &x1, &y1, &x2, &y2);
  276. /***************** Maze Stuff Happens Here ***************/
  277. mw = (x2-x1) / mvals.width;
  278. mh = (y2-y1) / mvals.height;
  279. if (!mvals.tile) {
  280. mw -= !(mw & 1); /* mazegen doesn't work with even-sized mazes. */
  281. mh -= !(mh & 1); /* Note I don't warn the user about this... */
  282. } else { /* On the other hand, tileable mazes must be even. */
  283. mw -= (mw & 1);
  284. mh -= (mh & 1);
  285. };
  286. /* It will really suck if your tileable maze ends up with this dead
  287. space around it. Oh well, life is hard. */
  288. deadx = ((x2-x1) - mw * mvals.width)/2;
  289. deady = ((y2-y1) - mh * mvals.height)/2;
  290. maz = g_new0(guchar, mw * mh);
  291. #ifdef MAZE_DEBUG
  292. printf("x: %d\ty: %d\nmw: %d\tmh: %d\ndx: %d\tdy: %d\nwidth:%d\theight: %d\n",
  293. (x2-x1),(y2-y1),mw,mh,deadx,deady,mvals.width, mvals.height);
  294. #endif
  295. /* Sanity check: */
  296. switch (mvals.algorithm) {
  297. case DEPTH_FIRST:
  298. break;
  299. case PRIMS_ALGORITHM:
  300. break;
  301. default:
  302. g_warning("maze: Invalid algorithm choice %d", mvals.algorithm);
  303. }
  304. if (mvals.tile) {
  305. switch (mvals.algorithm) {
  306. case DEPTH_FIRST:
  307. mazegen_tileable(0, maz, mw, mh, mvals.seed);
  308. break;
  309. case PRIMS_ALGORITHM:
  310. prim_tileable(maz, mw, mh);
  311. break;
  312. default:
  313. ;
  314. }
  315. } else { /* not tileable */
  316. if (active_selection) { /* Mask and draw mazes until there's no
  317. * more room left. */
  318. mask_maze(drawable->drawable_id,
  319. maz, mw, mh, x1, x2, y1, y2, deadx, deady);
  320. for(maz_yy=mw; maz_yy < (mh*mw); maz_yy += 2*mw) {
  321. for(maz_xx=1; maz_xx < mw; maz_xx += 2) {
  322. if(maz[maz_yy+maz_xx] == 0) {
  323. switch(mvals.algorithm) {
  324. case DEPTH_FIRST:
  325. mazegen(maz_yy+maz_xx, maz, mw, mh, mvals.seed);
  326. break;
  327. case PRIMS_ALGORITHM:
  328. prim(maz_yy+maz_xx, maz, mw, mh);
  329. break;
  330. default:
  331. ;
  332. } /* switch */
  333. } /* if maz[] == 0 */
  334. } /* next maz_xx */
  335. } /* next maz_yy */
  336. } else { /* No active selection. */
  337. pos=mw+1;
  338. switch(mvals.algorithm) {
  339. case DEPTH_FIRST:
  340. mazegen(pos, maz, mw, mh, mvals.seed);
  341. break;
  342. case PRIMS_ALGORITHM:
  343. prim(pos, maz, mw, mh);
  344. break;
  345. default:
  346. ;
  347. } /* switch */
  348. } /* no active selection */
  349. } /* not tileable */
  350. /************** Begin Drawing *********************/
  351. /* Initialize pixel region (?) */
  352. gimp_pixel_rgn_init (&dest_rgn, drawable, x1, y1, (x2 - x1), (y2 - y1), TRUE, TRUE);
  353. progress = 0;
  354. max_progress = (x2 - x1) * (y2 - y1);
  355. /* Get the foreground and background colors */
  356. get_colors(drawable,fg,bg);
  357. gimp_progress_init (_("Drawing Maze..."));
  358. for (pr = gimp_pixel_rgns_register (1, &dest_rgn);
  359. pr != NULL;
  360. pr = gimp_pixel_rgns_process (pr))
  361. {
  362. x = dest_rgn.x - x1 - deadx;
  363. y = dest_rgn.y - y1 - deady;
  364. /* First boxes by edge of tile must be handled specially
  365. because they may have started on a previous tile,
  366. unbeknownst to us. */
  367. dx = mvals.width - (x % mvals.width);
  368. dy = mvals.height - (y % mvals.height);
  369. maz_x = x/mvals.width;
  370. maz_row = mw * (y/mvals.height);
  371. /* Draws the upper-left [split] box */
  372. drawbox(&dest_rgn,0,0,dx,dy,
  373. (maz[maz_row+maz_x]==IN) ? fg : bg);
  374. maz_xx=maz_x+1;
  375. /* Draw the top row [split] boxes */
  376. for(xx=dx; xx < dest_rgn.w; xx+=mvals.width)
  377. { drawbox(&dest_rgn,xx,0,mvals.width,dy,
  378. (maz[maz_row + maz_xx++]==IN) ? fg : bg ); }
  379. maz_yy=maz_row+mw;
  380. /* Left column */
  381. for(yy=dy; yy < dest_rgn.h; yy+=mvals.height) {
  382. drawbox(&dest_rgn,0,yy,dx,mvals.height,
  383. (maz[maz_yy + maz_x]==IN) ? fg : bg );
  384. maz_yy += mw;
  385. }
  386. maz_x++;
  387. /* Everything else */
  388. for(yy=dy; yy < dest_rgn.h; yy+=mvals.height) {
  389. maz_xx = maz_x; maz_row+=mw;
  390. for(xx=dx; xx < dest_rgn.w; xx+=mvals.width)
  391. {
  392. drawbox(&dest_rgn,xx,yy,mvals.width,mvals.height,
  393. (maz[maz_row + maz_xx++]==IN) ? fg : bg ); }
  394. }
  395. progress += dest_rgn.w * dest_rgn.h;
  396. gimp_progress_update ((double) progress / (double) max_progress);
  397. /* Indicate progress in drawing. */
  398. }
  399. gimp_drawable_flush (drawable);
  400. gimp_drawable_merge_shadow (drawable->drawable_id, TRUE);
  401. gimp_drawable_update (drawable->drawable_id, x1, y1, (x2 - x1), (y2 - y1));
  402. }
  403. /* Shaped mazes: */
  404. /* With
  405. * Depth first: Nonzero cells will not be connected to or visited.
  406. * Prim's Algorithm:
  407. * Cells that are not IN will not be connected to.
  408. * Cells that are not OUT will not be converted to FRONTIER.
  409. *
  410. * So we'll put unavailable cells in a non-zero non-in non-out class
  411. * called MASKED.
  412. */
  413. /* But first... A little discussion about cells. */
  414. /* In the eyes of the generation algorithms, the world is made up of
  415. * two sorts of things: Cells, and the walls between them. Walls can
  416. * be knocked out, and then you have a passage between cells. The
  417. * drawing routine has a simpler view of life... Everything is a
  418. * pixel. Or a block of pixels. It makes no distinction between
  419. * passages, walls, and cells.
  420. *
  421. * We may also make the distinction between two different types of
  422. * passages: horizontal and vertical. With that in mind, a
  423. * part of the world looks something like this:
  424. *
  425. * @-@-@-@- Where @ is a cell, | is a vertical passage, and - is a
  426. * | | | | horizontal passsage.
  427. * @-@-@-@-
  428. * | | | | Remember, the maze generation routines will not rest
  429. * until the maze is full, that is, every cell is connected
  430. * to another. Already, we can determine a few things about the final
  431. * maze. We know which blocks will be cells, which blocks may become
  432. * passages (and we know what sort), and we also notice that there are
  433. * some blocks that will never be either cells or passages.
  434. *
  435. * Now, back to our masking routine... To save a little time, lets
  436. * just take sample points from the block. We'll sample a point from
  437. * the top and the bottom of vertical passages, left/right for
  438. * horizontal, and, hmm, left/right/top/bottom for cells. And of
  439. * course, we needn't concern ourselves with the others. We could
  440. * also sample the midpoint of each...
  441. * Then what we'll do is see if the average is higher than some magic
  442. * threshold number, and if so, we let maze happen there. Otherwise
  443. * we mask it out.
  444. */
  445. /* And, uh, that's on the TODO list. Looks like I spent so much time
  446. * writing comments I haven't left enough to implement the code. :)
  447. * Right now we only sample one point. */
  448. static void
  449. mask_maze(gint32 drawable_ID, guchar *maz, guint mw, guint mh,
  450. gint x1, gint x2, gint y1, gint y2, gint deadx, gint deady)
  451. {
  452. gint32 selection_ID;
  453. GimpPixelRgn sel_rgn;
  454. gint xx0=0, yy0=0, xoff, yoff;
  455. guint xx=0, yy=0;
  456. guint foo=0;
  457. gint cur_row, cur_col;
  458. gint x1half, x2half, y1half, y2half;
  459. guchar *linebuf;
  460. if ((selection_ID =
  461. gimp_image_get_selection(gimp_drawable_image_id(drawable_ID)))
  462. == -1)
  463. return;
  464. gimp_pixel_rgn_init(&sel_rgn, gimp_drawable_get(selection_ID),
  465. x1, y1, (x2-x1), (y2-y1),
  466. FALSE, FALSE);
  467. gimp_drawable_offsets(drawable_ID, &xoff, &yoff);
  468. /* Special cases: If mw or mh < 3 */
  469. /* FIXME (Currently works, but inefficiently.) */
  470. /* mw && mh => 3 */
  471. linebuf = g_new(guchar, sel_rgn.w * sel_rgn.bpp);
  472. xx0 = x1 + deadx + mvals.width + xoff;
  473. yy0 = y1 + deady + mvals.height + yoff;
  474. x1half = mvals.width/2;
  475. x2half = mvals.width - 1;
  476. y1half = mvals.height/2;
  477. y2half = mvals.height - 1;
  478. /* Here, yy is with respect to the drawable (or something),
  479. whereas xx is with respect to the row buffer. */
  480. yy=yy0 + y1half;
  481. for(cur_row=1; cur_row < mh; cur_row += 2) {
  482. gimp_pixel_rgn_get_row(&sel_rgn, linebuf, x1+xoff, yy, (x2-x1));
  483. cur_col=1; xx=mvals.width;
  484. while(cur_col < mw) {
  485. /* Cell: */
  486. maz[cur_row * mw + cur_col] =
  487. (linebuf[xx] + linebuf[xx + x1half] + linebuf[xx+x2half]) / 5;
  488. cur_col += 1;
  489. xx += mvals.width;
  490. /* Passage: */
  491. if (cur_col < mw)
  492. maz[cur_row * mw + cur_col] =
  493. (linebuf[xx] + linebuf[xx + x1half] + linebuf[xx+x2half]) / 3;
  494. cur_col += 1;
  495. xx += mvals.width;
  496. } /* next col */
  497. yy += 2 * mvals.height;
  498. } /* next cur_row += 2 */
  499. /* Done doing horizontal scans, change this from a row buffer to
  500. a column buffer. */
  501. g_free(linebuf);
  502. linebuf = g_new(guchar, sel_rgn.h * sel_rgn.bpp);
  503. /* Now xx is with respect to the drawable (or whatever),
  504. and yy is with respect to the row buffer. */
  505. xx=xx0 + x1half;
  506. for(cur_col=1; cur_col < mw; cur_col += 2) {
  507. gimp_pixel_rgn_get_col(&sel_rgn, linebuf, xx, y1, (y2-y1));
  508. cur_row=1; yy=mvals.height;
  509. while(cur_row < mh) {
  510. /* Cell: */
  511. maz[cur_row * mw + cur_col] +=
  512. (linebuf[yy] + linebuf[yy+y2half]) / 5;
  513. cur_row += 1;
  514. yy += mvals.height;
  515. /* Passage: */
  516. if (cur_row < mh)
  517. maz[cur_row * mw + cur_col] =
  518. (linebuf[yy] + linebuf[yy + y1half] + linebuf[yy+y2half]) / 3;
  519. cur_row += 1;
  520. yy += mvals.height;
  521. } /* next cur_row */
  522. xx += 2 * mvals.width;
  523. } /* next cur_col */
  524. g_free(linebuf);
  525. /* Do the alpha -> masked conversion. */
  526. for(yy=0;yy<mh;yy++) {
  527. for(xx=0;xx<mw;xx++) {
  528. maz[foo] = ( maz[foo] < MAZE_ALPHA_THRESHOLD ) ? MASKED : OUT;
  529. foo++;
  530. } /* next xx */
  531. } /* next yy*/
  532. } /* mask_maze */
  533. /* The attempt to implement this with tiles: (it wasn't fun) */
  534. #if 0
  535. /* Tiles make my life decidedly difficult here. There are too
  536. * many special cases... "What if a tile starts less/more than
  537. * halfway through a block? What if we get a narrow edge-tile
  538. * that..." etc, etc. I shall investigate other options.
  539. * Possibly a row buffer, or can we use something other than this
  540. * black-magic gimp_pixel_rgns_register call to get tiles of
  541. * different sizes? Now that'd be nice... */
  542. for (pr = gimp_pixel_rgns_register (1, &sel_rgn);
  543. pr != NULL;
  544. pr = gimp_pixel_rgns_process (pr)) {
  545. /* This gives us coordinates relative to the starting point
  546. * of the maze grid. Negative values happen here if there
  547. * is dead space. */
  548. x = sel_rgn.x - x1 - deadx;
  549. y = sel_rgn.y - y1 - deady;
  550. /* These coordinates are relative to the current tile. */
  551. /* This starts us off at the first block boundary in the
  552. * tile. */
  553. /* e.g. with x=16 and width=10.
  554. * 16 % 10 = 6
  555. * 10 - 6 = 4
  556. x: 6789!123456789!123456789!12
  557. ....|.........|.........|..
  558. xx: 0123456789!123456789!123456
  559. So to start on the boundary, begin at 4.
  560. For the case x=0, 10-0=10. So xx0 will always between 1 and width. */
  561. xx0 = mvals.width - (x % mvals.width);
  562. yy0 = mvals.height - (y % mvals.height);
  563. /* Find the corresponding row and column in the maze. */
  564. maz_x = (x+xx0)/mvals.width;
  565. maz_row = mw * ((y + yy0)/mvals.height);
  566. for (yy=yy0*sel_rgn.rowstride;
  567. yy < sel_rgn.h*sel_rgn.rowstride;
  568. yy+=(mvals.height * sel_rgn.rowstride)) {
  569. maz_xx = maz_x;
  570. for(xx=xx0*sel_rgn.bpp;
  571. xx < sel_rgn.w;
  572. xx+=mvals.width*sel_rgn.bpp) {
  573. if (sel_rgn.data[yy+xx] < MAZE_ALPHA_THRESHOLD)
  574. maz[maz_row+maz_xx]=MASKED;
  575. maz_xx++;
  576. } /* next xx */
  577. maz_row+=mw;
  578. } /* next yy */
  579. } /* next pr sel_rgn tile thing */
  580. #ifdef MAZE_DEBUG
  581. /* maze_dump(maz,mw,mh); */
  582. #endif
  583. } /* mask_maze */
  584. #endif /* 0 */