home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / plug-ins / maze / maze.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-08-24  |  19.9 KB  |  691 lines

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