Hello Dratone,
I had the same problem when I started with fractals (about 15 years ago). I didn't know how to draw something on screen or how to calculate fractal iteration. But during this time I wrote fractal renderers in Atari Basic, Amos Basic (Amiga), Matlab, Delphi, TurboPascal, C++ on Amiga (for Motorola 68040 and PowerPC), Microsoft Visual Basic, Borland C++, on Windows and latest in C++ on Linux. I know that some basic example is very helpful at the beginning. I prepared sample code for you in C / C++ for Linux GTK environment (I'm using Ubuntu Linux 9.10 x64). This program is for rendering simple 2D Mandelbrot sets
#include <gtk/gtk.h>
#include <math.h>
#include <jpeglib.h>
#include <setjmp.h>
#include <stdio.h>
#define IMAGE_WIDTH 800
#define IMAGE_HEIGHT 800
guchar *rgbbuf;
gboolean on_darea_expose(GtkWidget *widget, GdkEventExpose *event, gpointer user_data);
struct sFractal
{
double amin;
double amax;
double bmin;
double bmax;
int N;
double da;
double db;
};
struct sParam
{
int start;
int index;
sFractal fractal;
};
int CalculateIterations(double &a, double &b, int &N)
{
double x = a;
double y = b;
int i;
for (i = 0; i < N; i++)
{
double tempx = x * x - y * y + a;
y = 2.0 * x * y + b;
x = tempx;
double r = x * x + y * y;
if (r > 4) break;
}
return i;
}
//function for saving JPG file using jpeglib
void SaveJPEG(char *filename, int quality, int width, int height, JSAMPLE *image)
{
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
FILE * outfile;
JSAMPROW row_pointer[1];
int row_stride;
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_compress(&cinfo);
if ((outfile = fopen(filename, "wb")) == NULL)
{
fprintf(stderr, "can't open %s\n", filename);
return;
}
jpeg_stdio_dest(&cinfo, outfile);
cinfo.image_width = width;
cinfo.image_height = height;
cinfo.input_components = 3; /* # of color components per pixel */
cinfo.in_color_space = JCS_RGB; /* colorspace of input image */
jpeg_set_defaults(&cinfo);
jpeg_set_quality(&cinfo, quality, TRUE);
jpeg_start_compress(&cinfo, TRUE);
row_stride = width * 3; /* JSAMPLEs per row in image_buffer */
while (cinfo.next_scanline < cinfo.image_height)
{
row_pointer[0] = &image[cinfo.next_scanline * row_stride];
(void) jpeg_write_scanlines(&cinfo, row_pointer, 1);
}
jpeg_finish_compress(&cinfo);
fclose(outfile);
jpeg_destroy_compress(&cinfo);
}
//********************************** MAIN *******************************
int main(int argc, char *argv[])
{
//gtk widgets
GtkWidget *window, *darea, *box;
//allocation memory for graphics
rgbbuf = new guchar[IMAGE_WIDTH * IMAGE_HEIGHT * 3];
//main window
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL);
g_signal_connect(G_OBJECT(window), "delete_event", G_CALLBACK(gtk_main_quit), NULL);
//,ain box in window
box = gtk_vbox_new(FALSE, 0);
gtk_container_set_border_width(GTK_CONTAINER(box), 5);
//drawing area
darea = gtk_drawing_area_new();
gtk_widget_set_size_request(darea, IMAGE_WIDTH, IMAGE_HEIGHT);
gtk_signal_connect(GTK_OBJECT(darea), "expose-event", GTK_SIGNAL_FUNC(on_darea_expose), NULL);
//putting darea to box
gtk_box_pack_start(GTK_BOX(box), darea, FALSE, FALSE, 0);
//putting box to window
gtk_container_add(GTK_CONTAINER(window), box);
gtk_widget_show_all(window);
//main parameters of fractal
sFractal fractal;
fractal.amin = -2.2;
fractal.amax = 0.8;
fractal.bmin = -1.5;
fractal.bmax = 1.5;
fractal.N = 32;
fractal.da = (fractal.amax - fractal.amin) / IMAGE_WIDTH;
fractal.db = (fractal.bmax - fractal.bmin) / IMAGE_HEIGHT;
//rendering
for (int x = 0; x < IMAGE_WIDTH; x++)
{
for (int y = 0; y < IMAGE_HEIGHT; y++)
{
double a = fractal.amin + x * fractal.da;
double b = fractal.bmin + y * fractal.db;
int L = CalculateIterations(a, b, fractal.N);
int brightness = 255.0 * ((double) L / fractal.N);
int address = (x + y * IMAGE_WIDTH) * 3;
rgbbuf[address] = brightness * 1.0; // red
rgbbuf[address + 1] = brightness * 0.9; //green
rgbbuf[address + 2] = brightness * 0.5; //blue
}
}
//end of rendering
//draw offscreen image in window
gdk_draw_rgb_image(darea->window, darea->style->fg_gc[GTK_STATE_NORMAL], 0, 0, IMAGE_WIDTH, IMAGE_HEIGHT, GDK_RGB_DITHER_NONE, rgbbuf, IMAGE_WIDTH * 3);
//saving image in JPG file
SaveJPEG("/media/Dane/Roboczy2/test.jpg", 90, IMAGE_WIDTH, IMAGE_HEIGHT, (JSAMPLE*) rgbbuf);
//wait for refreshing interface (it is necessary when fractal is rendering in animation loop)
while (gtk_events_pending())
gtk_main_iteration();
printf("End of rendering");
gtk_main();
return 0;
}
//This function refreshes graphinc when window is exposured
gboolean on_darea_expose(GtkWidget *widget, GdkEventExpose *event, gpointer user_data)
{
gdk_draw_rgb_image(widget->window, widget->style->fg_gc[GTK_STATE_NORMAL], 0, 0, IMAGE_WIDTH, IMAGE_HEIGHT, GDK_RGB_DITHER_MAX, rgbbuf, IMAGE_WIDTH * 3);
return TRUE;
}
For compile this I'm using gcc or g++ with following parameters (this is example for Eclipse SDK C++):
g++ -O2 -march=native -mfpmath=387,sse -ffast-math -Wall -c -fmessage-length=0 `pkg-config --cflags gtk+-2.0;` -MMD -MP -MF"Fractal2D.d" -MT"Fractal2D.d" -o"Fractal2D.o" "../Fractal2D.cpp"
and for linker: g++ `pkg-config --libs gtk+-2.0` -o"Fractal2D" ./Fractal2D.o -ljpeg
If you have some additional questions please don't hesitate to ask.