OpenGLEAN
OpenGLEAN User Support
Home page | Introduction | Documentation | Files | Examples | Proposals | Authors | Links


OpenGLEAN Development
Summary | CVS | (discussion via home page) | (contact via home page) | (suggestion box) | License | Todo | Bugs

fractals_random.c File Reference

Include dependency graph for fractals_random.c:


Detailed Description

This demo is a single-buffered OpenGLEAN example.

Program to draw a fractal by Michael Barnsley's deterministic algorithm.

Algorithm:

User Interaction:

Author:
Copyright 2004, 2005, the OpenGLEAN Project.

Portions Copyright (C) 2004, the OpenGLUT project contributors.
OpenGLUT branched from freeglut in February, 2004.

openglean_fractals.png

OpenGLEAN Fractal Demonstration

#include <GL/openglean.h>

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifdef MSC_VER
#include <crtdbg.h>                /* DUMP MEMORY LEAKS */
#endif

typedef struct
{
    double a00, a01, a10, a11;        /* Transformation matrix */
    double b0, b1;                /* Constant vector added on */
    double statx, staty;        /* Coordinates of the stationary point */
} AffineTrans;

/* Number of levels to draw the fractal */
static int num_levels = 0;

/* The definition of the fractal */
static int num_trans;
static AffineTrans *affine;

/* the window title */
#define WIN_TITLE_LENGTH 80
char window_title [WIN_TITLE_LENGTH + 1];

/* The amount the view is translated */
double xwin = 0, ywin = 0;
double scale_factor = 1;

/* The current point */
double current_x = 0, current_y = 0;

/* Signals when a glClear is needed */
static GLboolean needClear = GL_TRUE;

static void draw_level (
    int num,
    double m00, double m01, double m10, double m11, double n0, double n1
)
{
    /* Draw a fractal transformed by "M", "N" as passed in */
    int i;

    (void) num; /* XXX Use parameters to silence GCC warnings */
    (void) m00;
    (void) m01;
    (void) m10;
    (void) m11;
    (void) n0;
    (void) n1;

    for (i = 0; i < 10; i++)
    {
        int random = (rand () >> 10) % num_trans;
        double new_x = affine [random].a00 * current_x +
            affine [random].a01 * current_y + affine [random].b0;
        double new_y = affine [random].a10 * current_x +
            affine [random].a11 * current_y + affine [random].b1;

        glVertex2d (new_x, new_y);
        current_x = new_x;
        current_y = new_y;
    }
}

static void Display (void)
{
    if (needClear)
    {
        glClear (GL_COLOR_BUFFER_BIT);
        needClear = GL_FALSE;
    }

    /* the curve */
    glPushMatrix ();
    glScaled (2.5, 2.5, 2.5);

    glColor4f (0, 0, 0, 1);
    glBegin (GL_POINTS);
    draw_level (num_levels, 1, 0, 0, 1, 0, 0);
    glEnd ();

    glPopMatrix ();

    glFlush ();
    glutPostRedisplay ();        /* Keep calling this function. */
}

static void Reshape (int width, int height)
{
    double ar;

    glViewport (0, 0, width, height);
    glMatrixMode (GL_PROJECTION);
    glLoadIdentity ();
    ar = width / (1.0 * height);
    if (ar > 1)
        glFrustum (-ar, ar, -1, 1, 2, 100);
    else
        glFrustum (-1, 1, -1 / ar, 1 / ar, 2, 100);
    glMatrixMode (GL_MODELVIEW);
    glLoadIdentity ();
    xwin = -1;
    ywin = 0;
    glTranslated (xwin, ywin, -5);
    needClear = GL_TRUE;
}

static void Key (unsigned char key, int x, int y)
{
    int changed_settings = 1;

    (void) x; /* XXX Reference at least once to placate GCC */
    (void) y;

    switch (key)
    {
    case 27: /* Escape key */
        glutLeaveMainLoop ();
        break;

    case 'r': case 'R':
        glMatrixMode (GL_MODELVIEW);
        glLoadIdentity ();
        xwin = -1;
        ywin = 0;
        glTranslated (xwin, ywin, -5);
        break;

    default:
        changed_settings = 0;
        break;
    }
    if (changed_settings)
        needClear = GL_TRUE;
    glutPostRedisplay ();
}

static void Special (int key, int x, int y)
{
    int changed_settings = 1;

    (void) x; /* XXX Reference at least once to placate GCC */
    (void) y;

    switch (key)
    {
    case GLUT_KEY_UP:
        glMatrixMode (GL_MODELVIEW);
        ywin += .1 * scale_factor;
        glTranslated (0, 1 * scale_factor, 0);
        break;

    case GLUT_KEY_DOWN:
        glMatrixMode (GL_MODELVIEW);
        ywin -= .1 * scale_factor;
        glTranslated (0, -.1 * scale_factor, 0);
        break;

    case GLUT_KEY_LEFT:
        glMatrixMode (GL_MODELVIEW);
        xwin -= .1 * scale_factor;
        glTranslated (-.1 * scale_factor, 0, 0);
        break;

    case GLUT_KEY_RIGHT:
        glMatrixMode (GL_MODELVIEW);
        xwin += .1 * scale_factor;
        glTranslated (.1 * scale_factor, 0, 0);
        break;

    case GLUT_KEY_PAGE_UP:
        glMatrixMode (GL_MODELVIEW);
        glTranslated (-xwin, -ywin, 0);
        glScaled (1.25, 1.25, 1.25);
        glTranslated (xwin, ywin, 0);
        scale_factor *= .8;
        break;

    case GLUT_KEY_PAGE_DOWN:
        glMatrixMode (GL_MODELVIEW);
        glTranslated (-xwin, -ywin, 0);
        glScaled (.8, .8, .8);
        glTranslated (xwin, ywin, 0);
        scale_factor *= 1.25;
        break;

    default:
        changed_settings = 0;
        break;
    }
    if (changed_settings)
        needClear = GL_TRUE;

    glutPostRedisplay ();
}


static int mouse_x = 0, mouse_y = 0;
static int button_down = GLUT_DOWN;

static void Mouse (int button, int updown, int x, int y)
{
    if (!button) /* Left-most */
    {
        button_down = updown;

        if (updown == GLUT_DOWN)
        {
            mouse_x = x;
            mouse_y = y;
        }
    }
}

static void MouseMotion (int x, int y)
{
    int window_width = glutGet (GLUT_WINDOW_WIDTH);
    int window_height = glutGet (GLUT_WINDOW_HEIGHT);
    int window_size = (window_width < window_height) ?
    window_width : window_height;

    double delta_x = 5 * (x - mouse_x) / (double) (window_size);
    double delta_y = 5 * (y - mouse_y) / (double) (window_size);

    xwin += delta_x * scale_factor;
    ywin -= delta_y * scale_factor;
    glMatrixMode (GL_MODELVIEW);
    glTranslated (delta_x * scale_factor, -delta_y * scale_factor, 0);

    needClear = GL_TRUE;
    glutPostRedisplay ();

    mouse_x = x;
    mouse_y = y;
}

static void MouseWheel (int wheel_number, int direction, int x, int y)
{
    double scale = (direction > 0) ? 1.25 : .8;

    (void) x; /* XXX Reference at least once to placate GCC */
    (void) y;
    (void) wheel_number;

    glMatrixMode (GL_MODELVIEW);
    glTranslated (-xwin, -ywin, 0);
    glScaled (scale, scale, scale);
    glTranslated (xwin, ywin, 0);
    scale_factor /= scale;

    needClear = GL_TRUE;
    glutPostRedisplay ();
}


void readConfigFile (char *fnme)
{
    FILE *fptr = fopen (fnme, "rt");
    int i;
    char inputline [256];

    if (fptr)
    {
        /* Read a header line */
        fgets (inputline, 256, fptr);

        /* Read a comment line */
        fgets (inputline, 256, fptr);

        /* Read the window title */
        fgets (inputline, 256, fptr);
        /*
           We assume here that this line will not exceed 79 characters plus a
           newline (window_title is 80 characters long). That'll cause a buffer
           overflow. For a simple program like  this, though, we're letting it
           slide!
        */
        sscanf (inputline, "%[a-zA-Z0-9!@#$%^&*()+=/\\_-\" ]", window_title);

        /* Read a comment line */
        fgets (inputline, 256, fptr);

        /* Read the number of affine transformations */
        fgets (inputline, 256, fptr);
        sscanf (inputline, "%d", &num_trans);

        affine = (AffineTrans *) malloc (num_trans * sizeof (AffineTrans));

        /* Read a comment line */
        fgets (inputline, 256, fptr);

        for (i = 0; i < num_trans; i++)
        {
            /* Read an affine transformation definition */
            fgets (inputline, 256, fptr);
            sscanf (
                inputline, "%lf %lf %lf %lf %lf %lf",
                &affine [i].a00, &affine [i].a01,
                &affine [i].a10, &affine [i].a11,
                &affine [i].b0,  &affine [i].b1
            );
        }
    }
    else /* No data file, set a default */
    {
        printf ("ERROR opening file <%s>\n", fnme);
        strncpy (window_title, "Cantor Dust", WIN_TITLE_LENGTH);
        num_trans = 2;
        affine = (AffineTrans *) malloc (num_trans * sizeof (AffineTrans));
        affine [0].a00 = .25; affine [0].a01 = 0;
        affine [0].a10 = 0;   affine [0].a11 = .25;
        affine [0].b0 = 0;    affine [0].b1 = 0;
        affine [1].a00 = .25; affine [1].a01 = 0;
        affine [1].a10 = 0;   affine [1].a11 = .25;
        affine [1].b0 = .5;   affine [1].b1 = 0;
    }
        
    for( i = 0; i < num_trans; i++ )
    {
        double m00, m01, m10, m11;  /* Matrix "I" minus "A" */
        double determ;              /* Determinant of this matrix */

        /* Calculate the stationary point */

        m00 = 1 - affine [i].a00;
        m01 = 0 - affine [i].a01;
        m10 = 0 - affine [i].a10;
        m11 = 1 - affine [i].a11;

        determ = m00 * m11 - m01 * m10;

        if (fabs (determ) > 1.e-6)
        {
            affine [i].statx =
                ( m11 * affine [i].b0 - m01 * affine [i].b1) / determ;
            affine [i].staty =
                (-m10 * affine [i].b0 + m00 * affine [i].b1) / determ;
        }
        else
            affine [i].statx = affine [i].staty = 0;
    }
}

int main (int argc, char **argv)
{
    int fractal_window;

    glutInitDisplayMode (GLUT_RGB | GLUT_SINGLE);

    glutInitWindowSize (500, 250);
    glutInitWindowPosition (140, 140);
    glutInit (&argc, argv);

    if (argc > 1)
        readConfigFile (argv [1]);
    else
        readConfigFile ("fractals.dat");

    fractal_window = glutCreateWindow (window_title);

    glClearColor (1, 1, 1, 1);

    glutReshapeFunc (Reshape);
    glutKeyboardFunc (Key);
    glutSpecialFunc (Special);
    glutDisplayFunc (Display);
    glutMouseFunc (Mouse);
    glutMotionFunc (MouseMotion);
    glutMouseWheelFunc (MouseWheel);

    glutMainLoop ();

    free (affine);

#ifdef MSC_VER
    _CrtDumpMemoryLeaks ();        /* DUMP MEMORY LEAK INFORMATION */
#endif

    return EXIT_SUCCESS;
}

Bug:
Uses a poor random number generator if rand() is not very good. We should define our own, since rand() is all that the C language will guarantee for us.




SourceForge.net Logo Supported in part by SourceForge.net.

Generated on Fri Sep 16 20:15:24 2005 for OpenGLEAN by doxygen 1.4.3
The OpenGLEAN project is hosted by olib.org and SourceForge.