1998-05-18 00:33:13 +00:00
/* maze.c
1997-11-24 22:05:25 +00:00
* This is a plug - in for the GIMP .
1998-01-14 05:44:12 +00:00
* It draws mazes . . .
1997-11-24 22:05:25 +00:00
*
* Implemented as a GIMP 0.99 Plugin by
* Kevin Turner < kevint @ poboxes . com >
* http : //www.poboxes.com/kevint/gimp/maze.html
*
* Code generously borrowed from assorted GIMP plugins
* and used as a template to get me started on this one . : )
*
* TO DO :
1998-05-18 00:33:13 +00:00
* maze_face . c : Rework the divboxes to be more like spinbuttons .
1998-03-09 01:45:26 +00:00
*
1998-05-18 00:33:13 +00:00
* Maybe add an option to kill the outer border .
1997-11-24 22:05:25 +00:00
*
* Fix that stray line down there between maze wall and dead space border . . .
*
1998-05-18 00:33:13 +00:00
* handy . c : Make get_colors ( ) work with indexed . * HELP ! *
1997-11-24 22:05:25 +00:00
*
*/
/*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
1998-05-18 00:33:13 +00:00
* Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
1997-11-24 22:05:25 +00:00
*
*/
1999-05-29 01:28:24 +00:00
# include "config.h"
1997-11-24 22:05:25 +00:00
# include <stdio.h>
# include <stdlib.h>
1999-05-29 01:28:24 +00:00
# ifdef MAZE_DEBUG
# ifdef HAVE_UNISTD_H
1998-05-18 00:33:13 +00:00
# include <unistd.h>
1998-02-20 10:41:20 +00:00
# endif
1999-05-29 01:28:24 +00:00
# endif
1998-02-20 10:41:20 +00:00
# include <time.h> /* For random seeding */
1999-05-29 01:28:24 +00:00
2000-01-01 15:38:59 +00:00
# include <gtk/gtk.h>
# include "libgimp/gimp.h"
# include "libgimp/stdplugins-intl.h"
1999-05-29 01:28:24 +00:00
1998-02-20 10:41:20 +00:00
# include "maze.h"
1997-11-24 22:05:25 +00:00
1998-02-20 10:41:20 +00:00
extern gint maze_dialog ( void ) ;
1997-11-24 22:05:25 +00:00
static void query ( void ) ;
static void run ( gchar * name ,
gint nparams ,
GParam * param ,
gint * nreturn_vals ,
GParam * * return_vals ) ;
static void maze ( GDrawable * drawable ) ;
1998-05-18 00:33:13 +00:00
static void mask_maze ( gint32 selection_ID , guchar * maz , guint mw , guint mh ,
gint x1 , gint x2 , gint y1 , gint y2 , gint deadx , gint deady ) ;
/* In algorithms.c */
extern void mazegen ( gint pos ,
guchar * maz ,
1997-11-24 22:05:25 +00:00
gint x ,
gint y ,
gint rnd ) ;
1998-05-18 00:33:13 +00:00
extern void mazegen_tileable ( gint pos ,
guchar * maz ,
1998-01-14 05:44:12 +00:00
gint x ,
gint y ,
gint rnd ) ;
1998-05-18 00:33:13 +00:00
extern void prim ( guint pos ,
guchar * maz ,
guint x ,
guint y ,
gint rnd ) ;
extern void prim_tileable ( guchar * maz ,
guint x ,
guint y ,
gint rnd ) ;
/* In handy.c */
extern void get_colors ( GDrawable * drawable ,
1997-11-24 22:05:25 +00:00
guint8 * fg ,
guint8 * bg ) ;
1998-05-18 00:33:13 +00:00
extern void drawbox ( GPixelRgn * dest_rgn ,
1997-11-24 22:05:25 +00:00
guint x ,
guint y ,
guint w ,
guint h ,
guint8 clr [ 4 ] ) ;
GPlugInInfo PLUG_IN_INFO =
{
NULL , /* init_proc */
NULL , /* quit_proc */
query , /* query_proc */
run , /* run_proc */
} ;
1998-02-20 10:41:20 +00:00
MazeValues mvals =
1997-11-24 22:05:25 +00:00
{
1998-02-20 10:41:20 +00:00
/* Calling parameters */
5 , /* Passage width */
5 , /* Passage height */
1997-11-24 22:05:25 +00:00
0 , /* seed */
1998-01-14 05:44:12 +00:00
FALSE , /* Tileable? */
1997-11-24 22:05:25 +00:00
57 , /* multiple * These two had "Experiment with this?" comments */
1998-02-20 10:41:20 +00:00
1 , /* offset * in the maz.c source, so, lets expiriment. :) */
1998-05-18 00:33:13 +00:00
DEPTH_FIRST , /* Algorithm */
1998-02-20 10:41:20 +00:00
/* Interface options */
TRUE /* Time seed? */
1997-11-24 22:05:25 +00:00
} ;
1998-02-20 10:41:20 +00:00
guint sel_w , sel_h ;
1997-11-24 22:05:25 +00:00
1998-01-14 05:44:12 +00:00
MAIN ( ) /*;*/
1997-11-24 22:05:25 +00:00
static void
query ( )
{
static GParamDef args [ ] =
{
{ PARAM_INT32 , " run_mode " , " Interactive, non-interactive " } ,
1998-05-18 00:33:13 +00:00
{ PARAM_IMAGE , " image_ID " , " (unused) " } ,
{ PARAM_DRAWABLE , " drawable_ID " , " ID of drawable " } ,
1997-11-24 22:05:25 +00:00
/* If we did have parameters, these be them: */
1998-05-18 00:33:13 +00:00
{ PARAM_INT16 , " width " , " Width of the passages " } ,
{ PARAM_INT16 , " height " , " Height of the passages " } ,
{ PARAM_INT8 , " tileable " , " Tileable maze? " } ,
{ PARAM_INT8 , " algorithm " , " Generation algorithm "
" (0=DEPTH FIRST, 1=PRIM'S ALGORITHM) " } ,
{ PARAM_INT32 , " seed " , " Random Seed " } ,
{ PARAM_INT16 , " multiple " , " Multiple (use 57) " } ,
{ PARAM_INT16 , " offset " , " Offset (use 1) " }
1997-11-24 22:05:25 +00:00
} ;
static GParamDef * return_vals = NULL ;
static int nargs = sizeof ( args ) / sizeof ( args [ 0 ] ) ;
static int nreturn_vals = 0 ;
2000-01-01 15:38:59 +00:00
gchar * help ;
1997-11-24 22:05:25 +00:00
2000-02-12 13:02:19 +00:00
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 ) ;
1997-11-24 22:05:25 +00:00
gimp_install_procedure ( " plug_in_maze " ,
2000-01-31 02:32:30 +00:00
" Draws a maze. " ,
2000-01-01 15:38:59 +00:00
help ,
1997-11-24 22:05:25 +00:00
" Kevin Turner <kevint@poboxes.com> " ,
" Kevin Turner " ,
1998-05-18 00:33:13 +00:00
" 1997, 1998 " ,
2000-01-01 15:38:59 +00:00
N_ ( " <Image>/Filters/Render/Pattern/Maze... " ) ,
1997-11-24 22:05:25 +00:00
" RGB*, GRAY*, INDEXED* " ,
PROC_PLUG_IN ,
nargs , nreturn_vals ,
args , return_vals ) ;
2000-01-01 15:38:59 +00:00
g_free ( help ) ;
1997-11-24 22:05:25 +00:00
}
static void
run ( gchar * name ,
gint nparams ,
GParam * param ,
gint * nreturn_vals ,
GParam * * return_vals )
{
1998-02-20 10:41:20 +00:00
static GParam values [ 1 ] ;
1997-11-24 22:05:25 +00:00
GDrawable * drawable ;
GRunModeType run_mode ;
GStatusType status = STATUS_SUCCESS ;
1998-02-20 10:41:20 +00:00
gint x1 , y1 , x2 , y2 ;
1997-11-24 22:05:25 +00:00
1998-02-20 10:41:20 +00:00
# ifdef MAZE_DEBUG
g_print ( " maze PID: %d \n " , getpid ( ) ) ;
# endif
1997-11-24 22:05:25 +00:00
run_mode = param [ 0 ] . data . d_int32 ;
* nreturn_vals = 1 ;
* return_vals = values ;
2000-01-01 15:38:59 +00:00
INIT_I18N_UI ( ) ;
1997-11-24 22:05:25 +00:00
values [ 0 ] . type = PARAM_STATUS ;
values [ 0 ] . data . d_status = status ;
drawable = gimp_drawable_get ( param [ 2 ] . data . d_drawable ) ;
switch ( run_mode )
{
case RUN_INTERACTIVE :
/* Possibly retrieve data */
gimp_get_data ( " plug_in_maze " , & mvals ) ;
1998-02-20 10:41:20 +00:00
/* The interface needs to know the dimensions of the image... */
gimp_drawable_mask_bounds ( drawable - > id , & x1 , & y1 , & x2 , & y2 ) ;
sel_w = x2 - x1 ; sel_h = y2 - y1 ;
1997-11-24 22:05:25 +00:00
/* Acquire info with a dialog */
if ( ! maze_dialog ( ) ) {
gimp_drawable_detach ( drawable ) ;
return ;
}
break ;
case RUN_NONINTERACTIVE :
1998-05-18 00:33:13 +00:00
if ( nparams ! = 10 )
1997-11-24 22:05:25 +00:00
{
status = STATUS_CALLING_ERROR ;
}
if ( status = = STATUS_SUCCESS )
{
1998-06-07 08:26:38 +00:00
mvals . width = ( gint16 ) param [ 3 ] . data . d_int16 ;
mvals . height = ( gint16 ) param [ 4 ] . data . d_int16 ;
mvals . tile = ( gint8 ) param [ 5 ] . data . d_int8 ;
mvals . algorithm = ( gint8 ) param [ 6 ] . data . d_int8 ;
1998-05-18 00:33:13 +00:00
mvals . seed = ( gint32 ) param [ 7 ] . data . d_int32 ;
1998-06-07 08:26:38 +00:00
mvals . multiple = ( gint16 ) param [ 8 ] . data . d_int16 ;
mvals . offset = ( gint16 ) param [ 9 ] . data . d_int16 ;
1997-11-24 22:05:25 +00:00
}
break ;
case RUN_WITH_LAST_VALS :
/* Possibly retrieve data */
gimp_get_data ( " plug_in_maze " , & mvals ) ;
break ;
default :
break ;
}
/* color, gray, or indexed... hmm, miss anything? ;) */
1999-10-24 20:49:09 +00:00
if ( gimp_drawable_is_rgb ( drawable - > id ) | | gimp_drawable_is_gray ( drawable - > id ) | | gimp_drawable_is_indexed ( drawable - > id ) ) {
1997-11-24 22:05:25 +00:00
maze ( drawable ) ;
if ( run_mode ! = RUN_NONINTERACTIVE )
gimp_displays_flush ( ) ;
1998-02-20 10:41:20 +00:00
if ( run_mode = = RUN_INTERACTIVE | |
( mvals . timeseed & & run_mode = = RUN_WITH_LAST_VALS ) )
1997-11-24 22:05:25 +00:00
gimp_set_data ( " plug_in_maze " , & mvals , sizeof ( MazeValues ) ) ;
} else {
status = STATUS_EXECUTION_ERROR ;
}
values [ 0 ] . data . d_status = status ;
gimp_drawable_detach ( drawable ) ;
}
1998-05-18 00:33:13 +00:00
# ifdef MAZE_DEBUG
void
maze_dump ( guchar * maz , gint mw , gint mh )
{
short xx , yy ;
int foo = 0 ;
for ( yy = 0 ; yy < mh ; yy + + ) {
for ( xx = 0 ; xx < mw ; xx + + )
g_print ( " %3d " , maz [ foo + + ] ) ;
g_print ( " \n " ) ;
}
}
void
maze_dumpX ( guchar * maz , gint mw , gint mh )
{
short xx , yy ;
int foo = 0 ;
for ( yy = 0 ; yy < mh ; yy + + ) {
for ( xx = 0 ; xx < mw ; xx + + )
g_print ( " %c " , maz [ foo + + ] ? ' X ' : ' . ' ) ;
g_print ( " \n " ) ;
}
}
# endif
1997-11-24 22:05:25 +00:00
static void
maze ( GDrawable * drawable )
{
GPixelRgn dest_rgn ;
1998-05-18 00:33:13 +00:00
guint mw , mh ;
1997-11-24 22:05:25 +00:00
gint deadx , deady ;
1998-05-18 00:33:13 +00:00
guint progress , max_progress ;
1997-11-24 22:05:25 +00:00
gint x1 , y1 , x2 , y2 , x , y ;
gint dx , dy , xx , yy ;
1998-05-18 00:33:13 +00:00
gint maz_x , maz_xx , maz_row , maz_yy ;
1997-11-24 22:05:25 +00:00
guint8 fg [ 4 ] , bg [ 4 ] ;
gpointer pr ;
1998-05-18 00:33:13 +00:00
gboolean active_selection ;
1997-11-24 22:05:25 +00:00
1998-05-18 00:33:13 +00:00
guchar * maz ;
guint pos ;
1997-11-24 22:05:25 +00:00
/* Gets the input area... */
1998-05-18 00:33:13 +00:00
active_selection = gimp_drawable_mask_bounds ( drawable - > id , & x1 , & y1 , & x2 , & y2 ) ;
1997-11-24 22:05:25 +00:00
1998-05-18 00:33:13 +00:00
/***************** Maze Stuff Happens Here ***************/
1997-11-24 22:05:25 +00:00
mw = ( x2 - x1 ) / mvals . width ;
1998-02-20 10:41:20 +00:00
mh = ( y2 - y1 ) / mvals . height ;
1997-11-24 22:05:25 +00:00
1998-01-14 05:44:12 +00:00
if ( ! mvals . tile ) {
mw - = ! ( mw & 1 ) ; /* mazegen doesn't work with even-sized mazes. */
mh - = ! ( mh & 1 ) ; /* Note I don't warn the user about this... */
} else { /* On the other hand, tileable mazes must be even. */
mw - = ( mw & 1 ) ;
mh - = ( mh & 1 ) ;
} ;
1997-11-24 22:05:25 +00:00
1998-01-14 05:44:12 +00:00
/* It will really suck if your tileable maze ends up with this dead
space around it . Oh well , life is hard . */
1997-11-24 22:05:25 +00:00
deadx = ( ( x2 - x1 ) - mw * mvals . width ) / 2 ;
1998-02-20 10:41:20 +00:00
deady = ( ( y2 - y1 ) - mh * mvals . height ) / 2 ;
1997-11-24 22:05:25 +00:00
1998-05-18 00:33:13 +00:00
maz = g_new0 ( guchar , mw * mh ) ;
1997-11-24 22:05:25 +00:00
# ifdef MAZE_DEBUG
1998-02-20 10:41:20 +00:00
printf ( " x: %d \t y: %d \n mw: %d \t mh: %d \n dx: %d \t dy: %d \n width:%d \t height: %d \n " ,
( x2 - x1 ) , ( y2 - y1 ) , mw , mh , deadx , deady , mvals . width , mvals . height ) ;
1997-11-24 22:05:25 +00:00
# endif
1998-02-20 10:41:20 +00:00
if ( mvals . timeseed )
mvals . seed = time ( NULL ) ;
1998-05-18 00:33:13 +00:00
/* Sanity check: */
switch ( mvals . algorithm ) {
case DEPTH_FIRST :
break ;
case PRIMS_ALGORITHM :
break ;
default :
g_warning ( " maze: Invalid algorithm choice %d " , mvals . algorithm ) ;
1998-01-14 05:44:12 +00:00
}
1998-05-18 00:33:13 +00:00
if ( mvals . tile ) {
switch ( mvals . algorithm ) {
case DEPTH_FIRST :
mazegen_tileable ( 0 , maz , mw , mh , mvals . seed ) ;
break ;
case PRIMS_ALGORITHM :
prim_tileable ( maz , mw , mh , mvals . seed ) ;
break ;
default :
;
}
} else { /* not tileable */
if ( active_selection ) { /* Mask and draw mazes until there's no
* more room left . */
mask_maze ( drawable - > id ,
maz , mw , mh , x1 , x2 , y1 , y2 , deadx , deady ) ;
for ( maz_yy = mw ; maz_yy < ( mh * mw ) ; maz_yy + = 2 * mw ) {
for ( maz_xx = 1 ; maz_xx < mw ; maz_xx + = 2 ) {
if ( maz [ maz_yy + maz_xx ] = = 0 ) {
switch ( mvals . algorithm ) {
case DEPTH_FIRST :
mazegen ( maz_yy + maz_xx , maz , mw , mh , mvals . seed ) ;
break ;
case PRIMS_ALGORITHM :
prim ( maz_yy + maz_xx , maz , mw , mh , mvals . seed ) ;
break ;
default :
;
} /* switch */
} /* if maz[] == 0 */
} /* next maz_xx */
} /* next maz_yy */
} else { /* No active selection. */
pos = mw + 1 ;
switch ( mvals . algorithm ) {
case DEPTH_FIRST :
mazegen ( pos , maz , mw , mh , mvals . seed ) ;
break ;
case PRIMS_ALGORITHM :
prim ( pos , maz , mw , mh , mvals . seed ) ;
break ;
default :
;
} /* switch */
} /* no active selection */
} /* not tileable */
/************** Begin Drawing *********************/
/* Initialize pixel region (?) */
gimp_pixel_rgn_init ( & dest_rgn , drawable , x1 , y1 , ( x2 - x1 ) , ( y2 - y1 ) , TRUE , TRUE ) ;
progress = 0 ;
max_progress = ( x2 - x1 ) * ( y2 - y1 ) ;
/* Get the foreground and background colors */
get_colors ( drawable , fg , bg ) ;
2000-01-01 15:38:59 +00:00
gimp_progress_init ( _ ( " Drawing Maze... " ) ) ;
1997-11-24 22:05:25 +00:00
for ( pr = gimp_pixel_rgns_register ( 1 , & dest_rgn ) ;
pr ! = NULL ;
pr = gimp_pixel_rgns_process ( pr ) )
{
x = dest_rgn . x - x1 - deadx ;
y = dest_rgn . y - y1 - deady ;
/* First boxes by edge of tile must be handled specially
because they may have started on a previous tile ,
unbeknownst to us . */
dx = mvals . width - ( x % mvals . width ) ;
1998-02-20 10:41:20 +00:00
dy = mvals . height - ( y % mvals . height ) ;
1998-05-18 00:33:13 +00:00
maz_x = x / mvals . width ;
maz_row = mw * ( y / mvals . height ) ;
1997-11-24 22:05:25 +00:00
/* Draws the upper-left [split] box */
drawbox ( & dest_rgn , 0 , 0 , dx , dy ,
1998-05-18 00:33:13 +00:00
( maz [ maz_row + maz_x ] = = IN ) ? fg : bg ) ;
1997-11-24 22:05:25 +00:00
1998-05-18 00:33:13 +00:00
maz_xx = maz_x + 1 ;
1997-11-24 22:05:25 +00:00
/* Draw the top row [split] boxes */
1998-02-20 10:41:20 +00:00
for ( xx = dx ; xx < dest_rgn . w ; xx + = mvals . width )
1997-11-24 22:05:25 +00:00
{ drawbox ( & dest_rgn , xx , 0 , mvals . width , dy ,
1998-05-18 00:33:13 +00:00
( maz [ maz_row + maz_xx + + ] = = IN ) ? fg : bg ) ; }
1997-11-24 22:05:25 +00:00
1998-05-18 00:33:13 +00:00
maz_yy = maz_row + mw ;
1997-11-24 22:05:25 +00:00
/* Left column */
1998-02-20 10:41:20 +00:00
for ( yy = dy ; yy < dest_rgn . h ; yy + = mvals . height ) {
drawbox ( & dest_rgn , 0 , yy , dx , mvals . height ,
1998-05-18 00:33:13 +00:00
( maz [ maz_yy + maz_x ] = = IN ) ? fg : bg ) ;
maz_yy + = mw ;
1997-11-24 22:05:25 +00:00
}
1998-05-18 00:33:13 +00:00
maz_x + + ;
1997-11-24 22:05:25 +00:00
/* Everything else */
1998-02-20 10:41:20 +00:00
for ( yy = dy ; yy < dest_rgn . h ; yy + = mvals . height ) {
1998-05-18 00:33:13 +00:00
maz_xx = maz_x ; maz_row + = mw ;
1998-02-20 10:41:20 +00:00
for ( xx = dx ; xx < dest_rgn . w ; xx + = mvals . width )
1997-11-24 22:05:25 +00:00
{
1998-02-20 10:41:20 +00:00
drawbox ( & dest_rgn , xx , yy , mvals . width , mvals . height ,
1998-05-18 00:33:13 +00:00
( maz [ maz_row + maz_xx + + ] = = IN ) ? fg : bg ) ; }
1997-11-24 22:05:25 +00:00
}
progress + = dest_rgn . w * dest_rgn . h ;
gimp_progress_update ( ( double ) progress / ( double ) max_progress ) ;
1998-05-18 00:33:13 +00:00
/* Indicate progress in drawing. */
1997-11-24 22:05:25 +00:00
}
gimp_drawable_flush ( drawable ) ;
gimp_drawable_merge_shadow ( drawable - > id , TRUE ) ;
gimp_drawable_update ( drawable - > id , x1 , y1 , ( x2 - x1 ) , ( y2 - y1 ) ) ;
}
1998-05-18 00:33:13 +00:00
/* Shaped mazes: */
/* With
* Depth first : Nonzero cells will not be connected to or visited .
* Prim ' s Algorithm :
* Cells that are not IN will not be connected to .
* Cells that are not OUT will not be converted to FRONTIER .
1998-03-09 01:45:26 +00:00
*
1998-05-18 00:33:13 +00:00
* So we ' ll put unavailable cells in a non - zero non - in non - out class
* called MASKED .
*/
/* But first... A little discussion about cells. */
/* In the eyes of the generation algorithms, the world is made up of
* two sorts of things : Cells , and the walls between them . Walls can
* be knocked out , and then you have a passage between cells . The
* drawing routine has a simpler view of life . . . Everything is a
* pixel . Or a block of pixels . It makes no distinction between
* passages , walls , and cells .
1998-03-09 01:45:26 +00:00
*
1998-05-18 00:33:13 +00:00
* We may also make the distinction between two different types of
* passages : horizontal and vertical . With that in mind , a
* part of the world looks something like this :
*
* @ - @ - @ - @ - Where @ is a cell , | is a vertical passage , and - is a
* | | | | horizontal passsage .
* @ - @ - @ - @ -
* | | | | Remember , the maze generation routines will not rest
* until the maze is full , that is , every cell is connected
* to another . Already , we can determine a few things about the final
* maze . We know which blocks will be cells , which blocks may become
* passages ( and we know what sort ) , and we also notice that there are
* some blocks that will never be either cells or passages .
1998-03-09 01:45:26 +00:00
*
1998-05-18 00:33:13 +00:00
* Now , back to our masking routine . . . To save a little time , lets
* just take sample points from the block . We ' ll sample a point from
* the top and the bottom of vertical passages , left / right for
* horizontal , and , hmm , left / right / top / bottom for cells . And of
* course , we needn ' t concern ourselves with the others . We could
* also sample the midpoint of each . . .
* Then what we ' ll do is see if the average is higher than some magic
* threshold number , and if so , we let maze happen there . Otherwise
* we mask it out .
1998-03-09 01:45:26 +00:00
*/
1998-05-18 00:33:13 +00:00
/* And, uh, that's on the TODO list. Looks like I spent so much time
* writing comments I haven ' t left enough to implement the code . : )
* Right now we only sample one point . */
static void
mask_maze ( gint32 drawable_ID , guchar * maz , guint mw , guint mh ,
gint x1 , gint x2 , gint y1 , gint y2 , gint deadx , gint deady )
{
gint32 selection_ID ;
GPixelRgn sel_rgn ;
gint xx0 = 0 , yy0 = 0 , xoff , yoff ;
guint xx = 0 , yy = 0 ;
guint foo = 0 ;
1998-03-09 01:45:26 +00:00
1998-05-18 00:33:13 +00:00
gint cur_row , cur_col ;
gint x1half , x2half , y1half , y2half ;
guchar * linebuf ;
1998-03-09 01:45:26 +00:00
1998-05-18 00:33:13 +00:00
if ( ( selection_ID =
gimp_image_get_selection ( gimp_drawable_image_id ( drawable_ID ) ) )
= = - 1 )
return ;
1998-03-09 01:45:26 +00:00
1998-05-18 00:33:13 +00:00
gimp_pixel_rgn_init ( & sel_rgn , gimp_drawable_get ( selection_ID ) ,
x1 , y1 , ( x2 - x1 ) , ( y2 - y1 ) ,
FALSE , FALSE ) ;
gimp_drawable_offsets ( drawable_ID , & xoff , & yoff ) ;
1998-03-09 01:45:26 +00:00
1998-05-18 00:33:13 +00:00
/* Special cases: If mw or mh < 3 */
/* FIXME (Currently works, but inefficiently.) */
/* mw && mh => 3 */
1997-11-24 22:05:25 +00:00
1998-05-18 00:33:13 +00:00
linebuf = g_new ( guchar , sel_rgn . w * sel_rgn . bpp ) ;
1997-11-24 22:05:25 +00:00
1998-05-18 00:33:13 +00:00
xx0 = x1 + deadx + mvals . width + xoff ;
yy0 = y1 + deady + mvals . height + yoff ;
1997-11-24 22:05:25 +00:00
1998-05-18 00:33:13 +00:00
x1half = mvals . width / 2 ;
x2half = mvals . width - 1 ;
1997-11-24 22:05:25 +00:00
1998-05-18 00:33:13 +00:00
y1half = mvals . height / 2 ;
y2half = mvals . height - 1 ;
1997-11-24 22:05:25 +00:00
1998-05-18 00:33:13 +00:00
/* Here, yy is with respect to the drawable (or something),
whereas xx is with respect to the row buffer . */
1998-01-14 05:44:12 +00:00
1998-05-18 00:33:13 +00:00
yy = yy0 + y1half ;
for ( cur_row = 1 ; cur_row < mh ; cur_row + = 2 ) {
1998-01-14 05:44:12 +00:00
1998-05-18 00:33:13 +00:00
gimp_pixel_rgn_get_row ( & sel_rgn , linebuf , x1 + xoff , yy , ( x2 - x1 ) ) ;
1998-01-14 05:44:12 +00:00
1998-05-18 00:33:13 +00:00
cur_col = 1 ; xx = mvals . width ;
while ( cur_col < mw ) {
1998-01-14 05:44:12 +00:00
1998-05-18 00:33:13 +00:00
/* Cell: */
maz [ cur_row * mw + cur_col ] =
( linebuf [ xx ] + linebuf [ xx + x1half ] + linebuf [ xx + x2half ] ) / 5 ;
1998-01-14 05:44:12 +00:00
1998-05-18 00:33:13 +00:00
cur_col + = 1 ;
xx + = mvals . width ;
1998-01-14 05:44:12 +00:00
1998-05-18 00:33:13 +00:00
/* Passage: */
if ( cur_col < mw )
maz [ cur_row * mw + cur_col ] =
( linebuf [ xx ] + linebuf [ xx + x1half ] + linebuf [ xx + x2half ] ) / 3 ;
1997-11-24 22:05:25 +00:00
1998-05-18 00:33:13 +00:00
cur_col + = 1 ;
xx + = mvals . width ;
1997-11-24 22:05:25 +00:00
1998-05-18 00:33:13 +00:00
} /* next col */
1997-11-24 22:05:25 +00:00
1998-05-18 00:33:13 +00:00
yy + = 2 * mvals . height ;
1997-11-24 22:05:25 +00:00
1998-05-18 00:33:13 +00:00
} /* next cur_row += 2 */
/* Done doing horizontal scans, change this from a row buffer to
a column buffer . */
g_free ( linebuf ) ;
linebuf = g_new ( guchar , sel_rgn . h * sel_rgn . bpp ) ;
/* Now xx is with respect to the drawable (or whatever),
and yy is with respect to the row buffer . */
xx = xx0 + x1half ;
for ( cur_col = 1 ; cur_col < mw ; cur_col + = 2 ) {
gimp_pixel_rgn_get_col ( & sel_rgn , linebuf , xx , y1 , ( y2 - y1 ) ) ;
cur_row = 1 ; yy = mvals . height ;
while ( cur_row < mh ) {
/* Cell: */
maz [ cur_row * mw + cur_col ] + =
( linebuf [ yy ] + linebuf [ yy + y2half ] ) / 5 ;
cur_row + = 1 ;
yy + = mvals . height ;
/* Passage: */
if ( cur_row < mh )
maz [ cur_row * mw + cur_col ] =
( linebuf [ yy ] + linebuf [ yy + y1half ] + linebuf [ yy + y2half ] ) / 3 ;
cur_row + = 1 ;
yy + = mvals . height ;
} /* next cur_row */
xx + = 2 * mvals . width ;
} /* next cur_col */
g_free ( linebuf ) ;
/* Do the alpha -> masked conversion. */
for ( yy = 0 ; yy < mh ; yy + + ) {
for ( xx = 0 ; xx < mw ; xx + + ) {
maz [ foo ] = ( maz [ foo ] < MAZE_ALPHA_THRESHOLD ) ? MASKED : OUT ;
foo + + ;
} /* next xx */
} /* next yy*/
} /* mask_maze */
/* The attempt to implement this with tiles: (it wasn't fun) */
#if 0
/* Tiles make my life decidedly difficult here. There are too
* many special cases . . . " What if a tile starts less/more than
* halfway through a block ? What if we get a narrow edge - tile
* that . . . " etc, etc. I shall investigate other options.
* Possibly a row buffer , or can we use something other than this
* black - magic gimp_pixel_rgns_register call to get tiles of
* different sizes ? Now that ' d be nice . . . */
for ( pr = gimp_pixel_rgns_register ( 1 , & sel_rgn ) ;
pr ! = NULL ;
pr = gimp_pixel_rgns_process ( pr ) ) {
/* This gives us coordinates relative to the starting point
* of the maze grid . Negative values happen here if there
* is dead space . */
x = sel_rgn . x - x1 - deadx ;
y = sel_rgn . y - y1 - deady ;
/* These coordinates are relative to the current tile. */
/* This starts us off at the first block boundary in the
* tile . */
/* e.g. with x=16 and width=10.
* 16 % 10 = 6
* 10 - 6 = 4
x : 6789 ! 123456789 ! 123456789 ! 12
. . . . | . . . . . . . . . | . . . . . . . . . | . .
xx : 01234567 89 ! 123456789 ! 123456
So to start on the boundary , begin at 4.
For the case x = 0 , 10 - 0 = 10. So xx0 will always between 1 and width . */
xx0 = mvals . width - ( x % mvals . width ) ;
yy0 = mvals . height - ( y % mvals . height ) ;
/* Find the corresponding row and column in the maze. */
maz_x = ( x + xx0 ) / mvals . width ;
maz_row = mw * ( ( y + yy0 ) / mvals . height ) ;
for ( yy = yy0 * sel_rgn . rowstride ;
yy < sel_rgn . h * sel_rgn . rowstride ;
yy + = ( mvals . height * sel_rgn . rowstride ) ) {
maz_xx = maz_x ;
for ( xx = xx0 * sel_rgn . bpp ;
xx < sel_rgn . w ;
xx + = mvals . width * sel_rgn . bpp ) {
if ( sel_rgn . data [ yy + xx ] < MAZE_ALPHA_THRESHOLD )
maz [ maz_row + maz_xx ] = MASKED ;
maz_xx + + ;
} /* next xx */
maz_row + = mw ;
} /* next yy */
} /* next pr sel_rgn tile thing */
1998-09-09 10:07:21 +00:00
# ifdef MAZE_DEBUG
/* maze_dump(maz,mw,mh); */
# endif
1998-05-18 00:33:13 +00:00
} /* mask_maze */
# endif /* 0 */