#include <iostream>
#include <math.h>
#include <string>
#include <time.h>
#include <stdio.h>
#include <sstream>
#include <vector>
#include <cmath>
#ifdef __APPLE__
#include <OpenGL/OpenGL.h>
#include <GLUT/glut.h>
#else
//#include <GL/glut.h>
#include <GL/glew.h>
#include <GL/freeglut.h>
#endif
using namespace std;
//// ***** TODO *****
// Choose a better method for storing points RGB values.
// A. use 256-scale unsigned char
// B. figure out a pointer system.
struct point {
unsigned char pointR;
unsigned char pointG;
unsigned char pointB;
float pointX;
float pointY;
float pointZ;
};
point * buff;
point * tmp;
float x = 0.3, y = 0, z = 0,
xOld = 0,
yOld = 0,
zOld = 0,
xOld2 = 0,
yOld2 = 0,
zOld2 = 0,
dOld = 0,
h = 0.083,
a = 14.633,
b = 9.502,
c = 7.827; // starting point
int initialIterations = 200, // initial number of iterations to allow the attractor to settle
iterations = 5000000, // number of times to iterate through the functions and draw a point
cols = 3;
void merge(point*, int, int, int);
void mergesort(point *p, int low, int high)
{
int pivot;
if(low<high)
{
pivot = (low + high)/2;
mergesort(p, low, pivot);
mergesort(p, pivot+1,high);
merge(p,low,pivot,high);
}
}
void merge(point *p, int low, int pivot, int high) {
int mh, mi, mj, mk;
mh = low;
mi = low;
mj = pivot+1;
while((mh <= pivot) && (mj <= high)) {
if(p[mh].pointZ <= p[mj].pointZ) {
tmp[mi] = p[mh];
mh++;
} else {
tmp[mi] = p[mj];
mj++;
}
mi++;
}
if(mh > pivot) {
for(mk = mj; mk <= high; mk++) {
tmp[mi] = p[mk];
mi++;
}
} else {
for(mk = mh; mk <= pivot; mk++) {
tmp[mi] = p[mk];
mi++;
}
}
for(mk = low; mk <= high; mk++) p[mk]=tmp[mk];
}
void myinit() {
// set the background color
glClearColor(0.0, 0.0, 0.0, 1.0);
// set the foreground (pen) color
glColor4f(1.0, 1.0, 1.0, 0.0005);
// set up the viewport
glViewport(0,0,1366,768);
// set up the projection matrix (the camera)
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(-20.0, 20.0, -11.24451, 11.24451);
// set up the modelview matrix (the objects)
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
GLint iMultiSample = 0;
GLint iNumSamples = 0;
glGetIntegerv(GL_SAMPLE_BUFFERS, &iMultiSample);
glGetIntegerv(GL_SAMPLES, &iNumSamples);
// compute some initial iterations to settle into the orbit of the attractor
for (int i = 0; i < initialIterations; i++) {
float xnew = x + h * a * (y - x);
float ynew = y + h * (x * (b-z) - y);
float znew = z + h * ( x * y - c * z);
float xdist = abs(xnew - x);
float ydist = abs(ynew - y);
float zdist = abs(znew - z);
float xydist = sqrt(xdist*xdist + ydist*ydist);
float dist = sqrt (xydist*xydist + zdist*zdist);
dOld = dist;
xOld = x;
yOld = y;
zOld = z;
// save the new point
x = xnew;
y = ynew;
z = znew;
}
// enable blending
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// enable point smoothing
glEnable(GL_POINT_SMOOTH);
glEnable(GL_MULTISAMPLE);
glEnable(GL_LINE_SMOOTH);
glHint(GL_LINE_SMOOTH, GL_NICEST);
glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
glHint(GL_POINT_SMOOTH, GL_NICEST);
glPointSize(1.0f);
}
void mydisplay() {
// clear the screen
glClear(GL_COLOR_BUFFER_BIT);
// draw some points
glBegin(GL_POINTS);
// iterate through the equations many times, drawing one point for each iteration
for (int i = 0; i < iterations; i++) {
// compute a new point using the strange attractor equations
float xnew = x + h * a * (y - x);
float ynew = y + h * (x * (b-z) - y);
float znew = z + h * ( x * y - c * z);
int mod = static_cast<int> ( i / 1000000 );
float res = i - static_cast<float>( mod ) * 1000000;
if (res == 0.0) {
cout << i / 1000000 << " million rendered, res = " << res << endl;
}
float xdist = abs(xnew - x);
float ydist = abs(ynew - y);
float zdist = abs(znew - z);
float xydist = sqrt(xdist*xdist + ydist*ydist);
float dist = sqrt (xydist*xydist + zdist*zdist);
float dAvg = (dist + dOld) / 2;
dOld = dist;
dist = dAvg;
float ypos = (1 / (dist / 27));
float angle = atan2(ypos, dist) * 4.0f;
angle = angle + (3.1415926535)/3.0f;
float r = 0.5 * ( sin(angle) ) + 0.5;
float g = 0.5 * ( sin(angle + (2 * 3.1415926535)/3) ) + 0.5;
float b = 0.5 * ( sin(angle + (4 * 3.1415926535)/3) ) + 0.5;
if (r >= 1.0f || g >= 1.0f || b >= 1.0f) {
// cout << "R: " << r << "G: " << g << "B: " << b << endl;
}
//vector<float> vx1, vy1, vz1, vx2, vy2, vz2;
xOld2 = xOld;
yOld2 = yOld;
zOld2 = zOld;
xOld = x;
yOld = y;
zOld = z;
x = xnew;
y = ynew;
z = znew;
// draw the new point
//glVertex4f(xOld, yOld, 0, 1.0f);
buff[i].pointX = xOld;
buff[i].pointY = yOld;
buff[i].pointZ = zOld;
buff[i].pointR = r * 256;
buff[i].pointG = g * 256;
buff[i].pointB = b * 256;
}
//glBegin(GL_POINTS);
for(int i = 0; i < iterations; i++) {
//cout << buff[i].pointR << " " << buff[i].pointG << " " << buff[i].pointB << endl;
glColor4f ((float)buff[i].pointR / 256.0f, (float)buff[i].pointG / 256.0f, (float)buff[i].pointB / 256.0f, 0.1f);
//cout << buff[i].pointX << " " << buff[i].pointY << " " << buff[i].pointZ << endl;
glVertex4f(buff[i].pointX, buff[i].pointY, /*buff[i].pointZ*/ 0.0, 1.0f);
}
glEnd();
// swap the buffers
glutSwapBuffers();
for(int li = 0; li < 20; li ++) {
cout << buff[li].pointZ << " ";
}
cout << endl;
mergesort(buff, 0, iterations);
for(int li = 0; li < 20; li ++) {
cout << buff[li].pointZ << " ";
}
cout << endl;
cout << "Finished!" << endl;
}
void mykey(unsigned char mychar, int x, int y) {
// exit the program when the Esc key is pressed
if (mychar == 27) {
exit(0);
}
}
int main (int argc, char **argv) {
buff = new point[iterations];
tmp = new point[iterations];
// initialize GLUT
glutInit(&argc, argv);
// set up our display mode for color with alpha and float buffering
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH | GLUT_MULTISAMPLE);
// create a 400px x 400px window
glutInitWindowSize(1366, 768);
glutCreateWindow("Strange Attractors in C++ and OpenGL Tutorial");
// register our callback functions
glutDisplayFunc(mydisplay);
glutKeyboardFunc(mykey);
// call our initialization function
myinit();
// start the program
glutMainLoop();
return 0;
}