diff options
author | Kevin Chabowski <der.pc222@googlemail.com> | 2010-07-28 23:03:16 +0200 |
---|---|---|
committer | Kevin Chabowski <der.pc222@googlemail.com> | 2010-07-28 23:03:16 +0200 |
commit | 054a617a9375b835492368c3773315b09d3851ce (patch) | |
tree | 231d5e4a57e994e3cc3c0b005fea6fe2a4a9fcc9 | |
download | Another-mandelbrot-viewer-054a617a9375b835492368c3773315b09d3851ce.tar.gz Another-mandelbrot-viewer-054a617a9375b835492368c3773315b09d3851ce.tar.bz2 Another-mandelbrot-viewer-054a617a9375b835492368c3773315b09d3851ce.zip |
Initial commit for mandelbrot.
-rwxr-xr-x | .gitignore | 2 | ||||
-rw-r--r-- | COMPILING | 23 | ||||
-rw-r--r-- | LICENSE | 18 | ||||
-rw-r--r-- | Makefile | 20 | ||||
-rw-r--r-- | common_types.h | 40 | ||||
-rw-r--r-- | cursor.tga | bin | 0 -> 2544 bytes | |||
-rw-r--r-- | graymap.c | 106 | ||||
-rw-r--r-- | graymap.h | 159 | ||||
-rw-r--r-- | graymap_alleg.c | 33 | ||||
-rw-r--r-- | graymap_alleg.h | 37 | ||||
-rw-r--r-- | mandelbrot.c | 460 | ||||
-rw-r--r-- | mandelbrot.cfg | 7 | ||||
-rw-r--r-- | paledit.c | 363 | ||||
-rw-r--r-- | paledit.h | 29 | ||||
-rw-r--r-- | pals/LSD.pal | bin | 0 -> 848 bytes | |||
-rw-r--r-- | pals/cool_blue.pal | bin | 0 -> 248 bytes | |||
-rw-r--r-- | pals/deepblue.pal | bin | 0 -> 368 bytes | |||
-rw-r--r-- | pals/default.pal | bin | 0 -> 248 bytes | |||
-rw-r--r-- | pals/fire.pal | bin | 0 -> 288 bytes | |||
-rw-r--r-- | pals/ice.pal | bin | 0 -> 288 bytes | |||
-rw-r--r-- | pals/matrix.pal | bin | 0 -> 248 bytes | |||
-rw-r--r-- | pals/simple_gray.pal | bin | 0 -> 88 bytes | |||
-rw-r--r-- | pals/snow.pal | bin | 0 -> 128 bytes | |||
-rw-r--r-- | pals/steel_blue.pal | bin | 0 -> 208 bytes | |||
-rw-r--r-- | pals/toxic.pal | bin | 0 -> 288 bytes | |||
-rw-r--r-- | pals/ugly.pal | bin | 0 -> 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! + @@ -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 Binary files differnew file mode 100644 index 0000000..052cde3 --- /dev/null +++ b/cursor.tga 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 Binary files differnew file mode 100644 index 0000000..18a64a3 --- /dev/null +++ b/pals/LSD.pal diff --git a/pals/cool_blue.pal b/pals/cool_blue.pal Binary files differnew file mode 100644 index 0000000..b34e4ef --- /dev/null +++ b/pals/cool_blue.pal diff --git a/pals/deepblue.pal b/pals/deepblue.pal Binary files differnew file mode 100644 index 0000000..192cd05 --- /dev/null +++ b/pals/deepblue.pal diff --git a/pals/default.pal b/pals/default.pal Binary files differnew file mode 100644 index 0000000..062b7d3 --- /dev/null +++ b/pals/default.pal diff --git a/pals/fire.pal b/pals/fire.pal Binary files differnew file mode 100644 index 0000000..2354735 --- /dev/null +++ b/pals/fire.pal diff --git a/pals/ice.pal b/pals/ice.pal Binary files differnew file mode 100644 index 0000000..0713a19 --- /dev/null +++ b/pals/ice.pal diff --git a/pals/matrix.pal b/pals/matrix.pal Binary files differnew file mode 100644 index 0000000..38fe97b --- /dev/null +++ b/pals/matrix.pal diff --git a/pals/simple_gray.pal b/pals/simple_gray.pal Binary files differnew file mode 100644 index 0000000..f590a14 --- /dev/null +++ b/pals/simple_gray.pal diff --git a/pals/snow.pal b/pals/snow.pal Binary files differnew file mode 100644 index 0000000..23c533d --- /dev/null +++ b/pals/snow.pal diff --git a/pals/steel_blue.pal b/pals/steel_blue.pal Binary files differnew file mode 100644 index 0000000..99029eb --- /dev/null +++ b/pals/steel_blue.pal diff --git a/pals/toxic.pal b/pals/toxic.pal Binary files differnew file mode 100644 index 0000000..387ee41 --- /dev/null +++ b/pals/toxic.pal diff --git a/pals/ugly.pal b/pals/ugly.pal Binary files differnew file mode 100644 index 0000000..d8ccc45 --- /dev/null +++ b/pals/ugly.pal |