mirror of https://github.com/GNOME/gimp.git
updated maze plugin
* plug-ins/maze: updated maze plugin * plug-ins/script-fu/scripts/circuit.scm: reflected maze pdb interface change -Yosh
This commit is contained in:
parent
5b1f6495d8
commit
a7b206b5c3
|
@ -1,3 +1,10 @@
|
||||||
|
Sun May 17 17:31:05 PDT 1998 Manish Singh <yosh@gimp.org>
|
||||||
|
|
||||||
|
* plug-ins/maze: updated maze plugin
|
||||||
|
|
||||||
|
* plug-ins/script-fu/scripts/circuit.scm: reflected maze pdb
|
||||||
|
interface change
|
||||||
|
|
||||||
Sun May 17 14:44:32 PDT 1998 Manish Singh <yosh@gimp.org>
|
Sun May 17 14:44:32 PDT 1998 Manish Singh <yosh@gimp.org>
|
||||||
|
|
||||||
* app/gimage.c: fix for merging indexed and indexed-alpha
|
* app/gimage.c: fix for merging indexed and indexed-alpha
|
||||||
|
|
|
@ -5,7 +5,7 @@ pluginlibdir = $(gimpplugindir)/plug-ins
|
||||||
pluginlib_PROGRAMS = maze
|
pluginlib_PROGRAMS = maze
|
||||||
|
|
||||||
maze_SOURCES = \
|
maze_SOURCES = \
|
||||||
maze.c maze.h maze_face.c
|
maze.c maze.h maze_face.c algorithms.c handy.c
|
||||||
|
|
||||||
INCLUDES = \
|
INCLUDES = \
|
||||||
$(X_CFLAGS) \
|
$(X_CFLAGS) \
|
||||||
|
|
|
@ -0,0 +1,586 @@
|
||||||
|
/* algorithms.c
|
||||||
|
* Contains routines for generating mazes, somewhat intertwined with
|
||||||
|
* Gimp plug-in-maze specific stuff.
|
||||||
|
*
|
||||||
|
* Kevin Turner <kevint@poboxes.com>
|
||||||
|
* http://www.poboxes.com/kevint/gimp/maze.html
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* mazegen code from rec.games.programmer's maze-faq:
|
||||||
|
* * maz.c - generate a maze
|
||||||
|
* *
|
||||||
|
* * algorithm posted to rec.games.programmer by jallen@ic.sunysb.edu
|
||||||
|
* * program cleaned and reorganized by mzraly@ldbvax.dnet.lotus.com
|
||||||
|
* *
|
||||||
|
* * don't make people pay for this, or I'll jump up and down and
|
||||||
|
* * yell and scream and embarass you in front of your friends...
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* I've put a HTMLized version of the FAQ up at
|
||||||
|
* http://www.poboxes.com/kevint/gimp/maze-faq/maze-faq.html
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "maze.h"
|
||||||
|
#include "libgimp/gimp.h"
|
||||||
|
#include "libgimp/gimpui.h"
|
||||||
|
|
||||||
|
extern MazeValues mvals;
|
||||||
|
|
||||||
|
void mazegen(gint pos,
|
||||||
|
gchar *maz,
|
||||||
|
gint x,
|
||||||
|
gint y,
|
||||||
|
gint rnd);
|
||||||
|
void mazegen_tileable(gint pos,
|
||||||
|
gchar *maz,
|
||||||
|
gint x,
|
||||||
|
gint y,
|
||||||
|
gint rnd);
|
||||||
|
void prim(guint pos,
|
||||||
|
gchar *maz,
|
||||||
|
guint x,
|
||||||
|
guint y,
|
||||||
|
gint rnd);
|
||||||
|
void prim_tileable(gchar *maz,
|
||||||
|
guint x,
|
||||||
|
guint y,
|
||||||
|
gint rnd);
|
||||||
|
|
||||||
|
#define ABSMOD(A,B) ( ((A) < 0) ? (((B) + (A)) % (B)) : ((A) % (B)) )
|
||||||
|
|
||||||
|
/* Since we are using a 1D array on 2D space, we need to do our own
|
||||||
|
calculations. (Ok, so there are ways of doing dynamically allocated
|
||||||
|
2D arrays, but we started this way, so let's stick with it. */
|
||||||
|
|
||||||
|
/* The difference between CELL_* and WALL_* is that cell moves two spaces,
|
||||||
|
while wall moves one. */
|
||||||
|
|
||||||
|
/* Macros assume that x and y will be defined where they are used. */
|
||||||
|
/* A return of -1 means "no such place, don't go there". */
|
||||||
|
#define CELL_UP(POS) ((POS) < (x*2) ? -1 : (POS) - x - x)
|
||||||
|
#define CELL_DOWN(POS) ((POS) >= x*(y-2) ? -1 : (POS) + x + x)
|
||||||
|
#define CELL_LEFT(POS) (((POS) % x) <= 1 ? -1 : (POS) - 2)
|
||||||
|
#define CELL_RIGHT(POS) (((POS) % x) >= (x - 2) ? -1 : (POS) + 2)
|
||||||
|
|
||||||
|
/* With walls, we don't need to check for boundaries, since we are
|
||||||
|
assured that there *is* a valid cell on the other side of the
|
||||||
|
wall. */
|
||||||
|
#define WALL_UP(POS) ((POS) - x)
|
||||||
|
#define WALL_DOWN(POS) ((POS) + x)
|
||||||
|
#define WALL_LEFT(POS) ((POS) - 1)
|
||||||
|
#define WALL_RIGHT(POS) ((POS) + 1)
|
||||||
|
|
||||||
|
/***** For tileable mazes *****/
|
||||||
|
|
||||||
|
#define CELL_UP_TILEABLE(POS) ((POS) < (x*2) ? x*(y-2)+(POS) : (POS) - x - x)
|
||||||
|
#define CELL_DOWN_TILEABLE(POS) ((POS) >= x*(y-2) ? (POS) - x*(y-2) : (POS) + x + x)
|
||||||
|
#define CELL_LEFT_TILEABLE(POS) (((POS) % x) <= 1 ? (POS) + x - 2 : (POS) - 2)
|
||||||
|
#define CELL_RIGHT_TILEABLE(POS) (((POS) % x) >= (x - 2) ? (POS) + 2 - x : (POS) + 2)
|
||||||
|
/* Up and left need checks, but down and right should never have to
|
||||||
|
wrap on an even sized maze. */
|
||||||
|
#define WALL_UP_TILEABLE(POS) ((POS) < x ? x*(y-1)+(POS) : (POS) - x)
|
||||||
|
#define WALL_DOWN_TILEABLE(POS) ((POS) + x)
|
||||||
|
#define WALL_LEFT_TILEABLE(POS) (((POS) % x) == 0 ? (POS) + x - 1 : (POS) - 1)
|
||||||
|
#define WALL_RIGHT_TILEABLE(POS) ((POS) + 1)
|
||||||
|
|
||||||
|
/* Down and right with checks.
|
||||||
|
#define WALL_DOWN_TILEABLE(POS) ((POS) >= x*(y-1) ? (POS) - x * (y-1) : (POS) + x)
|
||||||
|
#define WALL_RIGHT_TILEABLE(POS) (((POS) % x) == (x - 1) ? (POS) + 1 - x : (POS) + 1)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* The Incredible Recursive Maze Generation Routine */
|
||||||
|
/* Ripped from rec.programmers.games maze-faq */
|
||||||
|
/* Modified and commented by me, Kevin Turner. */
|
||||||
|
void
|
||||||
|
mazegen(gint pos, gchar *maz, gint x, gint y, gint rnd)
|
||||||
|
{
|
||||||
|
gchar d, i;
|
||||||
|
gint c=0, j=1;
|
||||||
|
|
||||||
|
/* Punch a hole here... */
|
||||||
|
maz[pos] = IN;
|
||||||
|
|
||||||
|
/* If there is a wall two rows above us, bit 1 is 1. */
|
||||||
|
while((d= (pos <= (x * 2) ? 0 : (maz[pos - x - x ] ? 0 : 1))
|
||||||
|
/* If there is a wall two rows below us, bit 2 is 1. */
|
||||||
|
| (pos >= x * (y - 2) ? 0 : (maz[pos + x + x] ? 0 : 2))
|
||||||
|
/* If there is a wall two columns to the right, bit 3 is 1. */
|
||||||
|
| (pos % x == x - 2 ? 0 : (maz[pos + 2] ? 0 : 4))
|
||||||
|
/* If there is a wall two colums to the left, bit 4 is 1. */
|
||||||
|
| ((pos % x == 1 ) ? 0 : (maz[pos-2] ? 0 : 8)))) {
|
||||||
|
|
||||||
|
/* Note if all bits are 0, d is false, we don't do this
|
||||||
|
while loop, we don't call ourselves again, so this branch
|
||||||
|
is done. */
|
||||||
|
|
||||||
|
/* I see what this loop does (more or less), but I don't know
|
||||||
|
_why_ it does it this way... I also haven't figured out exactly
|
||||||
|
which values of multiple will work and which won't. */
|
||||||
|
do {
|
||||||
|
rnd = (rnd * mvals.multiple + mvals.offset);
|
||||||
|
i = 3 & (rnd / d);
|
||||||
|
if (++c > 100) { /* Break and try to salvage something */
|
||||||
|
i=99; /* if it looks like we're going to be */
|
||||||
|
break; /* here forever... */
|
||||||
|
}
|
||||||
|
} while ( !(d & ( 1 << i) ) );
|
||||||
|
/* ...While there's *not* a wall in direction i. */
|
||||||
|
/* (stop looping when there is) */
|
||||||
|
|
||||||
|
switch (i) { /* This is simple enough. */
|
||||||
|
case 0: /* Go in the direction we just figured . . . */
|
||||||
|
j= -x;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
j = x;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
j=1;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
j= -1;
|
||||||
|
break;
|
||||||
|
case 99:
|
||||||
|
return; /* Hey neat, broken mazes! */
|
||||||
|
break; /* (Umm... Wow... Yeah, neat.) */
|
||||||
|
default:
|
||||||
|
g_warning("maze: mazegen: Going in unknown direction.\n"
|
||||||
|
"i: %d, d: %d, seed: %d, mw: %d, mh: %d, mult: %d, offset: %d\n",
|
||||||
|
i, d,mvals.seed, x, y, mvals.multiple, mvals.offset);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* And punch a hole there. */
|
||||||
|
maz[pos + j] = 1;
|
||||||
|
|
||||||
|
/* Now, start again just past where we punched the hole... */
|
||||||
|
mazegen(pos + 2 * j, maz, x, y, rnd);
|
||||||
|
|
||||||
|
} /* End while(d=...) Loop */
|
||||||
|
|
||||||
|
/* This routine is quite quick, even for rather large mazes.
|
||||||
|
For that reason, it doesn't need a progress bar. */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tileable mazes are my creation, based on the routine above. */
|
||||||
|
void
|
||||||
|
mazegen_tileable(gint pos, gchar *maz, gint x, gint y, gint rnd)
|
||||||
|
{
|
||||||
|
gchar d, i;
|
||||||
|
gint c=0, npos=2;
|
||||||
|
|
||||||
|
/* Punch a hole here... */
|
||||||
|
maz[pos] = IN;
|
||||||
|
|
||||||
|
/* If there is a wall two rows above us, bit 1 is 1. */
|
||||||
|
while((d= (maz[CELL_UP_TILEABLE(pos)] ? 0 : 1)
|
||||||
|
/* If there is a wall two rows below us, bit 2 is 1. */
|
||||||
|
| (maz[CELL_DOWN_TILEABLE(pos)] ? 0 : 2)
|
||||||
|
/* If there is a wall two columns to the right, bit 3 is 1. */
|
||||||
|
| (maz[CELL_RIGHT_TILEABLE(pos)] ? 0 : 4)
|
||||||
|
/* If there is a wall two colums to the left, bit 4 is 1. */
|
||||||
|
| (maz[CELL_LEFT_TILEABLE(pos)] ? 0 : 8))) {
|
||||||
|
|
||||||
|
/* Note if all bits are 0, d is false, we don't do this
|
||||||
|
while loop, we don't call ourselves again, so this branch
|
||||||
|
is done. */
|
||||||
|
|
||||||
|
/* I see what this loop does (more or less), but I don't know
|
||||||
|
_why_ it does it this way... I also haven't figured out exactly
|
||||||
|
which values of multiple will work and which won't. */
|
||||||
|
do {
|
||||||
|
rnd = (rnd * mvals.multiple + mvals.offset);
|
||||||
|
i = 3 & (rnd / d);
|
||||||
|
if (++c > 100) { /* Break and try to salvage something */
|
||||||
|
i=99; /* if it looks like we're going to be */
|
||||||
|
break; /* here forever... */
|
||||||
|
}
|
||||||
|
} while ( !(d & ( 1 << i) ) );
|
||||||
|
/* ...While there's *not* a wall in direction i. */
|
||||||
|
/* (stop looping when there is) */
|
||||||
|
|
||||||
|
switch (i) { /* This is simple enough. */
|
||||||
|
case 0: /* Go in the direction we just figured . . . */
|
||||||
|
maz[WALL_UP_TILEABLE(pos)]=IN;
|
||||||
|
npos = CELL_UP_TILEABLE(pos);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
maz[WALL_DOWN_TILEABLE(pos)]=IN;
|
||||||
|
npos = CELL_DOWN_TILEABLE(pos);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
maz[WALL_RIGHT_TILEABLE(pos)]=IN;
|
||||||
|
npos = CELL_RIGHT_TILEABLE(pos);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
maz[WALL_LEFT_TILEABLE(pos)]=IN;
|
||||||
|
npos = CELL_LEFT_TILEABLE(pos);
|
||||||
|
break;
|
||||||
|
case 99:
|
||||||
|
return; /* Hey neat, broken mazes! */
|
||||||
|
break; /* (Umm... Wow... Yeah, neat.) */
|
||||||
|
default:
|
||||||
|
g_warning("maze: mazegen_tileable: Going in unknown direction.\n"
|
||||||
|
"i: %d, d: %d, seed: %d, mw: %d, mh: %d, mult: %d, offset: %d\n",
|
||||||
|
i, d,mvals.seed, x, y, mvals.multiple, mvals.offset);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now, start again just past where we punched the hole... */
|
||||||
|
mazegen_tileable(npos, maz, x, y, rnd);
|
||||||
|
|
||||||
|
} /* End while(d=...) Loop */
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
static void
|
||||||
|
print_glist(gpointer data, gpointer user_data)
|
||||||
|
{
|
||||||
|
g_print("%d ",(guint)data);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* This function (as well as prim_tileable) make use of the somewhat
|
||||||
|
unclean practice of storing ints as pointers. I've been informed
|
||||||
|
that this may cause problems with 64-bit stuff. However, hopefully
|
||||||
|
it will be okay, since the only values stored are positive. If it
|
||||||
|
does break, let me know, and I'll go cry in a corner for a while
|
||||||
|
before I get up the strength to re-code it. */
|
||||||
|
void
|
||||||
|
prim(guint pos, gchar *maz, guint x, guint y, gint rnd)
|
||||||
|
{
|
||||||
|
GSList *front_cells=NULL;
|
||||||
|
guint current;
|
||||||
|
gint up, down, left, right; /* Not unsigned, because macros return -1. */
|
||||||
|
guint progress=0, max_progress;
|
||||||
|
char d, i;
|
||||||
|
guint c=0;
|
||||||
|
|
||||||
|
gimp_progress_init ("Constructing maze using Prim's Algorithm...");
|
||||||
|
|
||||||
|
/* OUT is zero, so we should be already initalized. */
|
||||||
|
|
||||||
|
max_progress=x*y/4;
|
||||||
|
|
||||||
|
/* Starting position has already been determined by the calling function. */
|
||||||
|
|
||||||
|
maz[pos]=IN;
|
||||||
|
|
||||||
|
/* For now, repeating everything four times seems manageable. But when
|
||||||
|
Gimp is extended to drawings in n-dimensional space instead of 2D,
|
||||||
|
this will require a bit of a re-write. */
|
||||||
|
/* Add frontier. */
|
||||||
|
up=CELL_UP(pos);
|
||||||
|
down=CELL_DOWN(pos);
|
||||||
|
left=CELL_LEFT(pos);
|
||||||
|
right=CELL_RIGHT(pos);
|
||||||
|
|
||||||
|
if (up >= 0) {
|
||||||
|
maz[up]=FRONTIER;
|
||||||
|
front_cells=g_slist_append(front_cells,(gpointer)up);
|
||||||
|
}
|
||||||
|
if (down >= 0) {
|
||||||
|
maz[up]=FRONTIER;
|
||||||
|
front_cells=g_slist_append(front_cells,(gpointer)down);
|
||||||
|
}
|
||||||
|
if (left >= 0) {
|
||||||
|
maz[up]=FRONTIER;
|
||||||
|
front_cells=g_slist_append(front_cells,(gpointer)left);
|
||||||
|
}
|
||||||
|
if (right >= 0) {
|
||||||
|
maz[up]=FRONTIER;
|
||||||
|
front_cells=g_slist_append(front_cells,(gpointer)right);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* While frontier is not empty do the following... */
|
||||||
|
while(g_slist_length(front_cells) > 0) {
|
||||||
|
|
||||||
|
/* Remove one cell at random from frontier and place it in IN. */
|
||||||
|
current = rand() % g_slist_length(front_cells);
|
||||||
|
pos = (guint)g_slist_nth(front_cells,current)->data;
|
||||||
|
|
||||||
|
front_cells=g_slist_remove(front_cells,(gpointer)pos);
|
||||||
|
maz[pos]=IN;
|
||||||
|
|
||||||
|
/* If the cell has any neighbors in OUT, remove them from
|
||||||
|
OUT and place them in FRONTIER. */
|
||||||
|
|
||||||
|
up=CELL_UP(pos);
|
||||||
|
down=CELL_DOWN(pos);
|
||||||
|
left=CELL_LEFT(pos);
|
||||||
|
right=CELL_RIGHT(pos);
|
||||||
|
|
||||||
|
d=0;
|
||||||
|
if (up>=0) {
|
||||||
|
switch (maz[up]) {
|
||||||
|
case OUT:
|
||||||
|
maz[up]=FRONTIER;
|
||||||
|
front_cells=g_slist_append(front_cells,(gpointer)up);
|
||||||
|
break;
|
||||||
|
case IN:
|
||||||
|
d=1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (down>=0) {
|
||||||
|
switch (maz[down]) {
|
||||||
|
case OUT:
|
||||||
|
maz[down]=FRONTIER;
|
||||||
|
front_cells=g_slist_append(front_cells,(gpointer)down);
|
||||||
|
break;
|
||||||
|
case IN:
|
||||||
|
d=d|2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (left>=0) {
|
||||||
|
switch (maz[left]) {
|
||||||
|
case OUT:
|
||||||
|
maz[left]=FRONTIER;
|
||||||
|
front_cells=g_slist_append(front_cells,(gpointer)left);
|
||||||
|
break;
|
||||||
|
case IN:
|
||||||
|
d=d|4;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (right>=0) {
|
||||||
|
switch (maz[right]) {
|
||||||
|
case OUT:
|
||||||
|
maz[right]=FRONTIER;
|
||||||
|
front_cells=g_slist_append(front_cells,(gpointer)right);
|
||||||
|
break;
|
||||||
|
case IN:
|
||||||
|
d=d|8;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The cell is guaranteed to have at least one neighbor in
|
||||||
|
IN (otherwise it would not have been in FRONTIER); pick
|
||||||
|
one such neighbor at random and connect it to the new
|
||||||
|
cell (ie knock out a wall). */
|
||||||
|
|
||||||
|
if (!d) {
|
||||||
|
g_warning("maze: prim: Lack of neighbors.\n"
|
||||||
|
"seed: %d, mw: %d, mh: %d, mult: %d, offset: %d\n",
|
||||||
|
mvals.seed, x, y, mvals.multiple, mvals.offset);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
c=0;
|
||||||
|
do {
|
||||||
|
rnd = (rnd * mvals.multiple + mvals.offset);
|
||||||
|
i = 3 & (rnd / d);
|
||||||
|
if (++c > 100) { /* Break and try to salvage something */
|
||||||
|
i=99; /* if it looks like we're going to be */
|
||||||
|
break; /* here forever... */
|
||||||
|
}
|
||||||
|
} while ( !(d & ( 1 << i) ) );
|
||||||
|
|
||||||
|
switch (i) {
|
||||||
|
case 0:
|
||||||
|
maz[WALL_UP(pos)]=1;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
maz[WALL_DOWN(pos)]=1;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
maz[WALL_LEFT(pos)]=1;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
maz[WALL_RIGHT(pos)]=1;
|
||||||
|
break;
|
||||||
|
case 99:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
g_warning("maze: prim: Going in unknown direction.\n"
|
||||||
|
"i: %d, d: %d, seed: %d, mw: %d, mh: %d, mult: %d, offset: %d\n",
|
||||||
|
i, d, mvals.seed, x, y, mvals.multiple, mvals.offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (progress++ % PRIMS_PROGRESS_UPDATE)
|
||||||
|
gimp_progress_update ((double) progress / (double) max_progress);
|
||||||
|
|
||||||
|
} /* while front_cells */
|
||||||
|
|
||||||
|
g_slist_free(front_cells);
|
||||||
|
} /* prim */
|
||||||
|
|
||||||
|
void
|
||||||
|
prim_tileable(gchar *maz, guint x, guint y, gint rnd)
|
||||||
|
{
|
||||||
|
GSList *front_cells=NULL;
|
||||||
|
guint current, pos;
|
||||||
|
guint up, down, left, right;
|
||||||
|
guint progress=0, max_progress;
|
||||||
|
char d, i;
|
||||||
|
guint c=0;
|
||||||
|
|
||||||
|
gimp_progress_init ("Constructing tileable maze using Prim's Algorithm...");
|
||||||
|
|
||||||
|
/* OUT is zero, so we should be already initalized. */
|
||||||
|
|
||||||
|
max_progress=x*y/4;
|
||||||
|
|
||||||
|
/* Pick someplace to start. */
|
||||||
|
srand(rnd);
|
||||||
|
pos = x * 2 * (rand() % y / 2) + 2 * (rand() % x / 2);
|
||||||
|
|
||||||
|
maz[pos]=IN;
|
||||||
|
|
||||||
|
/* Add frontier. */
|
||||||
|
up=CELL_UP_TILEABLE(pos);
|
||||||
|
down=CELL_DOWN_TILEABLE(pos);
|
||||||
|
left=CELL_LEFT_TILEABLE(pos);
|
||||||
|
right=CELL_RIGHT_TILEABLE(pos);
|
||||||
|
|
||||||
|
maz[up]=maz[down]=maz[left]=maz[right]=FRONTIER;
|
||||||
|
|
||||||
|
front_cells=g_slist_append(front_cells,(gpointer)up);
|
||||||
|
front_cells=g_slist_append(front_cells,(gpointer)down);
|
||||||
|
front_cells=g_slist_append(front_cells,(gpointer)left);
|
||||||
|
front_cells=g_slist_append(front_cells,(gpointer)right);
|
||||||
|
|
||||||
|
/* While frontier is not empty do the following... */
|
||||||
|
while(g_slist_length(front_cells) > 0) {
|
||||||
|
|
||||||
|
/* Remove one cell at random from frontier and place it in IN. */
|
||||||
|
current = rand() % g_slist_length(front_cells);
|
||||||
|
pos = (guint)g_slist_nth(front_cells,current)->data;
|
||||||
|
|
||||||
|
front_cells=g_slist_remove(front_cells,(gpointer)pos);
|
||||||
|
maz[pos]=IN;
|
||||||
|
|
||||||
|
/* If the cell has any neighbors in OUT, remove them from
|
||||||
|
OUT and place them in FRONTIER. */
|
||||||
|
|
||||||
|
up=CELL_UP_TILEABLE(pos);
|
||||||
|
down=CELL_DOWN_TILEABLE(pos);
|
||||||
|
left=CELL_LEFT_TILEABLE(pos);
|
||||||
|
right=CELL_RIGHT_TILEABLE(pos);
|
||||||
|
|
||||||
|
d=0;
|
||||||
|
switch (maz[up]) {
|
||||||
|
case OUT:
|
||||||
|
maz[up]=FRONTIER;
|
||||||
|
front_cells=g_slist_append(front_cells,(gpointer)up);
|
||||||
|
break;
|
||||||
|
case IN:
|
||||||
|
d=1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
;
|
||||||
|
}
|
||||||
|
switch (maz[down]) {
|
||||||
|
case OUT:
|
||||||
|
maz[down]=FRONTIER;
|
||||||
|
front_cells=g_slist_append(front_cells,(gpointer)down);
|
||||||
|
break;
|
||||||
|
case IN:
|
||||||
|
d=d|2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
;
|
||||||
|
}
|
||||||
|
switch (maz[left]) {
|
||||||
|
case OUT:
|
||||||
|
maz[left]=FRONTIER;
|
||||||
|
front_cells=g_slist_append(front_cells,(gpointer)left);
|
||||||
|
break;
|
||||||
|
case IN:
|
||||||
|
d=d|4;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
;
|
||||||
|
}
|
||||||
|
switch (maz[right]) {
|
||||||
|
case OUT:
|
||||||
|
maz[right]=FRONTIER;
|
||||||
|
front_cells=g_slist_append(front_cells,(gpointer)right);
|
||||||
|
break;
|
||||||
|
case IN:
|
||||||
|
d=d|8;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The cell is guaranteed to have at least one neighbor in
|
||||||
|
IN (otherwise it would not have been in FRONTIER); pick
|
||||||
|
one such neighbor at random and connect it to the new
|
||||||
|
cell (ie knock out a wall). */
|
||||||
|
|
||||||
|
if (!d) {
|
||||||
|
g_warning("maze: prim's tileable: Lack of neighbors.\n"
|
||||||
|
"seed: %d, mw: %d, mh: %d, mult: %d, offset: %d\n",
|
||||||
|
mvals.seed, x, y, mvals.multiple, mvals.offset);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
c=0;
|
||||||
|
do {
|
||||||
|
rnd = (rnd * mvals.multiple + mvals.offset);
|
||||||
|
i = 3 & (rnd / d);
|
||||||
|
if (++c > 100) { /* Break and try to salvage something */
|
||||||
|
i=99; /* if it looks like we're going to be */
|
||||||
|
break; /* here forever... */
|
||||||
|
}
|
||||||
|
} while ( !(d & ( 1 << i) ) );
|
||||||
|
|
||||||
|
switch (i) {
|
||||||
|
case 0:
|
||||||
|
maz[WALL_UP_TILEABLE(pos)]=1;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
maz[WALL_DOWN_TILEABLE(pos)]=1;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
maz[WALL_LEFT_TILEABLE(pos)]=1;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
maz[WALL_RIGHT_TILEABLE(pos)]=1;
|
||||||
|
break;
|
||||||
|
case 99:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
g_warning("maze: prim's tileable: Going in unknown direction.\n"
|
||||||
|
"i: %d, d: %d, seed: %d, mw: %d, mh: %d, mult: %d, offset: %d\n",
|
||||||
|
i, d, mvals.seed, x, y, mvals.multiple, mvals.offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (progress++ % PRIMS_PROGRESS_UPDATE)
|
||||||
|
gimp_progress_update ((double) progress / (double) max_progress);
|
||||||
|
|
||||||
|
} /* while front_cells */
|
||||||
|
|
||||||
|
g_slist_free(front_cells);
|
||||||
|
}
|
|
@ -0,0 +1,228 @@
|
||||||
|
/* handy.c
|
||||||
|
* These routines are useful for working with the GIMP and need not be
|
||||||
|
* specific to plug-in-maze.
|
||||||
|
*
|
||||||
|
* Kevin Turner <kevint@poboxes.com>
|
||||||
|
* http://www.poboxes.com/kevint/gimp/maze.html
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "libgimp/gimp.h"
|
||||||
|
|
||||||
|
/* get_colors Returns the current foreground and background colors in
|
||||||
|
nice little arrays. It works nicely for RGB and grayscale images,
|
||||||
|
however handling of indexed images is somewhat broken. Patches
|
||||||
|
appreciated. */
|
||||||
|
void get_colors (GDrawable * drawable,
|
||||||
|
guint8 *fg,
|
||||||
|
guint8 *bg);
|
||||||
|
|
||||||
|
/* drawbox draws a solid colored box in a GPixelRgn, hopefully fairly
|
||||||
|
quickly. See comments below. */
|
||||||
|
void drawbox (GPixelRgn *dest_rgn,
|
||||||
|
guint x,
|
||||||
|
guint y,
|
||||||
|
guint w,
|
||||||
|
guint h,
|
||||||
|
guint8 clr[4]);
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
get_colors (GDrawable *drawable, guint8 *fg, guint8 *bg)
|
||||||
|
{
|
||||||
|
GParam *return_vals;
|
||||||
|
gint nreturn_vals;
|
||||||
|
|
||||||
|
switch ( gimp_drawable_type (drawable->id) )
|
||||||
|
{
|
||||||
|
case RGBA_IMAGE: /* ASSUMPTION: Assuming the user wants entire */
|
||||||
|
fg[3] = 255; /* area to be fully opaque. */
|
||||||
|
bg[3] = 255;
|
||||||
|
case RGB_IMAGE:
|
||||||
|
|
||||||
|
return_vals = gimp_run_procedure ("gimp_palette_get_foreground",
|
||||||
|
&nreturn_vals,
|
||||||
|
PARAM_END);
|
||||||
|
|
||||||
|
if (return_vals[0].data.d_status == STATUS_SUCCESS)
|
||||||
|
{
|
||||||
|
fg[0] = return_vals[1].data.d_color.red;
|
||||||
|
fg[1] = return_vals[1].data.d_color.green;
|
||||||
|
fg[2] = return_vals[1].data.d_color.blue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fg[0] = 255;
|
||||||
|
fg[1] = 255;
|
||||||
|
fg[2] = 255;
|
||||||
|
}
|
||||||
|
return_vals = gimp_run_procedure ("gimp_palette_get_background",
|
||||||
|
&nreturn_vals,
|
||||||
|
PARAM_END);
|
||||||
|
|
||||||
|
if (return_vals[0].data.d_status == STATUS_SUCCESS)
|
||||||
|
{
|
||||||
|
bg[0] = return_vals[1].data.d_color.red;
|
||||||
|
bg[1] = return_vals[1].data.d_color.green;
|
||||||
|
bg[2] = return_vals[1].data.d_color.blue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bg[0] = 0;
|
||||||
|
bg[1] = 0;
|
||||||
|
bg[2] = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case GRAYA_IMAGE: /* and again */
|
||||||
|
fg[1] = 255;
|
||||||
|
bg[1] = 255;
|
||||||
|
case GRAY_IMAGE:
|
||||||
|
|
||||||
|
return_vals = gimp_run_procedure ("gimp_palette_get_foreground",
|
||||||
|
&nreturn_vals,
|
||||||
|
PARAM_END);
|
||||||
|
|
||||||
|
if (return_vals[0].data.d_status == STATUS_SUCCESS)
|
||||||
|
{
|
||||||
|
fg[0] = 0.30 * return_vals[1].data.d_color.red +
|
||||||
|
0.59 * return_vals[1].data.d_color.green +
|
||||||
|
0.11 * return_vals[1].data.d_color.blue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fg[0] = 255;
|
||||||
|
}
|
||||||
|
|
||||||
|
return_vals = gimp_run_procedure ("gimp_palette_get_background",
|
||||||
|
&nreturn_vals,
|
||||||
|
PARAM_END);
|
||||||
|
|
||||||
|
if (return_vals[0].data.d_status == STATUS_SUCCESS)
|
||||||
|
{
|
||||||
|
bg[0] = 0.30 * return_vals[1].data.d_color.red +
|
||||||
|
0.59 * return_vals[1].data.d_color.green +
|
||||||
|
0.11 * return_vals[1].data.d_color.blue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bg[0] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case INDEXEDA_IMAGE:
|
||||||
|
case INDEXED_IMAGE: /* FIXME: Should use current fg/bg colors. */
|
||||||
|
g_warning("maze: get_colors: Indexed image. Using colors 15 and 0.\n");
|
||||||
|
fg[0] = 15; /* As a plugin, I protest. *I* shouldn't be the */
|
||||||
|
bg[0] = 0; /* one who has to deal with this colormapcrap. */
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Draws a solid color box in a GPixelRgn. */
|
||||||
|
/* Optimization assumptions:
|
||||||
|
* (Or, "Why Maze is Faster Than Checkerboard.")
|
||||||
|
*
|
||||||
|
* Assuming calling memcpy is faster than using loops.
|
||||||
|
* Row buffers are nice...
|
||||||
|
*
|
||||||
|
* Assume allocating memory for row buffers takes a significant amount
|
||||||
|
* of time. Assume drawbox will be called many times.
|
||||||
|
* Only allocate memory once.
|
||||||
|
*
|
||||||
|
* Do not assume the row buffer will always be the same size. Allow
|
||||||
|
* for reallocating to make it bigger if needed. However, I don't see
|
||||||
|
* reason to bother ever shrinking it again.
|
||||||
|
* (Under further investigation, assuming the row buffer never grows
|
||||||
|
* may be a safe assumption in this case.)
|
||||||
|
*
|
||||||
|
* Also assume that the program calling drawbox is short-lived, so
|
||||||
|
* memory leaks aren't of particular concern-- the memory allocated to
|
||||||
|
* the row buffer is never set free.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Further optimizations that could be made...
|
||||||
|
* Currently, the row buffer is re-filled with every call. However,
|
||||||
|
* plug-ins such as maze and checkerboard only use two colors, and
|
||||||
|
* for the most part, have rows of the same size with every call.
|
||||||
|
* We could keep a row of each color on hand so we wouldn't have to
|
||||||
|
* re-fill it every time... */
|
||||||
|
|
||||||
|
void
|
||||||
|
drawbox( GPixelRgn *dest_rgn,
|
||||||
|
guint x, guint y, guint w, guint h,
|
||||||
|
guint8 clr[4])
|
||||||
|
{
|
||||||
|
guint xx, yy, y_max, x_min /*, x_max */;
|
||||||
|
static guint8 *rowbuf;
|
||||||
|
guint rowsize;
|
||||||
|
static guint high_size=0;
|
||||||
|
|
||||||
|
/* The maximum [xy] value is that of the far end of the box, or
|
||||||
|
* the edge of the region, whichever comes first. */
|
||||||
|
|
||||||
|
y_max = dest_rgn->rowstride * MIN(dest_rgn->h, (y + h));
|
||||||
|
/* x_max = dest_rgn->bpp * MIN(dest_rgn->w, (x + w)); */
|
||||||
|
|
||||||
|
x_min = x * dest_rgn->bpp;
|
||||||
|
|
||||||
|
/* rowsize = x_max - x_min */
|
||||||
|
rowsize = dest_rgn->bpp * MIN(dest_rgn->w, (x + w)) - x_min;
|
||||||
|
|
||||||
|
/* Does the row buffer need to be (re)allocated? */
|
||||||
|
if (high_size == 0) {
|
||||||
|
rowbuf = g_new(guint8, rowsize);
|
||||||
|
} else if (rowsize > high_size) {
|
||||||
|
g_realloc(rowbuf, rowsize * sizeof(guint8) );
|
||||||
|
}
|
||||||
|
|
||||||
|
high_size = MAX(high_size, rowsize);
|
||||||
|
|
||||||
|
/* Fill the row buffer with the color. */
|
||||||
|
for (xx= 0;
|
||||||
|
xx < rowsize;
|
||||||
|
xx+= dest_rgn->bpp) {
|
||||||
|
memcpy (&rowbuf[xx], clr, dest_rgn->bpp);
|
||||||
|
} /* next xx */
|
||||||
|
|
||||||
|
/* Fill in the box in the region with rows... */
|
||||||
|
for (yy = dest_rgn->rowstride * y;
|
||||||
|
yy < y_max;
|
||||||
|
yy += dest_rgn->rowstride ) {
|
||||||
|
memcpy (&dest_rgn->data[yy+x_min], rowbuf, rowsize);
|
||||||
|
} /* next yy */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Alternate ways of doing things if you don't like memcpy. */
|
||||||
|
#if 0
|
||||||
|
for (xx= x * dest_rgn->bpp;
|
||||||
|
xx < bar;
|
||||||
|
xx+= dest_rgn->bpp) {
|
||||||
|
#if 0
|
||||||
|
for (bp=0; bp < dest_rgn->bpp; bp++) {
|
||||||
|
dest_rgn->data[yy+xx+bp]=clr[bp];
|
||||||
|
} /* next bp */
|
||||||
|
#else
|
||||||
|
memcpy (&dest_rgn->data[yy+xx], clr, dest_rgn->bpp);
|
||||||
|
#endif
|
||||||
|
} /* next xx */
|
||||||
|
} /* next yy */
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -1,4 +1,4 @@
|
||||||
/* maze.c, version 0.6.2, March 7, 1998.
|
/* maze.c
|
||||||
* This is a plug-in for the GIMP.
|
* This is a plug-in for the GIMP.
|
||||||
* It draws mazes...
|
* It draws mazes...
|
||||||
*
|
*
|
||||||
|
@ -6,66 +6,17 @@
|
||||||
* Kevin Turner <kevint@poboxes.com>
|
* Kevin Turner <kevint@poboxes.com>
|
||||||
* http://www.poboxes.com/kevint/gimp/maze.html
|
* http://www.poboxes.com/kevint/gimp/maze.html
|
||||||
*
|
*
|
||||||
* mazegen code from rec.games.programmer's maze-faq:
|
|
||||||
* * maz.c - generate a maze
|
|
||||||
* *
|
|
||||||
* * algorithm posted to rec.games.programmer by jallen@ic.sunysb.edu
|
|
||||||
* * program cleaned and reorganized by mzraly@ldbvax.dnet.lotus.com
|
|
||||||
* *
|
|
||||||
* * don't make people pay for this, or I'll jump up and down and
|
|
||||||
* * yell and scream and embarass you in front of your friends...
|
|
||||||
*
|
|
||||||
* Code generously borrowed from assorted GIMP plugins
|
* Code generously borrowed from assorted GIMP plugins
|
||||||
* and used as a template to get me started on this one. :)
|
* and used as a template to get me started on this one. :)
|
||||||
*
|
*
|
||||||
* Revision history:
|
|
||||||
* 0.6.2 - drawbox rewritten with memcpy and a row buffer. By the way, Maze is now
|
|
||||||
* faster than Checkerboard.
|
|
||||||
* - Added Help button using extension_web_browser.
|
|
||||||
* - Added DIVBOX_LOOKS_LIKE_SPINBUTTON flag. Doesn't look too hot, set to
|
|
||||||
* FALSE by default.
|
|
||||||
* 0.6.1 - Made use-time-for-random-seed a toggle button that remembers
|
|
||||||
* its state, and moved seed to the second notebook page.
|
|
||||||
* 0.6.0 - Width and height are now seperate options.
|
|
||||||
* ^^ Note this changed the PDB interface. ^^
|
|
||||||
*
|
|
||||||
* - Added interface for selecting sizes by "divisions".
|
|
||||||
* - Added "Time" button for random seed.
|
|
||||||
* - Turned out that GParam shouldn't have been "fixed".
|
|
||||||
* 0.5.0 - Added the long-awaited "tileable" option.
|
|
||||||
* Required a change to PDB parameters.
|
|
||||||
* - fixed some stuff with GParam values in run();
|
|
||||||
* 0.4.2 - Applied Adrian Likins' patch to fix non-interactive stuff.
|
|
||||||
* - -ansi and -pedantic-errors clean. Woo-hoo?
|
|
||||||
* 0.4.1 - get_colors() now works properly for grayscale images.
|
|
||||||
* I'd still like it to do indexed too, but I don't know
|
|
||||||
* if that's worth breaking a sweat over.
|
|
||||||
* - We're -Wall clean now. Woohoo!
|
|
||||||
* 0.4.0 - Code for the painting of the maze has been almost completely rebuilt.
|
|
||||||
* Hopefully it's a more sane and speedier approach.
|
|
||||||
* Utilizes a new function, drawbox, which colors a solid rectangle.
|
|
||||||
* (Good excercise, in any case.)
|
|
||||||
* - Order of paramaters changed, defaults are used if not given.
|
|
||||||
* - Discovery made that that was an utterly useless thing to do.
|
|
||||||
* 0.3.0 - Maze is centered with dead space around outside
|
|
||||||
* - Width slider works... And does stuff!
|
|
||||||
* - Allows partial mazes to be generated with "broken" multiple
|
|
||||||
* and offset values.
|
|
||||||
* 0.1.99 - Has dialog box with seed, multiple, and offset.
|
|
||||||
* 0.1.0 - First release. It works! :)
|
|
||||||
*
|
|
||||||
* TO DO:
|
* TO DO:
|
||||||
* Rework the divboxes to be more like spinbuttons.
|
* maze_face.c: Rework the divboxes to be more like spinbuttons.
|
||||||
*
|
*
|
||||||
* Add an option to kill the outer border.
|
* Maybe add an option to kill the outer border.
|
||||||
*
|
*
|
||||||
* Fix that stray line down there between maze wall and dead space border...
|
* Fix that stray line down there between maze wall and dead space border...
|
||||||
*
|
*
|
||||||
* Make get_colors() work with indexed. * HELP! *
|
* handy.c: Make get_colors() work with indexed. * HELP! *
|
||||||
*
|
|
||||||
* Also someday:
|
|
||||||
* Maybe make it work with irregularly shaped selections?
|
|
||||||
* Add different generation algorythms.
|
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -82,13 +33,14 @@
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, write to the Free Software
|
||||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef MAZE_DEBUG
|
#ifdef MAZE_DEBUG
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <time.h> /* For random seeding */
|
#include <time.h> /* For random seeding */
|
||||||
|
@ -103,21 +55,37 @@ static void run (gchar *name,
|
||||||
gint *nreturn_vals,
|
gint *nreturn_vals,
|
||||||
GParam **return_vals);
|
GParam **return_vals);
|
||||||
static void maze (GDrawable * drawable);
|
static void maze (GDrawable * drawable);
|
||||||
static gint mazegen(gint pos,
|
|
||||||
gchar *maz,
|
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,
|
||||||
gint x,
|
gint x,
|
||||||
gint y,
|
gint y,
|
||||||
gint rnd);
|
gint rnd);
|
||||||
static gint mazegen_tileable(gint pos,
|
extern void mazegen_tileable(gint pos,
|
||||||
gchar *maz,
|
guchar *maz,
|
||||||
gint x,
|
gint x,
|
||||||
gint y,
|
gint y,
|
||||||
gint rnd);
|
gint rnd);
|
||||||
static void get_colors (GDrawable * drawable,
|
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,
|
||||||
guint8 *fg,
|
guint8 *fg,
|
||||||
guint8 *bg);
|
guint8 *bg);
|
||||||
|
|
||||||
static void drawbox (GPixelRgn *dest_rgn,
|
extern void drawbox (GPixelRgn *dest_rgn,
|
||||||
guint x,
|
guint x,
|
||||||
guint y,
|
guint y,
|
||||||
guint w,
|
guint w,
|
||||||
|
@ -141,6 +109,7 @@ MazeValues mvals =
|
||||||
FALSE, /* Tileable? */
|
FALSE, /* Tileable? */
|
||||||
57, /* multiple * These two had "Experiment with this?" comments */
|
57, /* multiple * These two had "Experiment with this?" comments */
|
||||||
1, /* offset * in the maz.c source, so, lets expiriment. :) */
|
1, /* offset * in the maz.c source, so, lets expiriment. :) */
|
||||||
|
DEPTH_FIRST, /* Algorithm */
|
||||||
/* Interface options */
|
/* Interface options */
|
||||||
TRUE /* Time seed? */
|
TRUE /* Time seed? */
|
||||||
};
|
};
|
||||||
|
@ -155,26 +124,28 @@ query ()
|
||||||
static GParamDef args[] =
|
static GParamDef args[] =
|
||||||
{
|
{
|
||||||
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
|
{ PARAM_INT32, "run_mode", "Interactive, non-interactive" },
|
||||||
{ PARAM_IMAGE, "image", "Input image (unused)" },
|
{ PARAM_IMAGE, "image_ID", "(unused)" },
|
||||||
{ PARAM_DRAWABLE, "drawable", "Input drawable" },
|
{ PARAM_DRAWABLE, "drawable_ID", "ID of drawable" },
|
||||||
/* If we did have parameters, these be them: */
|
/* If we did have parameters, these be them: */
|
||||||
{ PARAM_INT32, "mazep_width", "Width of the passages" },
|
{ PARAM_INT16, "width", "Width of the passages" },
|
||||||
{ PARAM_INT32, "mazep_height", "Height of the passages"},
|
{ PARAM_INT16, "height", "Height of the passages"},
|
||||||
{ PARAM_INT8, "maze_tile", "Tileable maze?"},
|
{ PARAM_INT8, "tileable", "Tileable maze?"},
|
||||||
{ PARAM_INT32, "maze_rseed", "Random Seed"},
|
{ PARAM_INT8, "algorithm", "Generation algorithm"
|
||||||
{ PARAM_INT32, "maze_multiple", "Multiple (use 57)" },
|
"(0=DEPTH FIRST, 1=PRIM'S ALGORITHM)" },
|
||||||
{ PARAM_INT32, "maze_offset", "Offset (use 1)" }
|
{ PARAM_INT32, "seed", "Random Seed"},
|
||||||
|
{ PARAM_INT16, "multiple", "Multiple (use 57)" },
|
||||||
|
{ PARAM_INT16, "offset", "Offset (use 1)" }
|
||||||
};
|
};
|
||||||
static GParamDef *return_vals = NULL;
|
static GParamDef *return_vals = NULL;
|
||||||
static int nargs = sizeof (args) / sizeof (args[0]);
|
static int nargs = sizeof (args) / sizeof (args[0]);
|
||||||
static int nreturn_vals = 0;
|
static int nreturn_vals = 0;
|
||||||
|
|
||||||
gimp_install_procedure ("plug_in_maze",
|
gimp_install_procedure ("plug_in_maze",
|
||||||
"Generates a maze.",
|
"Draws a maze.",
|
||||||
"Generates a maze using the depth-first search method.",
|
"Generates a maze using either the depth-first search method or Prim's algorithm. Can make tileable mazes too. See " MAZE_URL " for more help.",
|
||||||
"Kevin Turner <kevint@poboxes.com>",
|
"Kevin Turner <kevint@poboxes.com>",
|
||||||
"Kevin Turner",
|
"Kevin Turner",
|
||||||
"1997",
|
"1997, 1998",
|
||||||
"<Image>/Filters/Render/Maze",
|
"<Image>/Filters/Render/Maze",
|
||||||
"RGB*, GRAY*, INDEXED*",
|
"RGB*, GRAY*, INDEXED*",
|
||||||
PROC_PLUG_IN,
|
PROC_PLUG_IN,
|
||||||
|
@ -226,18 +197,19 @@ run (gchar *name,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RUN_NONINTERACTIVE:
|
case RUN_NONINTERACTIVE:
|
||||||
if (nparams != 9)
|
if (nparams != 10)
|
||||||
{
|
{
|
||||||
status = STATUS_CALLING_ERROR;
|
status = STATUS_CALLING_ERROR;
|
||||||
}
|
}
|
||||||
if (status == STATUS_SUCCESS)
|
if (status == STATUS_SUCCESS)
|
||||||
{
|
{
|
||||||
mvals.width = (gint) param[3].data.d_int32;
|
mvals.width = (gint16) param[3].data.d_int32;
|
||||||
mvals.height = (gint) param[4].data.d_int32;
|
mvals.height = (gint16) param[4].data.d_int32;
|
||||||
mvals.seed = (gint) param[5].data.d_int32;
|
mvals.tile = (gint8) param[5].data.d_int32;
|
||||||
mvals.tile = (gboolean) param[6].data.d_int32;
|
mvals.algorithm = (gint8) param[6].data.d_int32;
|
||||||
mvals.multiple = (gint) param[7].data.d_int32;
|
mvals.seed = (gint32) param[7].data.d_int32;
|
||||||
mvals.offset = (gint) param[8].data.d_int32;
|
mvals.multiple = (gint16) param[8].data.d_int32;
|
||||||
|
mvals.offset = (gint16) param[9].data.d_int32;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case RUN_WITH_LAST_VALS:
|
case RUN_WITH_LAST_VALS:
|
||||||
|
@ -251,7 +223,6 @@ run (gchar *name,
|
||||||
|
|
||||||
/* color, gray, or indexed... hmm, miss anything? ;) */
|
/* color, gray, or indexed... hmm, miss anything? ;) */
|
||||||
if (gimp_drawable_color (drawable->id) || gimp_drawable_gray (drawable->id) || gimp_drawable_indexed (drawable->id)) {
|
if (gimp_drawable_color (drawable->id) || gimp_drawable_gray (drawable->id) || gimp_drawable_indexed (drawable->id)) {
|
||||||
gimp_progress_init ("Drawing Maze...");
|
|
||||||
|
|
||||||
maze (drawable);
|
maze (drawable);
|
||||||
|
|
||||||
|
@ -270,34 +241,56 @@ run (gchar *name,
|
||||||
gimp_drawable_detach (drawable);
|
gimp_drawable_detach (drawable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#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
|
||||||
|
|
||||||
static void
|
static void
|
||||||
maze( GDrawable * drawable)
|
maze( GDrawable * drawable)
|
||||||
{
|
{
|
||||||
GPixelRgn dest_rgn;
|
GPixelRgn dest_rgn;
|
||||||
gint mw, mh;
|
guint mw, mh;
|
||||||
gint deadx, deady;
|
gint deadx, deady;
|
||||||
gint progress, max_progress;
|
guint progress, max_progress;
|
||||||
gint x1, y1, x2, y2, x, y;
|
gint x1, y1, x2, y2, x, y;
|
||||||
gint dx, dy, xx, yy;
|
gint dx, dy, xx, yy;
|
||||||
gint foo, bar, baz;
|
gint maz_x, maz_xx, maz_row, maz_yy;
|
||||||
guint8 fg[4],bg[4];
|
guint8 fg[4],bg[4];
|
||||||
gpointer pr;
|
gpointer pr;
|
||||||
|
gboolean active_selection;
|
||||||
|
|
||||||
gchar *maz;
|
guchar *maz;
|
||||||
|
guint pos;
|
||||||
|
|
||||||
/* Gets the input area... */
|
/* Gets the input area... */
|
||||||
gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2);
|
active_selection = gimp_drawable_mask_bounds (drawable->id, &x1, &y1, &x2, &y2);
|
||||||
|
|
||||||
/* Initialize pixel region (?) */
|
/***************** Maze Stuff Happens Here ***************/
|
||||||
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);
|
|
||||||
|
|
||||||
/* Maze Stuff Happens Here */
|
|
||||||
mw = (x2-x1) / mvals.width;
|
mw = (x2-x1) / mvals.width;
|
||||||
mh = (y2-y1) / mvals.height;
|
mh = (y2-y1) / mvals.height;
|
||||||
|
|
||||||
|
@ -314,7 +307,7 @@ maze( GDrawable * drawable)
|
||||||
deadx = ((x2-x1) - mw * mvals.width)/2;
|
deadx = ((x2-x1) - mw * mvals.width)/2;
|
||||||
deady = ((y2-y1) - mh * mvals.height)/2;
|
deady = ((y2-y1) - mh * mvals.height)/2;
|
||||||
|
|
||||||
maz = g_malloc0(mw * mh);
|
maz = g_new0(guchar, mw * mh);
|
||||||
|
|
||||||
#ifdef MAZE_DEBUG
|
#ifdef MAZE_DEBUG
|
||||||
printf("x: %d\ty: %d\nmw: %d\tmh: %d\ndx: %d\tdy: %d\nwidth:%d\theight: %d\n",
|
printf("x: %d\ty: %d\nmw: %d\tmh: %d\ndx: %d\tdy: %d\nwidth:%d\theight: %d\n",
|
||||||
|
@ -324,13 +317,75 @@ maze( GDrawable * drawable)
|
||||||
if (mvals.timeseed)
|
if (mvals.timeseed)
|
||||||
mvals.seed = time(NULL);
|
mvals.seed = time(NULL);
|
||||||
|
|
||||||
if (mvals.tile) {
|
/* Sanity check: */
|
||||||
(void) mazegen_tileable((mw+1), maz, mw, mh, mvals.seed);
|
switch (mvals.algorithm) {
|
||||||
} else {
|
case DEPTH_FIRST:
|
||||||
(void) mazegen((mw+1), maz, mw, mh, mvals.seed);
|
break;
|
||||||
/* (void) mazegen(((x2-x1)+1), maz, (x2-x1), (y2-y1), rnd); */
|
case PRIMS_ALGORITHM:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
g_warning("maze: Invalid algorithm choice %d", mvals.algorithm);
|
||||||
}
|
}
|
||||||
/* It's done happening. Now go through and color dem pixels... */
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
gimp_progress_init ("Drawing Maze...");
|
||||||
|
|
||||||
for (pr = gimp_pixel_rgns_register (1, &dest_rgn);
|
for (pr = gimp_pixel_rgns_register (1, &dest_rgn);
|
||||||
pr != NULL;
|
pr != NULL;
|
||||||
|
@ -345,375 +400,276 @@ maze( GDrawable * drawable)
|
||||||
|
|
||||||
dx = mvals.width - (x % mvals.width);
|
dx = mvals.width - (x % mvals.width);
|
||||||
dy = mvals.height - (y % mvals.height);
|
dy = mvals.height - (y % mvals.height);
|
||||||
foo = x/mvals.width;
|
maz_x = x/mvals.width;
|
||||||
bar = mw * (y/mvals.height);
|
maz_row = mw * (y/mvals.height);
|
||||||
|
|
||||||
/* Draws the upper-left [split] box */
|
/* Draws the upper-left [split] box */
|
||||||
drawbox(&dest_rgn,0,0,dx,dy,
|
drawbox(&dest_rgn,0,0,dx,dy,
|
||||||
maz[foo+bar] ? fg : bg);
|
(maz[maz_row+maz_x]==IN) ? fg : bg);
|
||||||
|
|
||||||
baz=foo+1;
|
maz_xx=maz_x+1;
|
||||||
/* Draw the top row [split] boxes */
|
/* Draw the top row [split] boxes */
|
||||||
for(xx=dx; xx < dest_rgn.w; xx+=mvals.width)
|
for(xx=dx; xx < dest_rgn.w; xx+=mvals.width)
|
||||||
{ drawbox(&dest_rgn,xx,0,mvals.width,dy,
|
{ drawbox(&dest_rgn,xx,0,mvals.width,dy,
|
||||||
maz[bar + baz++] ? fg : bg ); }
|
(maz[maz_row + maz_xx++]==IN) ? fg : bg ); }
|
||||||
|
|
||||||
baz=bar+mw;
|
maz_yy=maz_row+mw;
|
||||||
/* Left column */
|
/* Left column */
|
||||||
for(yy=dy; yy < dest_rgn.h; yy+=mvals.height) {
|
for(yy=dy; yy < dest_rgn.h; yy+=mvals.height) {
|
||||||
drawbox(&dest_rgn,0,yy,dx,mvals.height,
|
drawbox(&dest_rgn,0,yy,dx,mvals.height,
|
||||||
maz[foo + baz] ? fg : bg );
|
(maz[maz_yy + maz_x]==IN) ? fg : bg );
|
||||||
baz += mw;
|
maz_yy += mw;
|
||||||
}
|
}
|
||||||
|
|
||||||
foo++;
|
maz_x++;
|
||||||
/* Everything else */
|
/* Everything else */
|
||||||
for(yy=dy; yy < dest_rgn.h; yy+=mvals.height) {
|
for(yy=dy; yy < dest_rgn.h; yy+=mvals.height) {
|
||||||
baz = foo; bar+=mw;
|
maz_xx = maz_x; maz_row+=mw;
|
||||||
for(xx=dx; xx < dest_rgn.w; xx+=mvals.width)
|
for(xx=dx; xx < dest_rgn.w; xx+=mvals.width)
|
||||||
{
|
{
|
||||||
drawbox(&dest_rgn,xx,yy,mvals.width,mvals.height,
|
drawbox(&dest_rgn,xx,yy,mvals.width,mvals.height,
|
||||||
maz[bar + baz++] ? fg : bg ); }
|
(maz[maz_row + maz_xx++]==IN) ? fg : bg ); }
|
||||||
}
|
}
|
||||||
|
|
||||||
progress += dest_rgn.w * dest_rgn.h;
|
progress += dest_rgn.w * dest_rgn.h;
|
||||||
gimp_progress_update ((double) progress / (double) max_progress);
|
gimp_progress_update ((double) progress / (double) max_progress);
|
||||||
/* Note the progess indicator doesn't indicate how much of the maze
|
/* Indicate progress in drawing. */
|
||||||
has been built... It just indicates how much has been drawn
|
|
||||||
*after* building... Thing is, that's what takes longer. */
|
|
||||||
}
|
}
|
||||||
gimp_drawable_flush (drawable);
|
gimp_drawable_flush (drawable);
|
||||||
gimp_drawable_merge_shadow (drawable->id, TRUE);
|
gimp_drawable_merge_shadow (drawable->id, TRUE);
|
||||||
gimp_drawable_update (drawable->id, x1, y1, (x2 - x1), (y2 - y1));
|
gimp_drawable_update (drawable->id, x1, y1, (x2 - x1), (y2 - y1));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Draws a solid color box in a GPixelRgn. */
|
/* Shaped mazes: */
|
||||||
/* Optimization assumptions:
|
/* With
|
||||||
* (Or, "Why Maze is Faster Than Checkerboard.")
|
* 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.
|
||||||
*
|
*
|
||||||
* Assuming calling memcpy is faster than using loops.
|
* So we'll put unavailable cells in a non-zero non-in non-out class
|
||||||
* Row buffers are nice...
|
* called MASKED.
|
||||||
*
|
|
||||||
* Assume allocating memory for row buffers takes a significant amount
|
|
||||||
* of time. Assume drawbox will be called many times.
|
|
||||||
* Only allocate memory once.
|
|
||||||
*
|
|
||||||
* Do not assume the row buffer will always be the same size. Allow
|
|
||||||
* for reallocating to make it bigger if needed. However, I don't see
|
|
||||||
* reason to bother ever shrinking it again.
|
|
||||||
* (Under further investigation, assuming the row buffer never grows
|
|
||||||
* may be a safe assumption in this case.)
|
|
||||||
*
|
|
||||||
* Also assume that the program calling drawbox is short-lived, so
|
|
||||||
* memory leaks aren't of particular concern-- the memory allocated to
|
|
||||||
* the row buffer is never set free.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Further optimizations that could be made...
|
/* But first... A little discussion about cells. */
|
||||||
* Currently, the row buffer is re-filled with every call. However,
|
|
||||||
* plug-ins such as maze and checkerboard only use two colors, and
|
|
||||||
* for the most part, have rows of the same size with every call.
|
|
||||||
* We could keep a row of each color on hand so we wouldn't have to
|
|
||||||
* re-fill it every time... */
|
|
||||||
|
|
||||||
|
/* 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* 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
|
static void
|
||||||
drawbox( GPixelRgn *dest_rgn,
|
mask_maze(gint32 drawable_ID, guchar *maz, guint mw, guint mh,
|
||||||
guint x, guint y, guint w, guint h,
|
gint x1, gint x2, gint y1, gint y2, gint deadx, gint deady)
|
||||||
guint8 clr[4])
|
|
||||||
{
|
{
|
||||||
guint xx, yy, y_max, x_min /*, x_max */;
|
gint32 selection_ID;
|
||||||
static guint8 *rowbuf;
|
GPixelRgn sel_rgn;
|
||||||
guint rowsize;
|
gint xx0=0, yy0=0, xoff, yoff;
|
||||||
static guint high_size=0;
|
guint xx=0, yy=0;
|
||||||
|
guint foo=0;
|
||||||
|
|
||||||
/* The maximum [xy] value is that of the far end of the box, or
|
gint cur_row, cur_col;
|
||||||
* the edge of the region, whichever comes first. */
|
gint x1half, x2half, y1half, y2half;
|
||||||
|
guchar *linebuf;
|
||||||
|
|
||||||
y_max = dest_rgn->rowstride * MIN(dest_rgn->h, (y + h));
|
if ((selection_ID =
|
||||||
/* x_max = dest_rgn->bpp * MIN(dest_rgn->w, (x + w)); */
|
gimp_image_get_selection(gimp_drawable_image_id(drawable_ID)))
|
||||||
|
== -1)
|
||||||
|
return;
|
||||||
|
|
||||||
x_min = x * dest_rgn->bpp;
|
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);
|
||||||
|
|
||||||
/* rowsize = x_max - x_min */
|
/* Special cases: If mw or mh < 3 */
|
||||||
rowsize = dest_rgn->bpp * MIN(dest_rgn->w, (x + w)) - x_min;
|
/* FIXME (Currently works, but inefficiently.) */
|
||||||
|
|
||||||
/* Does the row buffer need to be (re)allocated? */
|
/* mw && mh => 3 */
|
||||||
if (high_size == 0) {
|
|
||||||
rowbuf = g_new(guint8, rowsize);
|
|
||||||
} else if (rowsize > high_size) {
|
|
||||||
g_realloc(rowbuf, rowsize * sizeof(guint8) );
|
|
||||||
}
|
|
||||||
|
|
||||||
high_size = MAX(high_size, rowsize);
|
linebuf = g_new(guchar, sel_rgn.w * sel_rgn.bpp);
|
||||||
|
|
||||||
/* Fill the row buffer with the color. */
|
xx0 = x1 + deadx + mvals.width + xoff;
|
||||||
for (xx= 0;
|
yy0 = y1 + deady + mvals.height + yoff;
|
||||||
xx < rowsize;
|
|
||||||
xx+= dest_rgn->bpp) {
|
|
||||||
memcpy (&rowbuf[xx], clr, dest_rgn->bpp);
|
|
||||||
} /* next xx */
|
|
||||||
|
|
||||||
/* Fill in the box in the region with rows... */
|
x1half = mvals.width/2;
|
||||||
for (yy = dest_rgn->rowstride * y;
|
x2half = mvals.width - 1;
|
||||||
yy < y_max;
|
|
||||||
yy += dest_rgn->rowstride ) {
|
|
||||||
memcpy (&dest_rgn->data[yy+x_min], rowbuf, rowsize);
|
|
||||||
} /* next yy */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The old drawbox code, preserved here 'just in case' something
|
y1half = mvals.height/2;
|
||||||
doesn't go right. */
|
y2half = mvals.height - 1;
|
||||||
|
|
||||||
|
/* Here, yy is with respect to the drawable (or something),
|
||||||
|
whereas xx is with respect to the row buffer. */
|
||||||
|
|
||||||
|
yy=yy0 + y1half;
|
||||||
|
for(cur_row=1; cur_row < mh; cur_row += 2) {
|
||||||
|
|
||||||
|
gimp_pixel_rgn_get_row(&sel_rgn, linebuf, x1+xoff, yy, (x2-x1));
|
||||||
|
|
||||||
|
cur_col=1; xx=mvals.width;
|
||||||
|
while(cur_col < mw) {
|
||||||
|
|
||||||
|
/* Cell: */
|
||||||
|
maz[cur_row * mw + cur_col] =
|
||||||
|
(linebuf[xx] + linebuf[xx + x1half] + linebuf[xx+x2half]) / 5;
|
||||||
|
|
||||||
|
cur_col += 1;
|
||||||
|
xx += mvals.width;
|
||||||
|
|
||||||
|
/* Passage: */
|
||||||
|
if (cur_col < mw)
|
||||||
|
maz[cur_row * mw + cur_col] =
|
||||||
|
(linebuf[xx] + linebuf[xx + x1half] + linebuf[xx+x2half]) / 3;
|
||||||
|
|
||||||
|
cur_col += 1;
|
||||||
|
xx += mvals.width;
|
||||||
|
|
||||||
|
} /* next col */
|
||||||
|
|
||||||
|
yy += 2 * mvals.height;
|
||||||
|
|
||||||
|
} /* 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
|
#if 0
|
||||||
for (xx= x * dest_rgn->bpp;
|
|
||||||
xx < bar;
|
|
||||||
xx+= dest_rgn->bpp) {
|
|
||||||
#if 0
|
|
||||||
for (bp=0; bp < dest_rgn->bpp; bp++) {
|
|
||||||
dest_rgn->data[yy+xx+bp]=clr[bp];
|
|
||||||
} /* next bp */
|
|
||||||
#else
|
|
||||||
memcpy (&dest_rgn->data[yy+xx], clr, dest_rgn->bpp);
|
|
||||||
#endif
|
|
||||||
} /* next xx */
|
|
||||||
} /* next yy */
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* The Incredible Recursive Maze Generation Routine */
|
/* Tiles make my life decidedly difficult here. There are too
|
||||||
/* Ripped from rec.programmers.games maze-faq */
|
* many special cases... "What if a tile starts less/more than
|
||||||
/* Modified and commented by me, Kevin Turner. */
|
* halfway through a block? What if we get a narrow edge-tile
|
||||||
gint mazegen(pos, maz, x, y, rnd)
|
* that..." etc, etc. I shall investigate other options.
|
||||||
gint pos, x, y, rnd;
|
* Possibly a row buffer, or can we use something other than this
|
||||||
gchar *maz;
|
* black-magic gimp_pixel_rgns_register call to get tiles of
|
||||||
{
|
* different sizes? Now that'd be nice... */
|
||||||
gchar d, i;
|
|
||||||
gint c=0, j=1;
|
|
||||||
|
|
||||||
/* Punch a hole here... */
|
for (pr = gimp_pixel_rgns_register (1, &sel_rgn);
|
||||||
maz[pos] = 1;
|
pr != NULL;
|
||||||
|
pr = gimp_pixel_rgns_process (pr)) {
|
||||||
|
|
||||||
/* If there is a wall two rows above us, bit 1 is 1. */
|
/* This gives us coordinates relative to the starting point
|
||||||
while((d= (pos <= (x * 2) ? 0 : (maz[pos - x - x ] ? 0 : 1))
|
* of the maze grid. Negative values happen here if there
|
||||||
/* If there is a wall two rows below us, bit 2 is 1. */
|
* is dead space. */
|
||||||
| (pos >= x * (y - 2) ? 0 : (maz[pos + x + x] ? 0 : 2))
|
x = sel_rgn.x - x1 - deadx;
|
||||||
/* If there is a wall two columns to the right, bit 3 is 1. */
|
y = sel_rgn.y - y1 - deady;
|
||||||
| (pos % x == x - 2 ? 0 : (maz[pos + 2] ? 0 : 4))
|
|
||||||
/* If there is a wall two colums to the left, bit 4 is 1. */
|
|
||||||
| ((pos % x == 1 ) ? 0 : (maz[pos-2] ? 0 : 8)))) {
|
|
||||||
|
|
||||||
/* Note if all bits are 0, d is false, we don't do this
|
/* These coordinates are relative to the current tile. */
|
||||||
while loop, we don't call ourselves again, so this branch
|
/* This starts us off at the first block boundary in the
|
||||||
is done. */
|
* tile. */
|
||||||
|
|
||||||
/* I see what this loop does (more or less), but I don't know
|
/* e.g. with x=16 and width=10.
|
||||||
_why_ it does it this way... I also haven't figured out exactly
|
* 16 % 10 = 6
|
||||||
which values of multiple will work and which won't. */
|
* 10 - 6 = 4
|
||||||
do {
|
|
||||||
rnd = (rnd * mvals.multiple + mvals.offset);
|
|
||||||
i = 3 & (rnd / d);
|
|
||||||
if (++c > 100) { /* Break and try to salvage something */
|
|
||||||
i=99; /* if it looks like we're going to be */
|
|
||||||
break; /* here forever... */
|
|
||||||
}
|
|
||||||
} while ( !(d & ( 1 << i) ) );
|
|
||||||
/* ...While there's *not* a wall in direction i. */
|
|
||||||
/* (stop looping when there is) */
|
|
||||||
|
|
||||||
switch (i) { /* This is simple enough. */
|
x: 6789!123456789!123456789!12
|
||||||
case 0: /* Go in the direction we just figured . . . */
|
....|.........|.........|..
|
||||||
j= -x;
|
xx: 0123456789!123456789!123456
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
j = x;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
j=1;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
j= -1;
|
|
||||||
break;
|
|
||||||
case 99:
|
|
||||||
return 1; /* Hey neat, broken mazes! */
|
|
||||||
break; /* (Umm... Wow... Yeah, neat.) */
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* And punch a hole there. */
|
So to start on the boundary, begin at 4.
|
||||||
maz[pos + j] = 1;
|
|
||||||
|
|
||||||
/* Now, start again just past where we punched the hole... */
|
For the case x=0, 10-0=10. So xx0 will always between 1 and width. */
|
||||||
mazegen(pos + 2 * j, maz, x, y, rnd);
|
|
||||||
|
|
||||||
} /* End while(d=...) Loop */
|
xx0 = mvals.width - (x % mvals.width);
|
||||||
|
yy0 = mvals.height - (y % mvals.height);
|
||||||
|
|
||||||
return 0;
|
/* Find the corresponding row and column in the maze. */
|
||||||
}
|
maz_x = (x+xx0)/mvals.width;
|
||||||
|
maz_row = mw * ((y + yy0)/mvals.height);
|
||||||
|
|
||||||
#define ABSMOD(A,B) ( ((A) < 0) ? (((B) + (A)) % (B)) : ((A) % (B)) )
|
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 */
|
||||||
|
|
||||||
/* Tileable mazes are my creation, based on the routine above. */
|
} /* next pr sel_rgn tile thing */
|
||||||
static gint mazegen_tileable(gint pos, gchar *maz, gint x, gint y, gint rnd)
|
/* #ifdef MAZE_DEBUG
|
||||||
{
|
maze_dump(maz,mw,mh);
|
||||||
gchar d, i;
|
#endif */
|
||||||
gint c=0, j=1, npos=2;
|
} /* mask_maze */
|
||||||
|
#endif /* 0 */
|
||||||
/* Punch a hole here... */
|
|
||||||
maz[pos] = 1;
|
|
||||||
|
|
||||||
/* If there is a wall two rows above us, bit 1 is 1. */
|
|
||||||
while((d= (pos < (x*2) ? (maz[x*(y-2)+pos] ? 0 : 1) : (maz[pos - x - x ] ? 0 : 1))
|
|
||||||
/* If there is a wall two rows below us, bit 2 is 1. */
|
|
||||||
| (pos >= x * (y-2) ? (maz[pos - x*(y-2)] ? 0 : 2) : (maz[pos +x+x] ? 0 : 2))
|
|
||||||
/* If there is a wall two columns to the right, bit 3 is 1. */
|
|
||||||
| (pos % x >= x - 2 ? (maz[pos + 2 - x] ? 0 : 4) : (maz[pos + 2] ? 0 : 4))
|
|
||||||
/* If there is a wall two colums to the left, bit 4 is 1. */
|
|
||||||
| ((pos % x <= 1 ) ? (maz[pos + x - 2] ? 0 : 8) : (maz[pos-2] ? 0 : 8)))) {
|
|
||||||
|
|
||||||
/* Note if all bits are 0, d is false, we don't do this
|
|
||||||
while loop, we don't call ourselves again, so this branch
|
|
||||||
is done. */
|
|
||||||
|
|
||||||
/* I see what this loop does (more or less), but I don't know
|
|
||||||
_why_ it does it this way... I also haven't figured out exactly
|
|
||||||
which values of multiple will work and which won't. */
|
|
||||||
do {
|
|
||||||
rnd = (rnd * mvals.multiple + mvals.offset);
|
|
||||||
i = 3 & (rnd / d);
|
|
||||||
if (++c > 100) { /* Break and try to salvage something */
|
|
||||||
i=99; /* if it looks like we're going to be */
|
|
||||||
break; /* here forever... */
|
|
||||||
}
|
|
||||||
} while ( !(d & ( 1 << i) ) );
|
|
||||||
/* ...While there's *not* a wall in direction i. */
|
|
||||||
/* (stop looping when there is) */
|
|
||||||
|
|
||||||
switch (i) { /* This is simple enough. */
|
|
||||||
case 0: /* Go in the direction we just figured . . . */
|
|
||||||
j = pos < x ? x*(y-1)+pos : pos - x;
|
|
||||||
npos = pos < (x*2) ? x*(y-2)+pos : pos - x - x;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
j = pos >= x*(y-1) ? pos - x * (y-1) : pos + x;
|
|
||||||
npos = pos >= x*(y-2) ? pos - x*(y-2) : pos + x + x;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
j = (pos % x) == (x - 1) ? pos + 1 - x : pos + 1;
|
|
||||||
npos = (pos % x) >= (x - 2) ? pos + 2 - x : pos + 2;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
j= (pos % x) == 0 ? pos + x - 1 : pos - 1;
|
|
||||||
npos = (pos % x) <= 1 ? pos + x - 2 : pos - 2;
|
|
||||||
break;
|
|
||||||
case 99:
|
|
||||||
return 1; /* Hey neat, broken mazes! */
|
|
||||||
break; /* (Umm... Wow... Yeah, neat.) */
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* And punch a hole there. */
|
|
||||||
maz[j] = 1;
|
|
||||||
|
|
||||||
/* Now, start again just past where we punched the hole... */
|
|
||||||
mazegen_tileable(npos, maz, x, y, rnd);
|
|
||||||
|
|
||||||
} /* End while(d=...) Loop */
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
get_colors (GDrawable *drawable, guint8 *fg, guint8 *bg)
|
|
||||||
{
|
|
||||||
GParam *return_vals;
|
|
||||||
gint nreturn_vals;
|
|
||||||
|
|
||||||
switch ( gimp_drawable_type (drawable->id) )
|
|
||||||
{
|
|
||||||
case RGBA_IMAGE: /* ASSUMPTION: Assuming the user wants entire */
|
|
||||||
fg[3] = 255; /* area to be fully opaque. */
|
|
||||||
bg[3] = 255;
|
|
||||||
case RGB_IMAGE:
|
|
||||||
|
|
||||||
return_vals = gimp_run_procedure ("gimp_palette_get_foreground",
|
|
||||||
&nreturn_vals,
|
|
||||||
PARAM_END);
|
|
||||||
|
|
||||||
if (return_vals[0].data.d_status == STATUS_SUCCESS)
|
|
||||||
{
|
|
||||||
fg[0] = return_vals[1].data.d_color.red;
|
|
||||||
fg[1] = return_vals[1].data.d_color.green;
|
|
||||||
fg[2] = return_vals[1].data.d_color.blue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fg[0] = 255;
|
|
||||||
fg[1] = 255;
|
|
||||||
fg[2] = 255;
|
|
||||||
}
|
|
||||||
return_vals = gimp_run_procedure ("gimp_palette_get_background",
|
|
||||||
&nreturn_vals,
|
|
||||||
PARAM_END);
|
|
||||||
|
|
||||||
if (return_vals[0].data.d_status == STATUS_SUCCESS)
|
|
||||||
{
|
|
||||||
bg[0] = return_vals[1].data.d_color.red;
|
|
||||||
bg[1] = return_vals[1].data.d_color.green;
|
|
||||||
bg[2] = return_vals[1].data.d_color.blue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bg[0] = 0;
|
|
||||||
bg[1] = 0;
|
|
||||||
bg[2] = 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case GRAYA_IMAGE: /* and again */
|
|
||||||
fg[1] = 255;
|
|
||||||
bg[1] = 255;
|
|
||||||
case GRAY_IMAGE:
|
|
||||||
|
|
||||||
return_vals = gimp_run_procedure ("gimp_palette_get_foreground",
|
|
||||||
&nreturn_vals,
|
|
||||||
PARAM_END);
|
|
||||||
|
|
||||||
if (return_vals[0].data.d_status == STATUS_SUCCESS)
|
|
||||||
{
|
|
||||||
fg[0] = 0.30 * return_vals[1].data.d_color.red +
|
|
||||||
0.59 * return_vals[1].data.d_color.green +
|
|
||||||
0.11 * return_vals[1].data.d_color.blue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
fg[0] = 255;
|
|
||||||
}
|
|
||||||
|
|
||||||
return_vals = gimp_run_procedure ("gimp_palette_get_background",
|
|
||||||
&nreturn_vals,
|
|
||||||
PARAM_END);
|
|
||||||
|
|
||||||
if (return_vals[0].data.d_status == STATUS_SUCCESS)
|
|
||||||
{
|
|
||||||
bg[0] = 0.30 * return_vals[1].data.d_color.red +
|
|
||||||
0.59 * return_vals[1].data.d_color.green +
|
|
||||||
0.11 * return_vals[1].data.d_color.blue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
bg[0] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
case INDEXEDA_IMAGE:
|
|
||||||
case INDEXED_IMAGE: /* FIXME: Should use current fg/bg colors. */
|
|
||||||
g_warning("maze: get_colors: Indexed image. Using colors 15 and 0.\n");
|
|
||||||
fg[0] = 15; /* As a plugin, I protest. *I* shouldn't be the */
|
|
||||||
bg[0] = 0; /* one who has to deal with this colormapcrap. */
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#define MAZE_TITLE "Maze 0.6.2"
|
#define MAZE_TITLE "Maze 1.2.1"
|
||||||
#define MAZE_URL "http://www.poboxes.com/kevint/gimp/maze.html"
|
#define MAZE_URL "http://www.poboxes.com/kevint/gimp/maze-help.html"
|
||||||
|
|
||||||
#define HELP_OPENS_NEW_WINDOW FALSE
|
#define HELP_OPENS_NEW_WINDOW FALSE
|
||||||
|
|
||||||
|
@ -8,15 +8,36 @@
|
||||||
latter leaves much to be desired. */
|
latter leaves much to be desired. */
|
||||||
#define DIVBOX_LOOKS_LIKE_SPINBUTTON FALSE
|
#define DIVBOX_LOOKS_LIKE_SPINBUTTON FALSE
|
||||||
|
|
||||||
#include "gtk/gtk.h"
|
/* Don't update the progress for every cell when creating a maze.
|
||||||
|
Instead, update every . . . */
|
||||||
|
#define PRIMS_PROGRESS_UPDATE 256
|
||||||
|
|
||||||
|
/* Don't draw in anything that has less than
|
||||||
|
this value in the selection channel. */
|
||||||
|
#define MAZE_ALPHA_THRESHOLD 127
|
||||||
|
|
||||||
|
#include "glib.h"
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
DEPTH_FIRST,
|
||||||
|
PRIMS_ALGORITHM
|
||||||
|
} MazeAlgoType;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
gint width;
|
gint width;
|
||||||
gint height;
|
gint height;
|
||||||
gint seed;
|
guint seed;
|
||||||
gboolean tile;
|
gboolean tile;
|
||||||
gint multiple;
|
gint multiple;
|
||||||
gint offset;
|
gint offset;
|
||||||
|
MazeAlgoType algorithm;
|
||||||
/* Interface options. */
|
/* Interface options. */
|
||||||
gboolean timeseed;
|
gboolean timeseed;
|
||||||
} MazeValues;
|
} MazeValues;
|
||||||
|
|
||||||
|
enum CellTypes {
|
||||||
|
OUT,
|
||||||
|
IN,
|
||||||
|
FRONTIER,
|
||||||
|
MASKED
|
||||||
|
};
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* maze_face.c, version 0.6.2, March 7, 1998.
|
/* maze_face.c
|
||||||
* User interface for plug-in-maze.
|
* User interface for plug-in-maze.
|
||||||
*
|
*
|
||||||
* Implemented as a GIMP 0.99 Plugin by
|
* Implemented as a GIMP 0.99 Plugin by
|
||||||
|
@ -19,7 +19,7 @@
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, write to the Free Software
|
||||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -29,7 +29,6 @@
|
||||||
#endif /* MAZE_DEBUG */
|
#endif /* MAZE_DEBUG */
|
||||||
|
|
||||||
#include "maze.h"
|
#include "maze.h"
|
||||||
|
|
||||||
#include "libgimp/gimp.h"
|
#include "libgimp/gimp.h"
|
||||||
#include "libgimp/gimpui.h"
|
#include "libgimp/gimpui.h"
|
||||||
|
|
||||||
|
@ -113,6 +112,8 @@ static void div_button_callback (GtkWidget *button, GtkWidget *entry);
|
||||||
static void div_entry_callback (GtkWidget *entry, GtkWidget *friend);
|
static void div_entry_callback (GtkWidget *entry, GtkWidget *friend);
|
||||||
static void height_width_callback (gint width, GtkWidget **div_entry);
|
static void height_width_callback (gint width, GtkWidget **div_entry);
|
||||||
static void toggle_callback (GtkWidget *widget, gboolean *data);
|
static void toggle_callback (GtkWidget *widget, gboolean *data);
|
||||||
|
static void alg_radio_callback (GtkWidget *widget, gpointer data);
|
||||||
|
|
||||||
static GtkWidget* divbox_new (guint *max,
|
static GtkWidget* divbox_new (guint *max,
|
||||||
GtkWidget *friend,
|
GtkWidget *friend,
|
||||||
GtkWidget **div_entry);
|
GtkWidget **div_entry);
|
||||||
|
@ -125,7 +126,7 @@ static void div_buttonr_callback (GtkObject *object);
|
||||||
/* entscale stuff begin */
|
/* entscale stuff begin */
|
||||||
static GtkWidget* entscale_int_new ( GtkWidget *table, gint x, gint y,
|
static GtkWidget* entscale_int_new ( GtkWidget *table, gint x, gint y,
|
||||||
gchar *caption, gint *intvar,
|
gchar *caption, gint *intvar,
|
||||||
gint min, gint max, gint constraint,
|
gint min, gint max, gboolean constraint,
|
||||||
EntscaleIntCallbackFunc callback,
|
EntscaleIntCallbackFunc callback,
|
||||||
gpointer data );
|
gpointer data );
|
||||||
|
|
||||||
|
@ -168,6 +169,8 @@ gint maze_dialog()
|
||||||
GtkWidget *div_x_hbox, *div_y_hbox;
|
GtkWidget *div_x_hbox, *div_y_hbox;
|
||||||
GtkWidget *div_x_label, *div_y_label, *div_x_entry, *div_y_entry;
|
GtkWidget *div_x_label, *div_y_label, *div_x_entry, *div_y_entry;
|
||||||
|
|
||||||
|
GtkWidget *alg_box, *alg_button;
|
||||||
|
|
||||||
gchar **argv;
|
gchar **argv;
|
||||||
gint argc;
|
gint argc;
|
||||||
gchar buffer[32];
|
gchar buffer[32];
|
||||||
|
@ -239,7 +242,6 @@ gint maze_dialog()
|
||||||
GTK_FRAME(msg_frame)->label) + 7);
|
GTK_FRAME(msg_frame)->label) + 7);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* Set up Options page */
|
/* Set up Options page */
|
||||||
frame = gtk_frame_new ("Maze Options");
|
frame = gtk_frame_new ("Maze Options");
|
||||||
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
|
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
|
||||||
|
@ -321,8 +323,6 @@ gint maze_dialog()
|
||||||
|
|
||||||
gtk_widget_show (div_y_hbox);
|
gtk_widget_show (div_y_hbox);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Add Options page to notebook */
|
/* Add Options page to notebook */
|
||||||
gtk_widget_show (frame);
|
gtk_widget_show (frame);
|
||||||
gtk_widget_show (table);
|
gtk_widget_show (table);
|
||||||
|
@ -331,11 +331,10 @@ gint maze_dialog()
|
||||||
gtk_label_new ("Options"));
|
gtk_label_new ("Options"));
|
||||||
|
|
||||||
/* Set up other page */
|
/* Set up other page */
|
||||||
frame = gtk_frame_new ("Don't change these");
|
frame = gtk_frame_new ("At Your Own Risk");
|
||||||
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
|
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
|
||||||
gtk_container_border_width (GTK_CONTAINER (frame), 10);
|
gtk_container_border_width (GTK_CONTAINER (frame), 10);
|
||||||
/* gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dlg)->vbox), frame, TRUE, TRUE, 0); */
|
table = gtk_table_new (4, 2, FALSE);
|
||||||
table = gtk_table_new (3, 2, FALSE);
|
|
||||||
gtk_container_border_width (GTK_CONTAINER (table), 10);
|
gtk_container_border_width (GTK_CONTAINER (table), 10);
|
||||||
gtk_container_add (GTK_CONTAINER (frame), table);
|
gtk_container_add (GTK_CONTAINER (frame), table);
|
||||||
|
|
||||||
|
@ -399,6 +398,35 @@ gint maze_dialog()
|
||||||
gtk_widget_show (time_button);
|
gtk_widget_show (time_button);
|
||||||
gtk_widget_show (seed_hbox);
|
gtk_widget_show (seed_hbox);
|
||||||
|
|
||||||
|
label = gtk_label_new("Algorithm");
|
||||||
|
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
|
||||||
|
gtk_table_attach (GTK_TABLE (table), label, 0, 1, 3, 4,
|
||||||
|
GTK_FILL, 0, 5, 5);
|
||||||
|
gtk_widget_show (label);
|
||||||
|
|
||||||
|
alg_box=gtk_vbox_new(FALSE, 5);
|
||||||
|
gtk_table_attach (GTK_TABLE (table), alg_box, 1, 2, 3, 4,
|
||||||
|
GTK_FILL, 0, 5, 5);
|
||||||
|
gtk_widget_show (alg_box);
|
||||||
|
|
||||||
|
alg_button=gtk_radio_button_new_with_label (NULL,"Depth First");
|
||||||
|
gtk_signal_connect(GTK_OBJECT(alg_button),"toggled",
|
||||||
|
GTK_SIGNAL_FUNC(alg_radio_callback), (gpointer)DEPTH_FIRST);
|
||||||
|
if(mvals.algorithm==DEPTH_FIRST)
|
||||||
|
gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(alg_button), TRUE);
|
||||||
|
gtk_container_add(GTK_CONTAINER(alg_box),alg_button);
|
||||||
|
gtk_widget_show(alg_button);
|
||||||
|
|
||||||
|
alg_button=gtk_radio_button_new_with_label (gtk_radio_button_group(
|
||||||
|
GTK_RADIO_BUTTON(alg_button)), "Prim's Algorithm");
|
||||||
|
gtk_signal_connect(GTK_OBJECT(alg_button),"toggled",
|
||||||
|
GTK_SIGNAL_FUNC(alg_radio_callback), (gpointer)PRIMS_ALGORITHM);
|
||||||
|
if(mvals.algorithm==PRIMS_ALGORITHM)
|
||||||
|
gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(alg_button), TRUE);
|
||||||
|
|
||||||
|
gtk_container_add(GTK_CONTAINER(alg_box),alg_button);
|
||||||
|
gtk_widget_show(alg_button);
|
||||||
|
|
||||||
/* Add Advanced page to notebook */
|
/* Add Advanced page to notebook */
|
||||||
gtk_widget_show (frame);
|
gtk_widget_show (frame);
|
||||||
gtk_widget_show (table);
|
gtk_widget_show (table);
|
||||||
|
@ -633,20 +661,24 @@ maze_close_callback (GtkWidget *widget,
|
||||||
static void
|
static void
|
||||||
maze_help (GtkWidget *widget, gpointer foo)
|
maze_help (GtkWidget *widget, gpointer foo)
|
||||||
{
|
{
|
||||||
void *bar=(void *)NULL;
|
char *proc_blurb, *proc_help, *proc_author, *proc_copyright, *proc_date;
|
||||||
|
int proc_type, nparams, nreturn_vals;
|
||||||
|
GParamDef *params, *return_vals;
|
||||||
gint baz;
|
gint baz;
|
||||||
|
|
||||||
if (gimp_query_procedure("extension_web_browser",
|
if (gimp_query_procedure("extension_web_browser",
|
||||||
bar, bar, bar, bar, bar,
|
&proc_blurb, &proc_help,
|
||||||
bar, bar, bar, bar, bar)) {
|
&proc_author, &proc_copyright, &proc_date,
|
||||||
maze_msg("Opening " MAZE_URL);
|
&proc_type, &nparams, &nreturn_vals,
|
||||||
gimp_run_procedure("extension_web_browser", &baz,
|
¶ms, &return_vals)) {
|
||||||
PARAM_INT32, RUN_NONINTERACTIVE,
|
maze_msg("Opening " MAZE_URL);
|
||||||
PARAM_STRING, MAZE_URL,
|
gimp_run_procedure("extension_web_browser", &baz,
|
||||||
PARAM_INT32, HELP_OPENS_NEW_WINDOW,
|
PARAM_INT32, RUN_NONINTERACTIVE,
|
||||||
PARAM_END);
|
PARAM_STRING, MAZE_URL,
|
||||||
|
PARAM_INT32, HELP_OPENS_NEW_WINDOW,
|
||||||
|
PARAM_END);
|
||||||
} else {
|
} else {
|
||||||
maze_msg("See " MAZE_URL);
|
maze_msg("See " MAZE_URL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -681,6 +713,12 @@ toggle_callback (GtkWidget *widget, gboolean *data)
|
||||||
*data = GTK_TOGGLE_BUTTON (widget)->active;
|
*data = GTK_TOGGLE_BUTTON (widget)->active;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
alg_radio_callback (GtkWidget *widget, gpointer data)
|
||||||
|
{
|
||||||
|
mvals.algorithm=(MazeAlgoType)data;
|
||||||
|
}
|
||||||
|
|
||||||
/* ==================================================================== */
|
/* ==================================================================== */
|
||||||
/* As found in pixelize.c,
|
/* As found in pixelize.c,
|
||||||
* hacked to return a pointer to the entry widget. */
|
* hacked to return a pointer to the entry widget. */
|
||||||
|
@ -710,7 +748,7 @@ toggle_callback (GtkWidget *widget, gboolean *data)
|
||||||
static GtkWidget*
|
static GtkWidget*
|
||||||
entscale_int_new ( GtkWidget *table, gint x, gint y,
|
entscale_int_new ( GtkWidget *table, gint x, gint y,
|
||||||
gchar *caption, gint *intvar,
|
gchar *caption, gint *intvar,
|
||||||
gint min, gint max, gint constraint,
|
gint min, gint max, gboolean constraint,
|
||||||
EntscaleIntCallbackFunc callback,
|
EntscaleIntCallbackFunc callback,
|
||||||
gpointer call_data)
|
gpointer call_data)
|
||||||
{
|
{
|
||||||
|
|
|
@ -92,7 +92,7 @@
|
||||||
(gimp-palette-set-foreground '(14 14 14))))
|
(gimp-palette-set-foreground '(14 14 14))))
|
||||||
|
|
||||||
(gimp-selection-load image active-selection)
|
(gimp-selection-load image active-selection)
|
||||||
(plug-in-maze 1 image active-layer 5 5 TRUE seed 57 1)
|
(plug-in-maze 1 image active-layer 5 5 TRUE 0 seed 57 1)
|
||||||
(plug-in-oilify 1 image active-layer mask-size 0)
|
(plug-in-oilify 1 image active-layer mask-size 0)
|
||||||
(plug-in-edge 1 image active-layer 2 1)
|
(plug-in-edge 1 image active-layer 2 1)
|
||||||
(gimp-desaturate image active-layer)
|
(gimp-desaturate image active-layer)
|
||||||
|
|
Loading…
Reference in New Issue