Created
May 4, 2022 00:20
-
-
Save silicontrip/815b6b84d5f46831d5bd57178a1469ea to your computer and use it in GitHub Desktop.
Mandelbrot animator
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <complex.h> | |
#include <stdio.h> | |
#import <Cocoa/Cocoa.h> | |
#import <Foundation/Foundation.h> | |
#import <unistd.h> | |
NSColor* colourWithHSV(float h, float s, float v) | |
{ | |
double r, g, b; | |
double j; | |
double f, p, q, t; | |
/* convert HSV back to RGB */ | |
if (s==0.0) | |
{ | |
return [NSColor colorWithCalibratedRed:v green:v blue:v alpha:1.0]; | |
} else { | |
while (h > 1.0) h -= 1.0; | |
while (h < 0) h += 1.0; | |
if (h==1.0) h = 0.0; | |
j = floor(h*6.0); | |
p = v * (1-s); | |
f = h * 6.0 - j; | |
q = v * (1 - (s*f)); | |
t = v * (1 - (s*(1 - f))); | |
if (j < 0.5) | |
return [NSColor colorWithCalibratedRed:v green:t blue:p alpha:1.0]; | |
if (j < 1.5) | |
return [NSColor colorWithCalibratedRed:q green:v blue:p alpha:1.0]; | |
if (j < 2.5) | |
return [NSColor colorWithCalibratedRed:p green:v blue:t alpha:1.0]; | |
if (j < 3.5) | |
return [NSColor colorWithCalibratedRed:p green:q blue:v alpha:1.0]; | |
if (j < 4.5) | |
return [NSColor colorWithCalibratedRed:t green:p blue:v alpha:1.0]; | |
if (j < 5.5) | |
return [NSColor colorWithCalibratedRed:v green:p blue:q alpha:1.0]; | |
return [NSColor colorWithCalibratedRed:v green:t blue:p alpha:1.0]; | |
} | |
} | |
//NSDictionary<NSString*,id>* getOptions (int argc, char *const * argv, NSString* arg) | |
NSDictionary* getOptions (int argc, char *const * argv, NSString* arg) | |
{ | |
NSMutableDictionary* toptions = [NSMutableDictionary dictionaryWithCapacity:3]; | |
NSMutableArray *targuments = [NSMutableArray arrayWithCapacity:3]; | |
if (argc > 0) | |
{ | |
int k; | |
while ((k=getopt(argc,argv,[arg UTF8String])) != -1) | |
{ | |
NSString* strarg = [NSString stringWithFormat:@"%c",k]; | |
if (optarg==NULL) | |
{ | |
[toptions setObject:@"" forKey:strarg]; | |
} else { | |
NSString* stropt = [NSString stringWithUTF8String:optarg]; | |
[toptions setObject:stropt forKey:strarg]; | |
} | |
// the rest are positional arguments | |
} | |
argc -= optind; | |
argv += optind; | |
int i; | |
for (i=0; i < argc; ++i) | |
[targuments addObject:[NSString stringWithUTF8String:argv[i]]]; | |
[toptions setObject:[NSArray arrayWithArray:targuments] forKey:@"ARGS"]; | |
// how do we return both of these? | |
return [NSDictionary dictionaryWithDictionary:toptions]; | |
//arguments = [NSArray arrayWithArray:targuments]; | |
} | |
return [[NSDictionary new] autorelease]; | |
} | |
int main(int argc, char* argv[]) | |
{ | |
NSAutoreleasePool *p1 = [NSAutoreleasePool new]; | |
// NSDictionary<NSString*,id>* options = getOptions(argc,argv,@"Z:z:o:x:y:W:H:f:h"); | |
NSDictionary* options = getOptions(argc,argv,@"Z:z:o:x:y:W:H:f:h"); | |
if ([options objectForKey:@"h"]) | |
{ | |
NSLog(@"-Z zoomPerFrame -z zoomLevelStart -o fileName -x xcoordinate -y ycoordinate -W width -H height -f frames"); | |
exit(-1); | |
} | |
double zoom = 4.0 / 1080; | |
double cox = 0; | |
double coy = 0; | |
int sizex = 1920; | |
int sizey = 1080; | |
int frameCount = 1; | |
double zpf = 0.95; | |
NSString* fileName = @"mand"; | |
if ([options objectForKey:@"Z"]) | |
zpf = [[options objectForKey:@"Z"] floatValue]; | |
if ([options objectForKey:@"o"]) | |
fileName = [options objectForKey:@"o"]; | |
if ([options objectForKey:@"z"]) | |
zoom = [[options objectForKey:@"z"] floatValue]; | |
if ([options objectForKey:@"x"]) | |
cox = [[options objectForKey:@"x"] floatValue]; | |
if ([options objectForKey:@"y"]) | |
coy = [[options objectForKey:@"y"] floatValue]; | |
if ([options objectForKey:@"W"]) | |
sizex = [[options objectForKey:@"W"] intValue]; | |
if ([options objectForKey:@"H"]) | |
sizey = [[options objectForKey:@"H"] intValue]; | |
if ([options objectForKey:@"f"]) | |
frameCount = [[options objectForKey:@"f"] intValue]; | |
NSBitmapImageRep *outrep = [[NSBitmapImageRep alloc] | |
initWithBitmapDataPlanes: NULL | |
pixelsWide: sizex | |
pixelsHigh: sizey | |
bitsPerSample: 8 | |
samplesPerPixel: 3 | |
hasAlpha: NO | |
isPlanar: NO | |
colorSpaceName: NSDeviceRGBColorSpace | |
bytesPerRow: sizex * 3 | |
bitsPerPixel: 24]; | |
// float st = 4.0 / 1280; | |
float cl; | |
float ss; | |
float vv; | |
int count; | |
NSColor *nsc; | |
complex double c; | |
complex double z; | |
double x; | |
double y; | |
int yp; int xp; | |
int fc; | |
for (fc = 0; fc < frameCount; fc++) | |
{ | |
NSLog(@"frame: %d X: %f-%f Y: %f-%f", | |
fc, | |
(-sizex / 2) * zoom + cox, | |
(sizex / 2) * zoom + cox, | |
(-sizey / 2) * zoom + coy, | |
(sizey / 2) * zoom + coy | |
); | |
NSAutoreleasePool *p2 = [NSAutoreleasePool new]; | |
for(yp=0; yp<sizey; yp++) { | |
for(xp=0; xp<sizex; xp++) { | |
x = (xp - sizex / 2) * zoom + cox; | |
y = (yp - sizey / 2) * zoom + coy; | |
// NSLog(@"xp: %d yp: %d xs: %f ys: %f",xp,yp,x,y); | |
c = x + y * I; | |
z=0; | |
count =0; | |
while(cabs(z) < 2.0 && count < 256) | |
{ | |
z = (z * z) + c; | |
count ++; | |
} | |
cl = 1.0 * count / 256.0; | |
ss = 1.0 * count / 8.0; | |
if (ss>1.0) ss = 1.0; | |
vv = 1.0 * (256 - count) / 8.0; | |
if (vv>1.0) vv = 1.0; | |
nsc = colourWithHSV(cl, ss, vv); | |
[outrep setColor:nsc atX:xp y:yp]; | |
//[nsc autorelease]; | |
} | |
} | |
// NSLog(@"outrep rc: %lu",[outrep retainCount]); | |
NSDictionary *prop = nil; | |
//NSData *dd = [outrep representationUsingType:NSBitmapImageFileTypePNG properties:prop]; | |
NSData *dd = [outrep representationUsingType:NSPNGFileType properties:prop]; | |
// NSLog(@"data rc: %lu",[dd retainCount]); | |
NSString* fns = [NSString stringWithFormat:@"%@%03d.png",fileName,fc]; | |
// NSLog(@"fns rc: %lu",[fns retainCount]); | |
[dd writeToFile:fns atomically: NO]; | |
[p2 release]; | |
zoom = zoom * zpf; | |
} | |
[p1 release]; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I should've added comments on the two critical lines at the heart of the algorithm. Line 191 sets the coordinate to test. And line 198 is the Mandelbrot iterator. Z remains inside the boundary for 256 iterations, it's deemed part of the Mandelbrot set and shown in Black. otherwise the colour is determined by the number of iterations it took to cross the boundary and is therefore not part of the Mandelbrot set. The number of iterations give the image its striking colours.