This is MartinView.m in view mode; [Download] [Up]
#import "MartinView.h" #import "Thinker.h" #import <math.h> #import <libc.h> #import <streams/streams.h> #import <defaults/defaults.h> #import <appkit/color.h> #import <appkit/graphics.h> #import <dpsclient/wraps.h> #import <appkit/Button.h> #import <appkit/Application.h> /* MartinView: a BackSpace.app v3.0 module by Jeffrey Adams * version 1.0 jeffa@wri.com */ char fname[Nfunc][16] = { "martin1", "martin2", "ejk1", "ejk2" }; /* The file used to store remembered fractals */ char fileName[] = "/.martinView"; @implementation MartinView /* Implemented so you can screen grab the image if you want to (at least I wanted to!) */ - pause:sender { isPaused = [sender state]; return self; } /* Inherited method for setting the graphics state before sending OneSteps */ - didLockFocus { NXSetColor(currColor); return self; } - oneStep { NXRect *currentPixel = pixels; if (isPaused) return self; /* Stay in here until we hit our flush buffer limit or we hit the maximum total points allowed */ while ((++nd < nD) && (++nP < mxP)) { switch (Function) { case Ejk1: x1 = y - ( (x>0) ? (B*x-C) : -(B*x-C) ); break; case Martin1: x1 = y - ( (x<0) ? sqrt(fabs(B*x-C)) : -sqrt(fabs(B*x-C)) ); break; case Ejk2: x1 = y - ( (x<0) ? log(fabs(B*x-C)) : -log(fabs(B*x-C)) ); break; case Martin2: x1 = y - sin(x); break; } y = A - x; x=x1; /* seed perturbation */ if (Pn && ++pn > Pn) { x += (x>0) ? -Pv : Pv; y += (y>0) ? -Pv : Pv; pn = 0; } /* Do we need to change the color? */ if (++nc > nC) { color = (color+1)%Ncolors; /* Since we are changing color, send buffered points to screen */ if (numPixels) { NXRectFillList(pixels, numPixels); numPixels = 0; currentPixel = pixels; } currColor = (Randomcolor) ? ((Color) ? NXConvertRGBToColor(Ranf(), Ranf(), Ranf()) : NXConvertGrayToColor(Ranf())) : colors[color]; NXSetColor(currColor); nc = 0; } /* If we are not within the screen range, do not store them */ iy = cy + Zf*y; if (iy < 0 || iy > mxY) continue; ix = cx + Zf*x; if (ix < 0 || ix > mxX) continue; /* Update the data needed for the NXRectFillList */ currentPixel->origin.x = ix; currentPixel->origin.y = iy; ++numPixels; ++currentPixel; /* Have we hit the in-range limit, if so, send the buffer to the screen */ if (++np > mxp) { if (numPixels) { NXRectFillList(pixels, numPixels); numPixels = 0; currentPixel = pixels; } [self newOne:self]; break; } } nd = 0; /* Flush buffer full, display pixels */ if (numPixels) { NXRectFillList(pixels, numPixels); numPixels = 0; currentPixel = pixels; } /* If we left because we hit max total limit, give us a new one */ if(nP == mxP) [self newOne:self]; return self; } - newOne:sender { double A1, B1, C1; /* 2nd part of parameter range */ char name[15],str[20]; NXStream *stream; int i; [self display]; if (!smallInspect) return nil; /* Record current settings in Defaults database */ sprintf(str,"%d", ([funcAuto state]) ? -1 : Function); NXWriteDefault([NXApp appName], "MartinFunction", str); sprintf(str,"%d", ([maxTotFlag state]) ? -1 : [maxTotalPts intValue]); NXWriteDefault([NXApp appName], "MartinMaxTot", str); sprintf(str,"%d", ([maxInFlag state]) ? -1 : [maxInRangePts intValue]); NXWriteDefault([NXApp appName], "MartinMaxIn", str); sprintf(str,"%d", ([colFlag state]) ? -1 : [colInterval intValue]); NXWriteDefault([NXApp appName], "MartinColorInt", str); np = 0; nP = 0; nd = 0; numPixels=0; x = y = 0; color = -1; Ranfset(time(0)); W = (int)bounds.size.width; H = (int)bounds.size.height; mxX = W-1; mxY = H-1; /* If we are using a file, load the settings from '.martinView' */ if (streamPos >= 0) { if (!(stream = NXMapFile(file, NX_READONLY))) { streamPos = -1; [useFileFlag setState:NO]; [self newOne:self]; return self; } for (i=0; i <= streamPos; ++i) { if(NXAtEOS(stream)){ streamPos = 0; i=-1; NXSeek(stream, 0, NX_FROMSTART); if(NXAtEOS(stream)) { streamPos =-1; [useFileFlag setState:NO]; [self newOne:self]; return self; } continue; } NXScanf(stream, "%s\n",name); NXScanf(stream, "%d %le\n",&Pn,&Pv); NXScanf(stream, "%d\n",&Function); NXScanf(stream, "%le %le %le %le\n",&A,&B,&C,&Zf); NXScanf(stream, "%d %d %d\n",&mxp,&mxP,&nC); NXScanf(stream, "%d %d\n",&moveX,&moveY); } streamPos++; NXCloseMemory(stream, NX_FREEBUFFER); } else { if ([seedIntFlag state]) Pn = pow(10., 1+Ranf()*3); else Pn = [seedPertInt intValue]; if ([seedValFlag state]) Pv = pow(10.,Ranf()*3); else Pv = [seedPertVal doubleValue]; /* provide default hopalong parameters if needed */ if ([funcAuto state]) { double r = Ranf(); if (r < 0.40) Function = Martin1; else if (r < 0.70) Function = Ejk1; else if (r < 0.90) Function = Ejk2; else Function = Martin2; } if (Function == Martin1) { if ([aFlag state]) A = 40 + Ranf()*1500; if ([bFlag state]) B = 3 + Ranf()*17; if ([cFlag state]) C = 100 + Ranf()*3000; } else if (Function == Martin2) { if ([aFlag state]) A = 3.075927 + Ranf()*0.14; } else if (Function == Ejk1) { if ([aFlag state]) A = Ranf()*500; if ([bFlag state]) B = Ranf()*.40; if ([cFlag state]) C = 10 + Ranf()*100; } else if (Function == Ejk2) { if ([aFlag state]) A = Ranf()*500; if ([bFlag state]) B = pow(10.,6+Ranf()*24); if ([cFlag state]) C = pow(10., Ranf()*9); } if(![aFlag state]) A = [hopAField doubleValue]; if(![bFlag state]) B = [hopBField doubleValue]; if(![cFlag state]) C = [hopCField doubleValue]; if (A1 = [a1Flag state]) A = Min(A,A1) + Ranf()*(Max(A,A1) - Min(A,A1)); if ([afFlag state] && Ranf()<0.5) A = -A; if (B1 = [b1Flag state]) B = Min(B,B1) + Ranf()*(Max(B,B1) - Min(B,B1)); if ([bfFlag state] && Ranf()<0.5) B = -B; if (C1 = [c1Flag state]) C = Min(C,C1) + Ranf()*(Max(C,C1) - Min(C,C1)); if ([cfFlag state] && Ranf()<0.5) C = -C; if ([magFlag state]) Zf = (Function == Martin2) ? 4.0 : 1.0; else Zf = [magField doubleValue]; if ([maxInFlag state]) mxp = (int) (0.40* (float)(W*H)); else mxp = [maxInRangePts intValue]; if ([maxTotFlag state]) mxP = 4 * mxp; else mxP = [maxTotalPts intValue]; /* color processing */ if ([colFlag state]) nC = (mxP/Ncolors)/2; else nC = [colInterval intValue]; } nc = nC; cx = W/2+moveX; cy = H/2+moveY; [displaceX setIntValue:moveX]; [displaceY setIntValue:moveY]; [seedPertInt setIntValue:Pn]; [seedPertVal setDoubleValue:Pv]; [dynamFlush setIntValue:nD]; [funcButton setTitle:fname[Function]]; [hopAField setDoubleValue:A]; [hopBField setDoubleValue:B]; [hopCField setDoubleValue:C]; [magField setDoubleValue:Zf]; [maxInRangePts setIntValue:mxp]; [maxTotalPts setIntValue:mxP]; [colInterval setIntValue:nC]; return self; } - changeFunc:sender { char str[10]; Function = [sender selectedTag]; [funcAuto setState:NO]; sprintf(str,"%d", Function); NXWriteDefault([NXApp appName], "MartinFunction", str); [self newOne:sender]; return self; } - changeDynam:sender { nD = [sender intValue]; if ((nD <1) || (nD > MAXDYNAMPOINTS)) nD = MAXDYNAMPOINTS; [dynamFlush setIntValue:nD]; [self makeNewDynam:nD]; [self newOne:sender]; return self; } /* We create the array of NXRects ahead of time so we do not waste time building the array up as we go along */ - makeNewDynam:(int)num { NXRect *curr; NXSize pixSize = {1,1}; if (pixels) free(pixels); pixels = (NXRect *)malloc(sizeof(NXRect)*(num+1)); for (curr = pixels; curr-pixels < num; ++curr) curr->size = pixSize; return self; } - setHopA:sender { if ([sender doubleValue] > 0) [aFlag setState:NO]; [self newOne:sender]; return self; } - setHopB:sender { if ([sender doubleValue] > 0) [bFlag setState:NO]; [self newOne:sender]; return self; } - setHopC:sender { if ([sender doubleValue] > 0) [cFlag setState:NO]; [self newOne:sender]; return self; } - setSeedInt:sender { if ([sender intValue] > 0) [seedIntFlag setState:NO]; [self newOne:sender]; return self; } - setMagnification:sender { if ([sender doubleValue] >= 0) [magFlag setState:NO]; [self newOne:sender]; return self; } - setSeedVal:sender { if ([sender doubleValue] >= 0) [seedValFlag setState:NO]; [self newOne:sender]; return self; } - setDisplacement:sender { moveX = [displaceX intValue]; moveY = [displaceY intValue]; [self newOne:sender]; return self; } - setColChange:sender { char str[30]; if ([sender intValue] > 0) { [colFlag setState:NO]; sprintf(str,"%d", [sender intValue]); NXWriteDefault([NXApp appName], "MartinColorInt", str); } [self newOne:sender]; return self; } - setMaxTot:sender { char str[30]; if ([sender intValue] > 0) { [maxTotFlag setState:NO]; sprintf(str,"%d", [sender intValue]); NXWriteDefault([NXApp appName], "MartinMaxTot", str); } [self newOne:sender]; return self; } - setMaxIn:sender { char str[30]; if ([sender intValue] > 0) { [maxInFlag setState:NO]; sprintf(str,"%d", [sender intValue]); NXWriteDefault([NXApp appName], "MartinMaxIn", str); } [self newOne:sender]; return self; } - setRandomColor:sender { char str[10]; Randomcolor = [sender state]; sprintf(str,"%d", Randomcolor); NXWriteDefault([NXApp appName], "MartinRandomCol", str); [self newOne:sender]; return self; } - changeColorMode:sender { int newColMode; char str[10]; newColMode = [sender selectedTag]; if (Color != newColMode) { Color = newColMode; [self convertColors]; sprintf(str,"%d",Color); NXWriteDefault([NXApp appName], "MartinColorMode", str); } [self newOne:self]; return self; } /* Weak way of changing from nonrandom color array to nonrandom gray array */ - convertColors { if (Color){ Ncolors = DEFAULTNUMCOLORS; colors[0] = NX_COLORBLUE; colors[1] = NX_COLORBROWN; colors[2] = NX_COLORWHITE; } else{ Ncolors = 3; colors[0] = NX_COLORWHITE; colors[1] = NX_COLORDKGRAY; colors[2] = NX_COLORLTGRAY; } return self; } /* Append the current fractal info (all of it) in the data file */ - remember:sender { NXStream *stream; if (!(stream = NXMapFile(file, NX_WRITEONLY))) { stream = NXOpenMemory(NULL, 0, NX_WRITEONLY); } NXSeek(stream, 0, NX_FROMEND); NXPrintf(stream, "MartinView\n"); NXPrintf(stream, "%d %.15le\n",Pn,Pv); NXPrintf(stream, "%d\n",Function); NXPrintf(stream, "%.15le %.15le %.15le %.15le\n",A,B,C,Zf); NXPrintf(stream, "%d %d %d\n",mxp,mxP,nC); NXPrintf(stream, "%d %d\n",moveX,moveY); NXSaveToFile(stream, file); NXCloseMemory(stream, NX_FREEBUFFER); return self; } - useFile:sender { NXStream *stream; char name[15],str[10]; if ([sender state]) { if (!(stream = NXMapFile(file, NX_READONLY))) { [sender setState:NO]; streamPos = -1; [self newOne:self]; } else { NXScanf(stream, "%s\n",name); if (strcmp("MartinView",name)) { [sender setState:NO]; streamPos = -1; } else streamPos = 0; NXCloseMemory(stream, NX_FREEBUFFER); [self newOne:self]; } } else { streamPos = -1; [self newOne:self]; } sprintf(str,"%d",[sender state]); NXWriteDefault([NXApp appName], "MartinUseFile", str); return self; } - initFrame:(NXRect *)frameRect { [super initFrame:frameRect]; [self allocateGState]; // For faster lock/unlockFocus strcpy(file,NXHomeDirectory()); strcat(file,fileName); srandom(getpid()); isPaused = 0; Ncolors = DEFAULTNUMCOLORS; colors = (NXColor *)malloc(sizeof(NXColor)*Ncolors); colors[0] = NX_COLORBLUE; colors[1] = NX_COLORBROWN; colors[2] = NX_COLORWHITE; colors[3] = NX_COLORCYAN; colors[4] = NXConvertRGBToColor(250,128, 114); colors[5] = NX_COLORGRAY; colors[6] = NX_COLORGREEN; colors[7] = NXConvertRGBToColor(255,87, 33); colors[8] = NX_COLORMAGENTA; colors[9] = NX_COLORORANGE; colors[10] = NX_COLORPURPLE; colors[11] = NX_COLORRED; colors[12] = NXConvertRGBToColor(227,207, 87); colors[13] = NX_COLORYELLOW; moveX = 0; moveY = 0; Ranfseed=4326; nD = STARTDYNAMPOINTS; [self makeNewDynam:nD]; return self; } - inspectorWillBeRemoved { [myPrefPanel orderOut:self]; return self; } - inspector:sender { char buf[MAXPATHLEN]; int value; if (!smallInspect) { sprintf(buf,"%s/MartinPrefs.nib",[sender moduleDirectory:"Martin"]); [NXApp loadNibFile:buf owner:self withNames:NO]; Function=atoi(NXGetDefaultValue([NXApp appName], "MartinFunction")); if (Function == -1) [funcAuto setState:YES]; else { [funcAuto setState:NO]; [funcButton setTitle:fname[Function]]; } if ((value = atoi(NXGetDefaultValue([NXApp appName], "MartinMaxTot"))) == -1) [maxTotFlag setState:YES]; else { [maxTotFlag setState:NO]; [maxTotalPts setIntValue:value]; } if ((value = atoi(NXGetDefaultValue([NXApp appName], "MartinMaxIn"))) == -1) [maxInFlag setState:YES]; else { [maxInFlag setState:NO]; [maxInRangePts setIntValue:value]; } if ((value = atoi(NXGetDefaultValue([NXApp appName], "MartinColorInt"))) == -1) [colFlag setState:YES]; else { [colFlag setState:NO]; [colInterval setDoubleValue:value]; } Randomcolor = atoi(NXGetDefaultValue([NXApp appName], "MartinRandomCol")); [randomFlag setState:Randomcolor]; Color=atoi(NXGetDefaultValue([NXApp appName], "MartinColorMode")); if (Color) [colorButton setTitle:"Color"]; else [colorButton setTitle:"Mono"]; [self convertColors]; currColor = (Randomcolor) ? ((Color) ? NXConvertRGBToColor(Ranf(), Ranf(), Ranf()) : NXConvertGrayToColor(Ranf())) : colors[0]; [useFileFlag setState:atoi(NXGetDefaultValue([NXApp appName], "MartinUseFile"))]; if ([useFileFlag state]) [self useFile:useFileFlag]; else { streamPos =-1; [self newOne:self]; } } return smallInspect; } + initialize { static NXDefaultsVector MartinViewDefaults = {{"MartinFunction", "-1"}, {"MartinMaxTot", "-1"},{"MartinMaxIn", "-1"}, {"MartinColorInt", "-1"},{"MartinRandomCol", "1"},{"MartinColorMode", "1"}, {"MartinUseFile", "0"},{NULL,NULL} }; NXRegisterDefaults([NXApp appName], MartinViewDefaults); return self; } - sizeTo:(NXCoord)width :(NXCoord)height { [super sizeTo:width :height]; [self newOne:self]; return self; } - drawSelf:(const NXRect *)rects :(int)rectCount { if (!rects || !rectCount) return self; PSsetgray(0.0); NXRectFill(rects); // black screen return self; } - free { if (pixels) free(pixels); if (Ncolors) free(colors); return [super free]; } /* Why not a little fluff */ - windowWillMiniaturize:sender toMiniwindow:miniwindow { [sender setMiniwindowIcon:"MartinMini"]; return self; } - (BOOL) useBufferedWindow { return NO; } - (const char *) windowTitle { return ( const char * ) "Martin Fractals";} @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.