summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin Chabowski <der.pc222@googlemail.com>2010-07-28 23:03:16 +0200
committerKevin Chabowski <der.pc222@googlemail.com>2010-07-28 23:03:16 +0200
commit054a617a9375b835492368c3773315b09d3851ce (patch)
tree231d5e4a57e994e3cc3c0b005fea6fe2a4a9fcc9
downloadAnother-mandelbrot-viewer-054a617a9375b835492368c3773315b09d3851ce.tar.gz
Another-mandelbrot-viewer-054a617a9375b835492368c3773315b09d3851ce.tar.bz2
Another-mandelbrot-viewer-054a617a9375b835492368c3773315b09d3851ce.zip
Initial commit for mandelbrot.
-rwxr-xr-x.gitignore2
-rw-r--r--COMPILING23
-rw-r--r--LICENSE18
-rw-r--r--Makefile20
-rw-r--r--common_types.h40
-rw-r--r--cursor.tgabin0 -> 2544 bytes
-rw-r--r--graymap.c106
-rw-r--r--graymap.h159
-rw-r--r--graymap_alleg.c33
-rw-r--r--graymap_alleg.h37
-rw-r--r--mandelbrot.c460
-rw-r--r--mandelbrot.cfg7
-rw-r--r--paledit.c363
-rw-r--r--paledit.h29
-rw-r--r--pals/LSD.palbin0 -> 848 bytes
-rw-r--r--pals/cool_blue.palbin0 -> 248 bytes
-rw-r--r--pals/deepblue.palbin0 -> 368 bytes
-rw-r--r--pals/default.palbin0 -> 248 bytes
-rw-r--r--pals/fire.palbin0 -> 288 bytes
-rw-r--r--pals/ice.palbin0 -> 288 bytes
-rw-r--r--pals/matrix.palbin0 -> 248 bytes
-rw-r--r--pals/simple_gray.palbin0 -> 88 bytes
-rw-r--r--pals/snow.palbin0 -> 128 bytes
-rw-r--r--pals/steel_blue.palbin0 -> 208 bytes
-rw-r--r--pals/toxic.palbin0 -> 288 bytes
-rw-r--r--pals/ugly.palbin0 -> 288 bytes
26 files changed, 1297 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100755
index 0000000..d6ff91a
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+*~
+*.o
diff --git a/COMPILING b/COMPILING
new file mode 100644
index 0000000..df10f1e
--- /dev/null
+++ b/COMPILING
@@ -0,0 +1,23 @@
+Compiling mandelbrot on Linux:
+ You will need the devel files for the allegro graphics library. You
+ should be able to find them via yum/zypper/apt-get or whatever the
+ package manager of your distro is called. Of course you will also need
+ GCC and the make command.
+ If you have everything,just type "make" into a console and everything
+ should compile in some seconds.
+
+Compiling mandelbrot on Windows:
+ You need a C compiler. I prefer mingw32 (wxDevC++), but anyone should
+ do. Then you have to get Allegro 4.2 for this compiler. If you are using
+ (wx)DevC++, you can download a devpak file from devpaks.org. For other
+ compilers: Google is your friend.
+ Then you can compile mandelbrot (do not forget do tell the compiler /
+ linker to include the allegro library!).
+ NOTE: I do not know any compiler for Windows, which supports OpenMP, but
+ perhaps a new MinGW version (not that old one from DevC++) or
+ Microsoft's VisualC++ do, but I do not know. If your compiler does not
+ like the "#pragma omp" lines, you have to remove them from the sources.
+
+Compiling mandelbrot on other Operating systems:
+ I don't have any clue. You are on your own. Good luck!
+
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..94ecb68
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,18 @@
+Copyright (c) 2010 Kevin Chabowski(kevin@kch42.de)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..cc1fdb3
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,20 @@
+CC = gcc
+CC_PARAMS = -O3 -Wall -Werror -fopenmp -c
+C_SOURCES = graymap.c graymap_alleg.c paledit.c mandelbrot.c
+OBJ = $(C_SOURCES:%.c=%.o)
+LIBS = `allegro-config --libs` -lm -lgomp
+
+mandelbrot: $(OBJ)
+ $(CC) $(LIBS) -o mandelbrot $(OBJ)
+
+%.o:%.c
+ $(CC) $(CC_PARAMS) -o $@ $<
+
+doc:
+ if [ ! -d doc ]; then mkdir doc; fi
+ doxygen Doxyfile
+
+clean:
+ rm -r doc
+ rm $(OBJ)
+ rm mandelbrot
diff --git a/common_types.h b/common_types.h
new file mode 100644
index 0000000..12bd174
--- /dev/null
+++ b/common_types.h
@@ -0,0 +1,40 @@
+#ifndef _common_types_h_
+#define _common_types_h_
+
+/**
+ * @file common_types.h
+ *
+ * This header file contains some typedefs to make programming easier.
+ */
+
+typedef unsigned char uint_8; /**< Unsigned 8-bit variable.*/
+typedef unsigned short int uint_16; /**< Unsigned 16-bit variable.*/
+typedef unsigned int uint_32; /**< Unsigned 32-bit variable.*/
+typedef unsigned long long int uint_64; /**< Unsigned 64-bit variable.*/
+
+typedef char int_8; /**< Signed 8-bit variable.*/
+typedef short int int_16; /**< Signed 16-bit variable.*/
+typedef int int_32; /**< Signed 32-bit variable.*/
+typedef long long int int_64; /**< Signed 64-bit variable.*/
+
+#ifndef BOOL
+/**
+ * Macro to define a boolean type in C.
+ */
+#define BOOL uint_8
+#endif
+#ifndef FALSE
+/**
+ * Macro for the boolean value false.
+ */
+#define FALSE 0
+#endif
+#ifndef TRUE
+/**
+ * Macro for the boolean value true.
+ */
+#define TRUE 1
+
+#endif
+
+#endif
diff --git a/cursor.tga b/cursor.tga
new file mode 100644
index 0000000..052cde3
--- /dev/null
+++ b/cursor.tga
Binary files differ
diff --git a/graymap.c b/graymap.c
new file mode 100644
index 0000000..c44347c
--- /dev/null
+++ b/graymap.c
@@ -0,0 +1,106 @@
+#include "graymap.h"
+#include "common_types.h"
+#include <stdlib.h>
+
+graymap_t create_graymap(int w, int h)
+{
+ graymap_t rv;
+ rv.w = -1;
+ rv.h = -1;
+ rv.data = (double*) malloc(sizeof(double) * w * h);
+ if(rv.data == NULL)
+ return rv;
+ rv.w = w;
+ rv.h = h;
+ return rv;
+}
+
+void destroy_graymap(graymap_t* gm)
+{
+ free(gm->data);
+ gm->w = gm->h = -1;
+}
+
+void clear_graymap(graymap_t* gm, double grayval)
+{
+ int limit = gm->w * gm->h;
+ int i;
+ double* data_p = gm->data;
+ for(i = 0; i < limit; ++i, ++data_p)
+ (*data_p) = grayval;
+}
+
+void set_pix_graymap(graymap_t* gm, int x, int y, double gray)
+{
+ GM_PIX((*gm),x,y) = gray;
+}
+
+double get_pix_graymap(graymap_t* gm, int x, int y)
+{
+ return GM_PIX(*gm,x,y);
+}
+
+void blit_graymaps(graymap_t* src, graymap_t* dst, int src_x, int src_y,
+ int dst_x, int dst_y, int w, int h)
+{
+ if(src_x + w >= src->w)
+ w = src->w - src_x;
+ if(src_y + h >= src->h)
+ h = src->h - src_y;
+ if(dst_x + w >= dst->w)
+ w = dst->w - dst_x;
+ if(dst_y + h >= dst->h)
+ h = dst->h - dst_y;
+ int x,y;
+ for(y = 0; y < h; ++y)
+ for(x = 0; x < w; ++x)
+ GM_PIX(*dst,dst_x+x, dst_y+y) = GM_PIX(*src, src_x+x, src_y+y);
+}
+
+color_t get_palette_color(double grayval, color_t* pal_cols, double* pal_grays,
+ int pal_n)
+{
+ color_t rv;
+ rv.r = rv.g = rv.b = rv.a = .0;
+ int index;
+ double factor1, factor2;
+ BOOL found = FALSE;
+ /* find the index number */
+ for(index = 0; index < ( pal_n - 1 ); ++index)
+ {
+ if((grayval >= pal_grays[index]) && (grayval <= pal_grays[index+1]))
+ {
+ found = TRUE;
+ break;
+ }
+ }
+
+ if(!found)
+ return rv;
+
+ /* Calculate factors */
+ factor1 = (pal_grays[index+1] - grayval ) /
+ ( pal_grays[index+1] -pal_grays[index] );
+ factor2 = 1.0 - factor1;
+
+ /* Calculate color */
+ rv.r = ( pal_cols[index].r * factor1 ) +
+ ( pal_cols[index+1].r * factor2 );
+ rv.g = ( pal_cols[index].g * factor1 ) +
+ ( pal_cols[index+1].g * factor2 );
+ rv.b = ( pal_cols[index].b * factor1 ) +
+ ( pal_cols[index+1].b * factor2 );
+ rv.a = ( pal_cols[index].a * factor1 ) +
+ ( pal_cols[index+1].a * factor2 );
+ return rv;
+}
+
+color_t mkcol(double r, double g, double b, double a)
+{
+ color_t rv;
+ rv.r = r;
+ rv.g = g;
+ rv.b = b;
+ rv.a = a;
+ return rv;
+}
diff --git a/graymap.h b/graymap.h
new file mode 100644
index 0000000..fd3a0ca
--- /dev/null
+++ b/graymap.h
@@ -0,0 +1,159 @@
+#ifndef _graymap_h_
+#define _graymap_h_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+/**
+ * @file graymap.h
+ *
+ * This header files contains thedefinition of data types and functions to deal
+ * with graymap images.
+ */
+
+/* ******************************** MACROS ************************************/
+/**
+ * This macro makes accessing graymap pixels easier.
+ *
+ * If you use pointers to graymaps, you have to call this macro like this:
+ * GM_PIX(*my_graymap, x,y) = foo;
+ *
+ * @param gm the graymap
+ * @param x X coordinate
+ * @param y Y coordinate
+ * @return The pixel of the graymap which can be used like a variable.
+ * @see set_pix_graymap()
+ * @see get_pix_graymap()
+ * @see color_t
+ */
+#define GM_PIX(gm,x,y) (gm).data[((y)*(gm).w)+(x)]
+
+/* ****************************** DATA TYPES **********************************/
+/**
+ * This is a data type to hold RGBA color values.
+ *
+ * All values are stored as floating point numbers.
+ */
+typedef struct
+{
+ double r; /**< Red color component. */
+ double g; /**< Green color component. */
+ double b; /**< Blue color component. */
+ double a; /**< Alpha value component. */
+} color_t;
+
+/**
+ * The data structure for graymaps.
+ */
+typedef struct
+{
+ int w; /**< Width of the image */
+ int h; /**< Height of the image. */
+ double* data; /**< Image data. */
+} graymap_t;
+
+/* ******************************* FUNCTIONS **********************************/
+/**
+ * Creating a graymap.
+ *
+ * @param w the width of the new image.
+ * @param h the height of the new image.
+ * @return a new graymap image.
+ * @see destroy_graymap()
+ */
+extern graymap_t create_graymap(int w, int h);
+
+/**
+ * Destroying a graymap.
+ *
+ * This will free the memory of the image data and set width/height to -1.
+ *
+ * @param gm Pointer to the graymap.
+ * @see create_graymap()
+ */
+extern void destroy_graymap(graymap_t* gm);
+
+/**
+ * Clear the graymap to a grayscale value.
+ *
+ * This will override all pixels in the graymap to the specified greyscale
+ * value.
+ *
+ * @param gm Pointer to the graymap.
+ * @param grayval Grayscale value.
+ */
+extern void clear_graymap(graymap_t* gm, double grayval);
+
+/**
+ * Set a pixel in a graymap.
+ *
+ * @param gm Pointer to the graymap
+ * @param x X coordinate
+ * @param y Y coordinate
+ * @param gray grayscale value of the pixel
+ * @see get_pix_graymap()
+ * @see GM_PIX()
+ */
+extern void set_pix_graymap(graymap_t* gm, int x, int y, double gray);
+
+/**
+ * Get a pixel from a graymap.
+ *
+ * @param gm Pointer to the graymap
+ * @param x X coordinate
+ * @param y Y coordinate
+ * @return grayscale value of the pixel
+ * @see set_pix_graymap()
+ * @see GM_PIX()
+ */
+extern double get_pix_graymap(graymap_t* gm, int x, int y);
+
+/**
+ * Blitting (copying) image data from one graymap to another.
+ *
+ * @param src pointer to the source graymap
+ * @param dst pointer to the destination graymap
+ * @param src_x Blitting start X coordinate in the source graymap
+ * @param src_y Blitting start Y coordinate in the source graymap
+ * @param dst_x Blitting start X coordinate in the destination graymap
+ * @param dst_y Blitting start Y coordinate in the destination graymap
+ * @param w Width of the blitting rectangle.
+ * @param h Height of the blitting rectangle.
+ */
+extern void blit_graymaps(graymap_t* src, graymap_t* dst, int src_x, int src_y,
+ int dst_x, int dst_y, int w, int h);
+
+/**
+ * Calculate a color from a palette and a grayscale value.
+ *
+ * A palette is represented by two arrays. One array contains colors, the other
+ * one contains the corresponding grayscale values. This palette now represents
+ * a color gradient. The color which fits to the grayscale value will be
+ * returned.
+ *
+ * @param grayval The grayscale value.
+ * @param pal_cols Array of colors.
+ * @param pal_grays Array of grayscale values
+ * @param pal_n length of the arrays.
+ * @return The calculated color.
+ */
+extern color_t get_palette_color(double grayval, color_t* pal_cols,
+ double* pal_grays, int pal_n);
+
+/**
+ * Create a color_t object.
+ *
+ * @param r The red color component.
+ * @param g The green color component.
+ * @param b The blue color component.
+ * @param a The Alpha value.
+ * @return the color_t object.
+ * @see color_t
+ */
+extern color_t mkcol(double r, double g, double b, double a);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/graymap_alleg.c b/graymap_alleg.c
new file mode 100644
index 0000000..6380436
--- /dev/null
+++ b/graymap_alleg.c
@@ -0,0 +1,33 @@
+#include "common_types.h"
+#include "graymap_alleg.h"
+#include "graymap.h"
+#include <math.h>
+#include <allegro.h>
+
+void render_graymap_alleg(BITMAP* canvas, graymap_t* gm, color_t* pal_cols,
+ double* pal_grays, int pal_n)
+{
+ int limit_w = gm->w;
+ int limit_h = gm->h;
+ if(limit_w > canvas->w)
+ limit_w = canvas->w;
+ if(limit_h > canvas->h)
+ limit_h = canvas->h;
+
+ color_t col;
+
+ int x,y,i;
+ uint_8 r,g,b,a;
+ for(y = 0, i = 0; y < limit_h; ++y)
+ {
+ for(x = 0; x < limit_w; ++x, ++i)
+ {
+ col = get_palette_color(gm->data[i], pal_cols, pal_grays, pal_n);
+ r = (uint_8) round(col.r * 255.0);
+ g = (uint_8) round(col.g * 255.0);
+ b = (uint_8) round(col.b * 255.0);
+ a = (uint_8) round(col.a * 255.0);
+ putpixel(canvas, x,y,makeacol(r,g,b,a));
+ }
+ }
+}
diff --git a/graymap_alleg.h b/graymap_alleg.h
new file mode 100644
index 0000000..87a35e7
--- /dev/null
+++ b/graymap_alleg.h
@@ -0,0 +1,37 @@
+#ifndef _graymap_alleg_h_
+#define _graymap_alleg_h_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @file graymap_alleg.h
+ *
+ * This header file conatins a function to render graymaps to allegro 4 bitmaps.
+ */
+#include <allegro.h>
+#include "graymap.h"
+
+/**
+ * Render a graymap to a allegro 4 bitmap.
+ *
+ * A palette is represented by two arrays. One array contains colors, the other
+ * one contains the corresponding grayscale values. This palette now represents
+ * a color gradient. The color which fits to the grayscale value will be
+ * returned.
+ *
+ * @param canvas The allegro 4 bitmap.
+ * @param gm The graymap.
+ * @param pal_cols Array of colors.
+ * @param pal_grays Array of grayscale values
+ * @param pal_n length of the arrays.
+ */
+extern void render_graymap_alleg(BITMAP* canvas, graymap_t* gm,
+ color_t* pal_cols, double* pal_grays, int pal_n);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/mandelbrot.c b/mandelbrot.c
new file mode 100644
index 0000000..e71c5bc
--- /dev/null
+++ b/mandelbrot.c
@@ -0,0 +1,460 @@
+#include "common_types.h"
+#include "graymap.h"
+#include "graymap_alleg.h"
+#include "paledit.h"
+#include <allegro.h>
+#include <math.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <semaphore.h>
+
+void blur(BITMAP* src, BITMAP* dst)
+{
+ int lim_w = src->w > dst->w ? src->w : dst->w;
+ int lim_h = src->h > dst->h ? src->h : dst->h;
+ int x,y;
+
+ #pragma omp parallel
+ {
+ #pragma omp for collapse(2)
+ for(y = 1; y < lim_h-1; ++y)
+ for(x = 1; x < lim_w-1; ++x)
+ {
+ int r,g,b,xr,yr,n;
+ r = g = b = 0;
+ n = 0;
+ for(xr = x-1; xr < x+2; ++xr)
+ {
+ for(yr = y-1; yr < y+2; ++yr)
+ {
+ if((xr >= 0) && (xr < lim_w) && (yr >= 0) &&
+ (yr < lim_h))
+ {
+ ++n;
+ r += getr(getpixel(src,xr,yr));
+ g += getg(getpixel(src,xr,yr));
+ b += getb(getpixel(src,xr,yr));
+ }
+ }
+ }
+ if(n != 0)
+ {
+ r /= n;
+ g /= n;
+ b /= n;
+ }
+ putpixel(dst,x,y,makeacol(r,g,b,255));
+ }
+ }
+}
+
+double mandel_iter(double cx, double cy, double bailout, double max_iter)
+{
+ double x, y, xt;
+ int iter;
+ x = y = 0;
+ iter = 0;
+ while((x*x+y*y < bailout*bailout) && (iter < max_iter))
+ {
+ xt = x*x-y*y+cx;
+ y = 2.0*x*y+cy;
+ x = xt;
+ iter++;
+ }
+ return (double) iter + (double) ((log(2*log(bailout)) - log(log(x*x+y*y))) / log(2));
+}
+
+void mandelbrot(graymap_t* gm, double x1,double y1, double x2, double y2,
+ int max_iter)
+{
+ double bailout = 1000.0;
+ double stepx = (x2-x1)/gm->w;
+ double stepy = (y2-y1)/gm->h;
+
+ int px, py;
+
+ #pragma omp parallel
+ {
+ #pragma omp for collapse(2)
+ for(px = 0; px < gm->w ;px++)
+ for(py = 0; py < gm->h; py++)
+ GM_PIX(*gm,px,py) = mandel_iter(x1+(px*stepx),y1+(py*stepy),
+ bailout, max_iter);
+ }
+ int i;
+ static double max_gray = 0.0;
+ if(max_gray == 0.0)
+ for(i = 0; i < (gm->w * gm->h); ++i)
+ max_gray = gm->data[i] > max_gray ? gm->data[i] : max_gray;
+ #pragma omp parallel
+ {
+ #pragma omp for
+ for(i = 0; i < (gm->w * gm->h); ++i)
+ gm->data[i] /= max_gray;
+ }
+}
+
+double dabs(double in)
+{
+ return in < 0 ? in * -1.0 : in;
+}
+
+void fix_rect(double* x1, double* y1, double* x2, double* y2, double asp_ratio)
+{
+ double swap = .0;
+ if(*x1 > *x2)
+ {
+ swap = *x1;
+ *x1 = *x2;
+ *x2 = swap;
+ }
+ if(*y1 > *y2)
+ {
+ swap = *y1;
+ *y1 = *y2;
+ *y2 = swap;
+ }
+
+ double dx = *x2 - *x1;
+ double dy = *y2 - *y1;
+ double new_dx;
+ if(dx/dy != asp_ratio)
+ {
+ new_dx = dy * asp_ratio;
+ *x1 += (dx - new_dx) / 2;
+ *x2 -= (dx - new_dx) / 2;
+ }
+}
+
+void introtext(BITMAP* canvas)
+{
+ textprintf_centre_ex(canvas, font, (int) canvas->w/2, 10, 0xffffffff, -1,
+ "simple mandelbrot viewer by");
+ textprintf_centre_ex(canvas, font, (int) canvas->w/2, 22, 0xffffffff, -1,
+ "Kevin Chabowski (kevin@kch42.de)");
+ textprintf_centre_ex(canvas, font, (int) canvas->w/2, 34, 0xffffffff, -1,
+ "v 0.5");
+ textprintf_centre_ex(canvas, font, (int) canvas->w/2, 46, 0xffffffff, -1,
+ "This program may be redistributed under the conditions");
+ textprintf_centre_ex(canvas, font, (int) canvas->w/2, 58, 0xffffffff, -1,
+ "of the MIT-License. See LICENSE for more details.");
+
+ textprintf_centre_ex(canvas, font, (int) canvas->w/2, 82, 0xffffffff, -1,
+ "Instructions:");
+ textprintf_centre_ex(canvas, font, (int) canvas->w/2, 94, 0xffffffff, -1,
+ "Draw a border with the mouse to zoom in.");
+ textprintf_centre_ex(canvas, font, (int) canvas->w/2, 106, 0xffffffff, -1,
+ "Hold right mouse button and move mouse wheel to zoom in/out.");
+ textprintf_centre_ex(canvas, font, (int) canvas->w/2, 118, 0xffffffff, -1,
+ "Drag image with middle mouse button to move section.");
+ textprintf_centre_ex(canvas, font, (int) canvas->w/2, 130, 0xffffffff, -1,
+ "[P] opens the palette editor.");
+ textprintf_centre_ex(canvas, font, (int) canvas->w/2, 142, 0xffffffff, -1,
+ "[ESC] to quit.");
+
+ textprintf_centre_ex(canvas, font, (int) canvas->w/2, 166, 0xffffffff, -1,
+ "Click to start.");
+}
+
+/* Speed control thread */
+sem_t timer_sem;
+BOOL speed_control;
+void ticker()
+{
+ if(speed_control)
+ sem_post(&timer_sem);
+}
+END_OF_FUNCTION(ticker)
+
+
+int main()
+{
+ /* init allegro */
+ allegro_init();
+ install_keyboard();
+ install_mouse();
+ install_timer();
+ set_color_depth(32);
+
+ set_config_file("mandelbrot.cfg");
+ int scr_return;
+ if(get_config_int("mandelbrot", "fullscreen", 0) != 0)
+ scr_return = set_gfx_mode(GFX_AUTODETECT,
+ get_config_int("mandelbrot", "width", 800),
+ get_config_int("mandelbrot", "height", 600), 0, 0);
+ else
+ scr_return = set_gfx_mode(GFX_AUTODETECT_WINDOWED,
+ get_config_int("mandelbrot", "width", 800),
+ get_config_int("mandelbrot", "height", 600), 0, 0);
+ if(scr_return != 0)
+ {
+ set_gfx_mode(GFX_TEXT, 0, 0, 0, 0);
+ allegro_message("Unable to set any graphic mode\n%s\n",
+ allegro_error);
+ return 1;
+ }
+ set_alpha_blender();
+ drawing_mode(DRAW_MODE_TRANS, NULL, 0, 0);
+ BITMAP* cursor;
+ BITMAP* checkered;
+ BITMAP* buffer;
+ BITMAP* blurbuf;
+ BITMAP* mandel;
+ cursor = create_bitmap(21, 21);
+ checkered = create_bitmap(SCREEN_W, SCREEN_H);
+ buffer = create_bitmap(SCREEN_W, SCREEN_H);
+ blurbuf = create_bitmap(SCREEN_W, SCREEN_H);
+ mandel = create_bitmap(SCREEN_W, SCREEN_H);
+
+ /* Prepare cursor */
+ cursor = load_tga("cursor.tga", NULL);
+
+ /* Prepare checkered background pattern */
+ int x,y;
+ long color = 0;
+ for(y = 0; y < (int) floor(SCREEN_H / 20); ++y)
+ {
+ for(x = 0; x < (int) floor(SCREEN_W / 20); ++x)
+ {
+ if(x%2)
+ color = (y%2) ? 0xff707070 : 0xff909090;
+ else
+ color = (y%2) ? 0xff909090 : 0xff707070;
+ rectfill(checkered, x*20, y*20, (x+1)*20, (y+1)*20, color);
+ }
+ }
+
+ double x1,x2,y1,y2, dx, dy;
+ double dppx = 0;
+ int max_iter = get_config_int("mandelbrot", "max_iter", 250);
+ x1 = -2.5;
+ y1 = -1.5;
+ x2 = 1.0;
+ y2 = 1.5;
+
+ BOOL update_fract = TRUE;
+ BOOL screen_update = FALSE;
+ BOOL render_graymap = FALSE;
+
+ int r_x1 = -1;
+ int r_y1 = 0;
+ int r_x2 = 0;
+ int r_y2 = 0;
+ BOOL old_mousebtn = FALSE;
+ BOOL new_mousebtn = FALSE;
+ int mmx, mmy;
+
+ int draw_offset_x = 0;
+ int draw_offset_y = 0;
+ double draw_zoom = 1.0;
+
+ BOOL drag = FALSE;
+
+ graymap_t my_map = create_graymap(SCREEN_W, SCREEN_H);
+
+ /* GUI setup */
+ gui_fg_color = 0xff000000;
+ gui_bg_color = 0xffffffff;
+
+ init_paledit(SCREEN_W, SCREEN_H);
+ paledit_data.pal_cols[0] = mkcol(.0, .0, .0, 1.0);
+ paledit_data.pal_cols[1] = mkcol(.75, .0, .0, 1.0);
+ paledit_data.pal_cols[2] = mkcol(1.0, 1.0, .0, 1.0);
+ paledit_data.pal_cols[3] = mkcol(.0, 0.5, 1.0, 1.0);
+ paledit_data.pal_cols[4] = mkcol(1.0, 1.0, 1.0, 1.0);
+ paledit_data.pal_cols[5] = mkcol(.0, .0, .0, 1.0);
+ paledit_data.pal_grays[0] = 0.0;
+ paledit_data.pal_grays[1] = .05;
+ paledit_data.pal_grays[2] = .25;
+ paledit_data.pal_grays[3] = .5;
+ paledit_data.pal_grays[4] = 0.9999;
+ paledit_data.pal_grays[5] = 1.0;
+ paledit_data.n = 6;
+ load_palette_cc(get_config_string("mandelbrot", "palette", "default"));
+
+ /* Introtext */
+ introtext(screen);
+ while(!(mouse_b & 0x1))
+ rest(1);
+
+ /* init speed control */
+ LOCK_FUNCTION(ticker);
+ install_int_ex(ticker, BPS_TO_TIMER(60));
+ speed_control = TRUE;
+
+ while(!key[KEY_ESC])
+ {
+ mainloop:
+ sem_wait(&timer_sem);
+ if(update_fract)
+ {
+ fix_rect(&x1, &y1, &x2, &y2, ((double)SCREEN_W / (double)SCREEN_H));
+ dppx = (x2-x1) / SCREEN_W;
+ mandelbrot(&my_map, x1, y1, x2, y2, max_iter);
+ clear_to_color(mandel, 0xff000000);
+ draw_offset_x = draw_offset_y = 0;
+ draw_zoom = 1.0;
+ update_fract = FALSE;
+ screen_update = TRUE;
+ render_graymap = TRUE;
+ }
+
+ new_mousebtn = mouse_b;
+ if(new_mousebtn != old_mousebtn)
+ {
+ old_mousebtn = new_mousebtn;
+ screen_update = TRUE;
+ }
+ get_mouse_mickeys(&mmx, &mmy);
+ if((mmx != 0) || (mmy != 0) || (screen_update) || (mouse_z != 0))
+ {
+ screen_update = TRUE;
+ if(new_mousebtn & 0x1)
+ {
+ if(r_x1 == -1)
+ {
+ r_x1 = r_x2 = mouse_x;
+ r_y1 = r_y2 = mouse_y;
+ }
+ else
+ {
+ r_x2 = mouse_x;
+ r_y2 = mouse_y;
+ }
+ }
+ else if(r_x1 != -1)
+ {
+ if((r_x1 != r_x2) && (r_y1 != r_y2))
+ {
+ dx = x2 - x1;
+ dy = y2 - y1;
+ x2 = x1 + (r_x2 * (dx/SCREEN_W));
+ y2 = y1 + (r_y2 * (dy/SCREEN_H));
+ x1 = x1 + (r_x1 * (dx/SCREEN_W));
+ y1 = y1 + (r_y1 * (dy/SCREEN_H));
+ screen_update = update_fract = TRUE;
+ }
+ r_x1 = -1; /* Disable zoom mode */
+ }
+ if(new_mousebtn & 0x2)
+ {
+ if(mouse_z < 0)
+ draw_zoom *= 0.75;
+ else if(mouse_z > 0)
+ draw_zoom /= 0.75;
+ if(mouse_z != 0)
+ {
+ draw_offset_x = (int) round((SCREEN_W - (SCREEN_W *
+ draw_zoom))/2);
+ draw_offset_y = (int) round((SCREEN_H - (SCREEN_H *
+ draw_zoom))/2);
+ screen_update = TRUE;
+ }
+ }
+ else if(draw_zoom != 1.0)
+ {
+ draw_zoom = 1.0 / draw_zoom;
+ dx = x2 - x1;
+ dy = y2 - y1;
+ x1 -= ((dx*draw_zoom) - dx)/2;
+ x2 += ((dx*draw_zoom) - dx)/2;
+ y1 -= ((dy*draw_zoom) - dy)/2;
+ y2 += ((dy*draw_zoom) - dy)/2;
+ draw_zoom = 1.0 / draw_zoom;
+ screen_update = update_fract = TRUE;
+ }
+ if(new_mousebtn & 0x4)
+ {
+ drag = TRUE;
+ draw_offset_x += mmx;
+ draw_offset_y += mmy;
+ screen_update = TRUE;
+ }
+ else if(drag)
+ {
+ drag = FALSE;
+ x1 -= draw_offset_x * dppx;
+ x2 -= draw_offset_x * dppx;
+ y1 -= draw_offset_y * dppx;
+ y2 -= draw_offset_y * dppx;
+ screen_update = update_fract = TRUE;
+ }
+ }
+
+ if(key[KEY_P])
+ {
+ speed_control = FALSE;
+ blur(buffer, blurbuf);
+ blit(blurbuf, screen, 0, 0, 0, 0, SCREEN_W, SCREEN_H);
+ exec_paledit();
+ render_graymap = TRUE;
+ speed_control = TRUE;
+ }
+
+ position_mouse_z(0);
+
+ if(screen_update)
+ {
+ /* Render graymap */
+ if(render_graymap)
+ {
+ render_graymap_alleg(mandel, &my_map, paledit_data.pal_cols,
+ paledit_data.pal_grays, paledit_data.n);
+ render_graymap = FALSE;
+ }
+
+ blit(checkered, buffer, 0, 0, 0, 0, SCREEN_W, SCREEN_H);
+ if((draw_offset_x != 0) || (draw_offset_y != 0) ||
+ (draw_zoom != 1.0))
+ stretch_blit(mandel, buffer, 0, 0, mandel->w, mandel->h,
+ draw_offset_x, draw_offset_y,
+ (int) round(mandel->w * draw_zoom),
+ (int) round(mandel->h * draw_zoom));
+ else
+ blit(mandel, buffer, 0, 0, 0, 0, SCREEN_W, SCREEN_H);
+ if(r_x1 != -1)
+ {
+ rectfill(buffer, r_x1, r_y1, r_x2, r_y2, 0x80ffffff);
+ rect(buffer, r_x1, r_y1, r_x2, r_y2, 0xffffffff);
+ }
+ /* Draw cursor */
+ draw_trans_sprite(buffer, cursor, mouse_x-10, mouse_y-10);
+
+ /* Infobar */
+ rectfill(buffer, 0, SCREEN_H - 14, SCREEN_W, SCREEN_H,
+ 0x90000000);
+ textprintf_ex(buffer, font, 2, SCREEN_H - 12, 0xffffffff, -1,
+ "X = %lf Y = %lf", x1 + mouse_x * dppx, y1 + mouse_y * dppx);
+ textprintf_right_ex(buffer, font, SCREEN_W - 2, SCREEN_H - 12,
+ 0xffffffff, -1, "(c) 2010 by Kevin Chabowski");
+
+ if(update_fract)
+ textprintf_centre_ex(buffer, font, (int)(SCREEN_W/2),
+ (int)(SCREEN_H/2), 0xffffffff, makecol(0,0,0),
+ "Rerendering. Please wait...");
+
+ blit(buffer, screen, 0, 0, 0, 0, SCREEN_W, SCREEN_H);
+ screen_update = FALSE;
+ }
+ }
+ blur(buffer, blurbuf);
+ blit(blurbuf, screen, 0, 0, 0, 0, SCREEN_W, SCREEN_H);
+ if(alert("", "Do you really want to quit?", "", "&Yes, get out of here!",
+ "&No, I want to stay", 'y', 'n') == 2)
+ {
+ screen_update = TRUE;
+ goto mainloop;
+ }
+
+ /* Tidy up */
+ destroy_paledit();
+ destroy_graymap(&my_map);
+ destroy_bitmap(cursor);
+ destroy_bitmap(blurbuf);
+ destroy_bitmap(checkered);
+ destroy_bitmap(buffer);
+ destroy_bitmap(mandel);
+ allegro_exit();
+ return 0;
+}
+END_OF_MAIN()
diff --git a/mandelbrot.cfg b/mandelbrot.cfg
new file mode 100644
index 0000000..29af675
--- /dev/null
+++ b/mandelbrot.cfg
@@ -0,0 +1,7 @@
+# Config file for mandelbrot
+[mandelbrot]
+fullscreen = 0
+width = 1200
+height = 750
+palette = default
+max_iter = 300
diff --git a/paledit.c b/paledit.c
new file mode 100644
index 0000000..bb7dd26
--- /dev/null
+++ b/paledit.c
@@ -0,0 +1,363 @@
+#include <allegro.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include "common_types.h"
+#include "graymap.h"
+#include "graymap_alleg.h"
+
+/* Set directory seperator */
+#define DS '/'
+#if defined(WIN32) || defined(__WIN32__)
+#define DS '\\'
+#endif
+
+struct
+{
+ BITMAP* gradient;
+ int n;
+ color_t pal_cols[30];
+ double pal_grays[30];
+ BOOL pal_change;
+ char palname_buffer[41 * 4];
+} paledit_data;
+
+void write_eightbytes(FILE* fp, uint_64 eb)
+{
+ int i;
+ for(i = 0; i < 8; ++i)
+ fputc((int)(((char*) (&eb))[i]), fp);
+}
+
+uint_64 read_eightbytes(FILE* fp)
+{
+ int i;
+ uint_64 rv;
+ for(i = 0; i < 8; ++i)
+ ((char*)(&rv))[i] = (char) fgetc(fp);
+ return rv;
+}
+
+void save_palette(char* name)
+{
+ char* fullpath;
+ uint_64 eb;
+ int i;
+ fullpath = (char*) malloc(sizeof(char) * (strlen(name) + 10));
+ if(fullpath == NULL)
+ exit(1);
+
+ sprintf(fullpath, "pals%c%s.pal", DS, name);
+
+ FILE* fp;
+ fp = fopen(fullpath, "wb");
+ if(fp == NULL)
+ exit(1);
+
+ /* Write numbers of entries */
+ write_eightbytes(fp, (uint_64) paledit_data.n);
+
+ /* Write entries */
+ for(i = 0; i < paledit_data.n; ++i)
+ {
+ (eb) = (uint_64) round(paledit_data.pal_grays[i]*10000.0);
+ write_eightbytes(fp, eb);
+ (eb) = (uint_64) round(paledit_data.pal_cols[i].r*10000.0);
+ write_eightbytes(fp, eb);
+ (eb) = (uint_64) round(paledit_data.pal_cols[i].g*10000.0);
+ write_eightbytes(fp, eb);
+ (eb) = (uint_64) round(paledit_data.pal_cols[i].b*10000.0);
+ write_eightbytes(fp, eb);
+ (eb) = (uint_64) round(paledit_data.pal_cols[i].a*10000.0);
+ write_eightbytes(fp, eb);
+ }
+
+ fclose(fp);
+ free(fullpath);
+}
+
+void load_palette(char* name)
+{
+ char* fullpath;
+ uint_64 eb;
+ int i;
+ fullpath = (char*) malloc(sizeof(char) * (strlen(name) + 10));
+ if(fullpath == NULL)
+ exit(1);
+
+ sprintf(fullpath, "pals%c%s.pal", DS, name);
+
+ FILE* fp;
+ fp = fopen(fullpath, "rb");
+ if(fp == NULL)
+ return;
+
+ /* Read numbers of entries */
+ paledit_data.n = (int) read_eightbytes(fp);
+
+ /* Read entries */
+ for(i = 0; i < paledit_data.n; ++i)
+ {
+ eb = read_eightbytes(fp);
+ paledit_data.pal_grays[i] = (double)(eb/10000.0);
+ eb = read_eightbytes(fp);
+ paledit_data.pal_cols[i].r = (double)(eb/10000.0);
+ eb = read_eightbytes(fp);
+ paledit_data.pal_cols[i].g = (double)(eb/10000.0);
+ eb = read_eightbytes(fp);
+ paledit_data.pal_cols[i].b = (double)(eb/10000.0);
+ eb = read_eightbytes(fp);
+ paledit_data.pal_cols[i].a = (double)(eb/10000.0);
+ }
+
+ fclose(fp);
+ free(fullpath);
+}
+
+void load_palette_cc(const char* name)
+{
+ char* passname;
+ passname = malloc(sizeof(char) * (strlen(name) + 1));
+ if(passname == NULL)
+ exit(1);
+ strcpy(passname, name);
+ load_palette(passname);
+ free(passname);
+}
+
+void add_pal_entry(color_t col, double gray)
+{
+ if((gray < .0) || (gray > 1.0))
+ return;
+
+ int new_pos, i;
+ /* Does grayval already exist? */
+ for(i = 0; i < paledit_data.n; ++i)
+ {
+ if(paledit_data.pal_grays[i] == gray)
+ {
+ new_pos = i;
+ goto add_pal_entry_add_sub;
+ }
+ }
+
+ paledit_data.n++;
+ /* find position in array and shift larger values. */
+ for(new_pos = 0; new_pos < paledit_data.n-2; ++new_pos)
+ {
+ if((gray >= paledit_data.pal_grays[new_pos]) &&
+ (gray <= paledit_data.pal_grays[new_pos+1]))
+ break;
+ }
+ new_pos++;
+ for(i = paledit_data.n-1; i >= new_pos; --i)
+ {
+ paledit_data.pal_grays[i+1] = paledit_data.pal_grays[i];
+ paledit_data.pal_cols[i+1] = paledit_data.pal_cols[i];
+ }
+
+ add_pal_entry_add_sub:
+ paledit_data.pal_cols[new_pos] = col;
+ paledit_data.pal_grays[new_pos] = gray;
+ paledit_data.pal_change = TRUE;
+}
+
+void rem_pal_entry(int i)
+{
+ /* Shift larger elements back. */
+ for(; i < paledit_data.n; ++i)
+ {
+ paledit_data.pal_cols[i] = paledit_data.pal_cols[i+1];
+ paledit_data.pal_grays[i] = paledit_data.pal_grays[i+1];
+ }
+
+ paledit_data.n--;
+
+ paledit_data.pal_change = TRUE;
+}
+
+void rem_nearest_pal(double gray)
+{
+ int i, nearest;
+ nearest = 0;
+ double dist = 10000.0;
+ for(i = 0; i < paledit_data.n; ++i)
+ {
+ if(fabs(paledit_data.pal_grays[i] - gray) < dist)
+ {
+ nearest = i;
+ dist = fabs(paledit_data.pal_grays[i] - gray);
+ }
+ }
+
+ if((nearest == 0) || (nearest == paledit_data.n-1))
+ return;
+
+ rem_pal_entry(nearest);
+}
+
+DIALOG* md;
+
+int color_box(int msg, DIALOG* d, int c)
+{
+ int r,g,b;
+ r = md[1].d2;
+ g = md[2].d2;
+ b = md[3].d2;
+ d->bg = 0xff000000 | makecol(r,g,b);
+ return d_box_proc(msg,d,c);
+}
+
+int my_slider(int msg, DIALOG* d, int c)
+{
+ int old_val = d->d2;
+ int ret;
+ ret = d_slider_proc(msg,d,c);
+ if(d->d2 != old_val)
+ return D_REDRAW;
+ else
+ return ret;
+}
+
+int the_gradient(int msg, DIALOG* d, int c)
+{
+ int x,y;
+ color_t col;
+ if(paledit_data.pal_change)
+ {
+ for(x = 0; x < 370; ++x)
+ {
+ col = get_palette_color((double)((double)x/362.0), paledit_data.pal_cols,
+ paledit_data.pal_grays, paledit_data.n);
+ for(y = 0; y < 30; ++y)
+ {
+ putpixel(paledit_data.gradient, x, y, makeacol(
+ (int) round(col.r*255), (int) round(col.g*255),
+ (int) round(col.b*255), 255));
+ }
+ }
+ paledit_data.pal_change = FALSE;
+ }
+
+ d->dp = paledit_data.gradient;
+ return d_bitmap_proc(msg, d, c);
+}
+
+int add_button(int msg, DIALOG* d, int c)
+{
+ if((d->flags & D_DISABLED) && (paledit_data.n < 30))
+ d->flags &= (~D_DISABLED);
+
+ int rv = d_button_proc(msg,d,c);
+ color_t t;
+ t.a = 1.0;
+ if(rv == D_EXIT)
+ {
+ t.r = md[1].d2 / 255.0;
+ t.g = md[2].d2 / 255.0;
+ t.b = md[3].d2 / 255.0;
+ add_pal_entry(t, md[8].d2 / 1000.0);
+ if(paledit_data.n == 30)
+ d->flags |= D_DISABLED;
+ return D_REDRAW;
+ }
+ return rv;
+}
+
+int del_button(int msg, DIALOG* d, int c)
+{
+ int rv = d_button_proc(msg,d,c);
+ if(rv == D_EXIT)
+ {
+ rem_nearest_pal(md[8].d2 / 1000.0);
+ return D_REDRAW;
+ }
+ return rv;
+}
+
+int save_palette_btn(int msg, DIALOG* d, int c)
+{
+ int rv;
+
+ rv = d_button_proc(msg,d,c);
+ if(rv == D_EXIT)
+ {
+ if(strcmp(paledit_data.palname_buffer, ""))
+ {
+ save_palette(paledit_data.palname_buffer);
+ alert("","Palette saved!","", "&OK!", NULL, 'o', 0);
+ }
+ return D_O_K;
+ }
+ return rv;
+}
+
+int load_palette_btn(int msg, DIALOG* d, int c)
+{
+ int rv;
+
+ rv = d_button_proc(msg,d,c);
+ if(rv == D_EXIT)
+ {
+ if(strcmp(paledit_data.palname_buffer, ""))
+ {
+ load_palette(paledit_data.palname_buffer);
+ paledit_data.pal_change = TRUE;
+ }
+ return D_REDRAW;
+ }
+ return rv;
+}
+
+DIALOG the_dialog[] =
+{
+ /* (dialog proc) (x) (y) (w) (h) (fg)(bg) (key) (flags) (d1) (d2) (dp) (dp2) (dp3) */
+ { d_box_proc, 0, 0, 374, 200, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
+ { my_slider, 12, 102, 300, 10, 0, 0, 0, 0, 255, 0, NULL, NULL, NULL },
+ { my_slider, 12, 122, 300, 10, 0, 0, 0, 0, 255, 0, NULL, NULL, NULL },
+ { my_slider, 12, 142, 300, 10, 0, 0, 0, 0, 255, 0, NULL, NULL, NULL },
+ { color_box, 322, 102, 50, 50, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
+ { d_text_proc, 2, 102, 10, 10, 0, 0, 0, 0, 0, 0, "R", NULL, NULL },
+ { d_text_proc, 2, 122, 10, 10, 0, 0, 0, 0, 0, 0, "G", NULL, NULL },
+ { d_text_proc, 2, 142, 10, 10, 0, 0, 0, 0, 0, 0, "B", NULL, NULL },
+ { d_slider_proc, 2, 62, 370, 10, 0, 0, 0, 0, 1000, 0, NULL, NULL, NULL },
+ { the_gradient, 6, 22, 362, 30, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
+ { add_button, 6, 77, 165, 14, 0, 0, 0, D_EXIT, 0, 0, "Add color here", NULL, NULL },
+ { del_button, 192, 77, 180, 14, 0, 0, 0, D_EXIT, 0, 0, "Delete nearest color", NULL, NULL },
+ { d_text_proc, 2, 162, 110, 10, 0, 0, 0, 0, 0, 0, "Palette name:", NULL, NULL },
+ { d_box_proc, 111, 161, 262, 10, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
+ { d_edit_proc, 112, 162, 260, 8, 0, 0, 0, 0, 40, 0, paledit_data.palname_buffer, NULL, NULL},
+ { save_palette_btn, 57, 177, 120, 14, 0, 0, 0, D_EXIT, 0, 0, "Save palette", NULL, NULL },
+ { load_palette_btn, 187, 177, 120, 14, 0, 0, 0, D_EXIT, 0, 0, "Load palette", NULL, NULL },
+ { d_text_proc, 2, 2, 112, 10, 0, 0, 0, 0, 0, 0, "Palette editor", NULL, NULL },
+ { d_button_proc, 358, 0, 16, 14, 0, 0, 0,D_EXIT, 0, 0, "X", NULL, NULL },
+
+ /* the next two elements don't draw anything */
+ { d_yield_proc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL },
+ { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }
+};
+
+void init_paledit(int canvas_w, int canvas_h)
+{
+ md = the_dialog;
+ position_dialog(the_dialog, (canvas_w-374) / 2, (canvas_h-200)/2);
+ paledit_data.pal_change = TRUE;
+ paledit_data.gradient = create_bitmap(370, 30);
+ set_dialog_color(the_dialog, gui_fg_color, gui_bg_color);
+ the_dialog[0].bg = 0xffffffff;
+ the_dialog[13].bg = 0xff000000 | makecol(255,255,255);
+ the_dialog[13].fg = 0xff000000 | makecol(0,0,0);
+ the_dialog[14].bg = makecol(255, 255, 255);
+ the_dialog[14].fg = makecol(0,0,0);
+}
+
+void exec_paledit()
+{
+ do_dialog(the_dialog, -1);
+}
+
+void destroy_paledit()
+{
+ destroy_bitmap(paledit_data.gradient);
+}
diff --git a/paledit.h b/paledit.h
new file mode 100644
index 0000000..63ac78f
--- /dev/null
+++ b/paledit.h
@@ -0,0 +1,29 @@
+#ifndef _paledit_h_
+#define _paledit_h_
+
+#include <allegro.h>
+#include "common_types.h"
+#include "graymap.h"
+
+extern struct
+{
+ BITMAP* gradient;
+ int n;
+ color_t pal_cols[30];
+ double pal_grays[30];
+ BOOL pal_change;
+ char palname_buffer[41 * 4];
+} paledit_data;
+
+extern void save_palette(char* name);
+
+extern void load_palette(char* name);
+extern void load_palette_cc(const char* name);
+
+extern void init_paledit(int canvas_w, int canvas_h);
+
+extern void exec_paledit();
+
+extern void destroy_paledit();
+
+#endif
diff --git a/pals/LSD.pal b/pals/LSD.pal
new file mode 100644
index 0000000..18a64a3
--- /dev/null
+++ b/pals/LSD.pal
Binary files differ
diff --git a/pals/cool_blue.pal b/pals/cool_blue.pal
new file mode 100644
index 0000000..b34e4ef
--- /dev/null
+++ b/pals/cool_blue.pal
Binary files differ
diff --git a/pals/deepblue.pal b/pals/deepblue.pal
new file mode 100644
index 0000000..192cd05
--- /dev/null
+++ b/pals/deepblue.pal
Binary files differ
diff --git a/pals/default.pal b/pals/default.pal
new file mode 100644
index 0000000..062b7d3
--- /dev/null
+++ b/pals/default.pal
Binary files differ
diff --git a/pals/fire.pal b/pals/fire.pal
new file mode 100644
index 0000000..2354735
--- /dev/null
+++ b/pals/fire.pal
Binary files differ
diff --git a/pals/ice.pal b/pals/ice.pal
new file mode 100644
index 0000000..0713a19
--- /dev/null
+++ b/pals/ice.pal
Binary files differ
diff --git a/pals/matrix.pal b/pals/matrix.pal
new file mode 100644
index 0000000..38fe97b
--- /dev/null
+++ b/pals/matrix.pal
Binary files differ
diff --git a/pals/simple_gray.pal b/pals/simple_gray.pal
new file mode 100644
index 0000000..f590a14
--- /dev/null
+++ b/pals/simple_gray.pal
Binary files differ
diff --git a/pals/snow.pal b/pals/snow.pal
new file mode 100644
index 0000000..23c533d
--- /dev/null
+++ b/pals/snow.pal
Binary files differ
diff --git a/pals/steel_blue.pal b/pals/steel_blue.pal
new file mode 100644
index 0000000..99029eb
--- /dev/null
+++ b/pals/steel_blue.pal
Binary files differ
diff --git a/pals/toxic.pal b/pals/toxic.pal
new file mode 100644
index 0000000..387ee41
--- /dev/null
+++ b/pals/toxic.pal
Binary files differ
diff --git a/pals/ugly.pal b/pals/ugly.pal
new file mode 100644
index 0000000..d8ccc45
--- /dev/null
+++ b/pals/ugly.pal
Binary files differ