commit 0be3c70181a88114da5567d3d7dc61706837690e Author: Geoff Murphy <murphy@fake.onl> Date: Sat Oct 5 12:12:58 2024 +1000 :tada: Initial commit diff --git a/.gitignore b/.gitignore new file mode 100755 index 0000000..39f3a08 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +/bin +/obj +/output +/tmp diff --git a/makefile b/makefile new file mode 100755 index 0000000..e9b7665 --- /dev/null +++ b/makefile @@ -0,0 +1,44 @@ +OS := $(shell uname) + +NAME=$(shell pwd | sed "s/.*\///g") + +ifeq (${OS},Darwin) + CC=clang++ + FLAGS=-std=c++11 -stdlib=libc++ + RUN=${NAME} +else ifeq (${OS},Linux) + CC=g++ + FLAGS=-std=c++11 -pthread + RUN=${NAME} + FILES=$(shell find -name *.cpp) +else + CC=g++ + FLAGS=-std=c++11 + RUN=${NAME}.exe + FILES=$(shell find -name *.cpp) +endif + + +all: clean build run images video play + +build: + ${CC} ${FILES} ${FLAGS} -o bin/${RUN} + +run: + bin/./${RUN} + +video: + ffmpeg -i output/frames/image_%05d.png -c:v libx264 -vf fps=25 -pix_fmt yuv420p output/video.mp4 + +play: + vlc -L output/video.mp4 + +images: + mogrify -verbose -format png output/frames/*.ppm + rm $(shell find output/frames -name "*.ppm") + + +clean: + rm -f -r bin/* + rm -f -r output/frames/* + rm -f output/video.mp4 diff --git a/src/fractal/buddhabulb.cpp b/src/fractal/buddhabulb.cpp new file mode 100755 index 0000000..53fd3bc --- /dev/null +++ b/src/fractal/buddhabulb.cpp @@ -0,0 +1 @@ +#include "buddhabulb.h" diff --git a/src/fractal/buddhabulb.h b/src/fractal/buddhabulb.h new file mode 100755 index 0000000..fdcdfbb --- /dev/null +++ b/src/fractal/buddhabulb.h @@ -0,0 +1,6 @@ +#ifndef BUDDHABULB_H_ +#define BUDDHABULB_H_ + + + +#endif diff --git a/src/fractal/buffer.cpp b/src/fractal/buffer.cpp new file mode 100755 index 0000000..c28deb9 --- /dev/null +++ b/src/fractal/buffer.cpp @@ -0,0 +1,191 @@ +#include "buffer.h" + + + + +///////// +///////// Buffer Functions +///////// + +Buffer::Buffer(int _width, int _height){ + width = _width; + height = _height; + + itterations = 255; + samples = 4; + contrast = 2; + fractal = 1; + ratio = (float)width/(float)height; + + setCursor(0, 0, 1, 0); + setStart(0, 0, 1, 0); + setEnd(0, 0, 1, 0); + + buffer.resize(width, std::vector<int>(height)); +} + +void Buffer::clear(){ + maxValue = 0; + for(int x=0; x<width; x++){ + for(int y=0; y<height; y++){ + buffer[x][y] = 0; + } + } +} + +void Buffer::save(std::string _filename){ + FILE *f = fopen( _filename.c_str(), "w" ); // Write image to PPM file. + fprintf(f, "P3\n%d %d\n%d\n", width, height, 255); + for(int y=0; y<height; y++){ + for(int x=0; x<width; x++){ + + float bright = map((float)buffer[x][y], 0, (float)maxValue, 0, 1.0); + int value = (int)map(pow(bright, 1.0/contrast), 0, 1, 0, 255); + + fprintf(f,"%d %d %d ", value, value, value); + } + } +} + + + + +///////// +///////// Buffer Settings +///////// + +int Buffer::getMax(){ + return maxValue; +} + +void Buffer::setItterations(int _itterations){ + itterations = _itterations; +} +void Buffer::setSamples(int _samples){ + samples = _samples; +} +void Buffer::setContrast(float _contrast){ + contrast = _contrast; +} + +void Buffer::setFractal(unsigned char _fractal){ + fractal = _fractal; +} + +std::string Buffer::stats(){ + std::ostringstream output; + output << "Buffer: " << width << "x" << height; + output << " Samples: " << samples << " Itterations: " << itterations; + output << " Contrast: " << contrast; + return output.str(); +} + + + + +///////// +///////// Translate Coordinates +///////// + +void Buffer::setCursor(float _x, float _y, float _s, float _r){ + cur.x = _x; + cur.y = _y; + cur.s = _s; + cur.r = _r; +} +void Buffer::setStart(float _x, float _y, float _s, float _r){ + start.x = _x; + start.y = _y; + start.s = _s; + start.r = _r; +} +void Buffer::setEnd(float _x, float _y, float _s, float _r){ + end.x = _x; + end.y = _y; + end.s = _s; + end.r = _r; +} + +void Buffer::cursorUpdate(float _f){ + cur.x = start.x + (end.x-start.x)*_f; + cur.y = start.y + (end.y-start.y)*_f; + cur.s = start.s + (end.s-start.s)*_f; + cur.r = start.r + (end.r-start.r)*_f; +} + +float Buffer::map(float _v, float _a1, float _a2, float _b1, float _b2){ + return _b1 + (_v-_a1)*(_b2-_b1)/(_a2-_a1); +} + +Coords Buffer::translate(int _x, int _y){ + + + float angle = -cur.r * M_PI / 180.0; + + float rx = (float)rand()/(float)RAND_MAX; + float ry = (float)rand()/(float)RAND_MAX; + + Coords org; // origin point + org.x = ((((float)_x+rx) / (float)width * 2) - 1) * ratio; // X Origin + org.y = (((float)_y+ry) / (float)height * 2) - 1; // Y Origin + + float x = cos(angle)*org.x*cur.s - sin(angle)*org.y*cur.s + cur.x; // New X + float y = sin(angle)*org.x*cur.s + cos(angle)*org.y*cur.s + cur.y; // New Y + + Coords tmpCords = {x, y}; + return tmpCords; +} + +Pixel Buffer::translate(float _x, float _y){ + + float angle = cur.r * M_PI / 180.0; + + Coords org; // origin point + org.x = cos(angle)*(_x-cur.x)/cur.s - sin(angle)*(_y-cur.y)/cur.s; + org.y = sin(angle)*(_x-cur.x)/cur.s + cos(angle)*(_y-cur.y)/cur.s; + + float x = (org.x/ratio + 1) / 2 * width; // New X + float y = (org.y + 1) / 2 * height; // New Y + + Pixel tmpPix = {(int)x, (int)y}; + return tmpPix; +} + + + + +///////// +///////// Render Fractal +///////// + +void Buffer::render(int _x, int _y){ + Coords c = translate(_x, _y); + + float a = c.x; + float b = c.y; + + int n = 0; + float z = 0; + while(n<=itterations){ + float aa = a*a - b*b; + float bb = 2.0 * a * b; + a = aa + c.x; + b = bb + c.y; + if(abs(a + b) > 4){ break; } + + if(fractal==2 || fractal==0){ + Pixel p = translate(a, b); + if(p.x>=0 && p.x<width && p.y>=0 && p.y<height){ + buffer[p.x][p.y] += 1; + if(buffer[p.x][p.y]>maxValue){ maxValue = buffer[p.x][p.y]; } + } + } + + n++; + } + if(fractal==1 || fractal==0){ + if(n >= itterations){ n=0; } + buffer[_x][_y] += n; + if(buffer[_x][_y] > maxValue){ maxValue = buffer[_x][_y]; } + } +} diff --git a/src/fractal/buffer.h b/src/fractal/buffer.h new file mode 100755 index 0000000..4a13416 --- /dev/null +++ b/src/fractal/buffer.h @@ -0,0 +1,78 @@ +#ifndef BUFFER_H_ +#define BUFFER_H_ + +#include <iostream> +#include <cmath> +#include <cstdio> +#include <sstream> +#include <string> +#include <vector> + + +#define M_PI 3.14159265358979323846 /* pi */ + + +#define ALL 0 +#define MANDELBROT 1 +#define BUDDHABROT 2 +#define BUDDHABULB 3 + + +struct Cur{ + float x; // X position of cursur + float y; // Y position of cursur + float s; // Scale of cursur + float r; // Rotation of cursur +}; + +struct Coords{ + float x; + float y; +}; + +struct Pixel{ + int x; + int y; +}; + + +class Buffer{ +private: + std::vector<std::vector<int>> buffer; // Buffer array + Cur cur; // Viewing cursur + Cur start; + Cur end; + float ratio; // Ratio of image width to hight + int itterations; // Number of itterations for render (defult 255) + float contrast; // Log contrast of render output (defult 2) + int maxValue; // Maximum value of array to normalise + unsigned char fractal; // Fractal type +public: + int width; // Width of buffer + int height; // Height of buffer + int samples; // Rendering subresolution (defult 2) + + Buffer(int _width, int _height); // Constructor + void save(std::string _filename); // Save buffer to PPM image + void clear(); // Clear buffer + std::string stats(); // Print buffer stats to console + + int getMax(); // Return max value in buffer + void setItterations(int _itterations); // Set number of render itterations + void setSamples(int _subres); // Set subresolution of render + void setContrast(float _contrast); // Set contast of output image + void setFractal(unsigned char _fractal); // set type of fractal to render + + void setCursor(float _x, float _y, float _s, float _r); + void setStart(float _x, float _y, float _s, float _r); + void setEnd(float _x, float _y, float _s, float _r); + void cursorUpdate(float _f); + Coords translate(int _x, int _y); + Pixel translate(float _x, float _y); + float map(float _v, float _a1, float _a2, float _b1, float _b2); + + void render(int _x, int _y); +}; + + +#endif diff --git a/src/fractal/timer.cpp b/src/fractal/timer.cpp new file mode 100755 index 0000000..525c7dd --- /dev/null +++ b/src/fractal/timer.cpp @@ -0,0 +1,33 @@ +#include "timer.h" + + +Timer::Timer(){ + startTime = clock(); + std::cout << startTime << std::endl; +} + + +std::string Timer::getTime(){ + clock_t elapsedTime = (clock() - startTime) / CLOCKS_PER_SEC; + + unsigned char seconds = elapsedTime % 60; + unsigned char minutes = (elapsedTime / 60) % 60; + unsigned char hours = (elapsedTime / 3600) % 24; + unsigned char days = elapsedTime / 86400; + + std::string tmpString = ""; + + if(days<10){ tmpString += "0"; } + tmpString += std::to_string(days); + + if(hours<10){ tmpString += ":0"; }else{ tmpString+=":"; } + tmpString += std::to_string(hours); + + if(minutes<10){ tmpString += ":0"; }else{ tmpString+=":"; } + tmpString += std::to_string(minutes); + + if(seconds<10){ tmpString += ":0"; }else{ tmpString+=":"; } + tmpString += std::to_string(seconds); + + return tmpString; +} diff --git a/src/fractal/timer.h b/src/fractal/timer.h new file mode 100755 index 0000000..f07ef8e --- /dev/null +++ b/src/fractal/timer.h @@ -0,0 +1,18 @@ +#ifndef TIMER_H_ +#define TIMER_H_ + +#include <ctime> +#include <iomanip> +#include <iostream> +#include <sstream> +#include <string> + +class Timer{ +private: + clock_t startTime; +public: + Timer(); + std::string getTime(); +}; + +#endif diff --git a/src/main.cpp b/src/main.cpp new file mode 100755 index 0000000..681f8c0 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,40 @@ +#include "main.h" + +Buffer buffer(1920, 1080); + +int main(int argc, char** argv){ + + Timer timer; + + buffer.clear(); + buffer.setContrast(2); + buffer.setSamples(8); + buffer.setItterations(255); + buffer.setFractal(ALL); + + buffer.setStart(0, 0, 1, -10); + buffer.setEnd(0, 0, 0.8, 15); + + std::cout << std::endl << buffer.stats() << std::endl << std::endl; + + int frames = 200; + for(int f=0; f<=frames; f++){ + + buffer.clear(); + buffer.cursorUpdate( (float)f/(float)frames ); + for(int y=0; y<buffer.height; y++){ + for(int x=0; x<buffer.width; x++){ + for(int s=0; s<buffer.samples; s++){ + buffer.render(x, y); + } + } + std::cout << " " << timer.getTime() << " Frame: " << f << " " << 100*y/buffer.height << "% maxValue: " << buffer.getMax() << " \r" << std::flush; + } + std::ostringstream filename; + filename << "output/frames/image_" << std::setfill('0') << std::setw(5) << f << ".ppm"; + buffer.save( filename.str() ); + } + + std::cout << std::endl << std::endl << "Finished!" << std::endl << std::endl; + return 0; +} diff --git a/src/main.h b/src/main.h new file mode 100755 index 0000000..72c965a --- /dev/null +++ b/src/main.h @@ -0,0 +1,13 @@ +#ifndef MAIN_H_ +#define MAIN_H_ + +#include <cmath> +#include <iomanip> +#include <iostream> +#include <thread> + +#include "fractal/buffer.h" +#include "fractal/buddhabulb.h" +#include "fractal/timer.h" + +#endif