This is Colormap.m in view mode; [Download] [Up]
/* * File: Colormap.m * Module: Mandelbrot * Author: R. Dunbar Poor * Last Edit: Mon Sep 10 1990 * * You may freely copy, distribute and reuse the code in this example. NeXT * disclaims any warranty of any kind, expressed or implied, as to its fitness * for any particular use. */ #import "Colormap.h" #import <stdlib.h> /* for malloc, free */ #import <appkit/color.h> /* for NXSetColor stuff */ #import <appkit/graphics.h> /* for NXRect, etc */ #import <appkit/Cell.h> /* for floatValue, etc */ #import <appkit/View.h> /* for -bounds */ #import <appkit/Menu.h> /* for itemList */ #import <appkit/Matrix.h> /* for selectedRow */ #import <dpsclient/psops.h> /* for PSxxx functions */ #import <appkit/Application.h> /* for appDidInit */ #import <appkit/NXColorWell.h> /* for appDidInit */ #import <math.h> /* for cos, M_PI */ static float warp(float x, float xp) /* * Warp takes an x value between 0 and 1, and "warps" it towards 0 * or 1 depending on the value of xp. When xp is close to zero, all * but the smallest values of x are mapped to 1.0. When xp is close * to 1, all but the largest values of x are mapped to 0.0. When xp * is .5, warp is an identity function. * * Looked at another way, warp is a piecewise linear approximation of * the function x^(xp*k). */ { if (x > xp) { /* return a point on the line between (xp,1-xp) and (1,1) */ return (xp * (x - 2) + 1) / (1 - xp); } else { /* return a point on the line between (0,0) and (xp,1-xp) */ return x * (1 - xp) / xp; } } static void setup_map(float *map, int npoints, float freq, float phase, float curve) /* * setup_map is an auxiliary routine to initialize one color in the * color map. map is the pointer to the base of the color map, we * assume the colors are interleaved N_COLORS to 1 */ { int i; float phase0, freq0; phase0 = phase*2*M_PI; freq0 = freq*2*M_PI/npoints; for (i=0; i<npoints; i++) { float s = (1 + cos(phase0 + i*freq0)) * .5; map[N_COLORS*i] = warp(s,curve); } } @implementation Colormap:Object - free { if (map) free(map); if (cMap) free(cMap); return [super free]; } - setup:sender { id field; [self setMapLength:DEFAULT_MAP_LENGTH]; [[[colorSelect target] itemList] selectCellWithTag:RED_TAG]; field = [forms findCellWithTag:FREQUENCY_TAG]; [field setFloatingPointFormat:YES left:2 right:3]; field = [forms findCellWithTag:PHASE_TAG]; [field setFloatingPointFormat:YES left:2 right:3]; field = [forms findCellWithTag:CURVE_TAG]; [field setFloatingPointFormat:YES left:2 right:3]; return self; } - (int)mapLength { return mapLength/N_COLORS; } - setMapLength:(int)length { if (length <= 0) return nil; if ((length != mapLength) || (map == (float *)nil)) { mapLength = length; if (map) free(map); if (cMap) free(cMap); map = (float *)malloc(mapLength * sizeof(float) * N_COLORS); cMap = (NXColor *)malloc(mapLength * sizeof(NXColor)); } return self; } - changeColor:sender /* * change one of the frequency instance variables */ { float value, freq, phase, curve; int color, tag; color = [[[colorSelect target] itemList] selectedTag]; tag = [[sender selectedCell] tag]; value = [[sender selectedCell] floatValue]; /* extract freq, phase, curve info */ if (tag==FREQUENCY_TAG) { freq = value; } else { freq = [[forms findCellWithTag:FREQUENCY_TAG] floatValue]; } if (tag==PHASE_TAG) { phase = value; } else { phase = [[forms findCellWithTag:PHASE_TAG] floatValue]; } if (tag==CURVE_TAG) { curve = value; } else { curve = [[forms findCellWithTag:CURVE_TAG] floatValue]; } /* write new values into the colormap and update the display */ [self setColor:color :freq :phase :curve]; [self updateFields:self]; [self updateMap:self]; return self; } - setColor:(int)color :(float)freq :(float)phase :(float)curve /* * Build the color map. Does NOT update the sliders, fields and mapView. */ { switch(color) { case RED_TAG: redFreq = freq; redPhase = phase; redCurve = curve; setup_map(&map[0],mapLength,redFreq,redPhase,redCurve); break; #if (N_COLORS == 3) case GREEN_TAG: greenFreq = freq; greenPhase = phase; greenCurve = curve; setup_map(&map[1],mapLength,greenFreq,greenPhase,greenCurve); break; case BLUE_TAG: blueFreq = freq; bluePhase = phase; blueCurve = curve; setup_map(&map[2],mapLength,blueFreq,bluePhase,blueCurve); break; #endif } return self; } - setColors:(float)rf :(float)rp :(float)rc :(float)gf :(float)gp :(float)gc :(float)bf :(float)bp :(float)bc /* * Set up the internal colors. DOES update the sliders, fields, and mapView. */ { [self setColor:RED_TAG :rf :rp :rc]; [self setColor:GREEN_TAG :gf :gp :gc]; [self setColor:BLUE_TAG :bf :bp :bc]; [self updateFields:self]; [self updateMap:self]; [self updateChaosView:self]; return self; } - updateFields:sender /* * update the sliders, fields from the internal instance variables */ { float freq, phase, curve; /* extract the current freq, phase, curve information */ switch ([[[colorSelect target] itemList] selectedTag]) { case RED_TAG: default: freq = redFreq; phase = redPhase; curve = redCurve; break; case GREEN_TAG: freq = greenFreq; phase = greenPhase; curve = greenCurve; break; case BLUE_TAG: freq = blueFreq; phase = bluePhase; curve = blueCurve; break; } /* update the sliders and form cells */ [[sliders findCellWithTag:FREQUENCY_TAG] setFloatValue:freq]; [[sliders findCellWithTag:PHASE_TAG] setFloatValue:phase]; [[sliders findCellWithTag:CURVE_TAG] setFloatValue:curve]; [[forms findCellWithTag:FREQUENCY_TAG] setFloatValue:freq]; [[forms findCellWithTag:PHASE_TAG] setFloatValue:phase]; [[forms findCellWithTag:CURVE_TAG] setFloatValue:curve]; return self; } - updateMap:sender /* * update the mapView from the internal color map */ { NXRect bbox; int i; [mapView lockFocus]; [mapView getBounds:&bbox]; bbox.size.width /= mapLength; for (i=0;i<mapLength;i++) { if (![isMono state]) cMap[i] = NXConvertRGBToColor(map[3*i+0],map[3*i+1],map[3*i+2]); else // it IS mono... All 3 rgb components the same = gray cMap[i] = NXConvertRGBToColor(map[3*i+0],map[3*i+0],map[3*i+0]); NXSetColor(cMap[i]); NXRectFill(&bbox); bbox.origin.x += bbox.size.width; } [mapView getBounds:&bbox]; PSsetgray(NX_BLACK); NXFrameRect(&bbox); [[mapView window] flushWindow]; [mapView unlockFocus]; return self; } - updateChaosView:sender { float red, green, blue; NXConvertColorToRGB([myWell color], &red, &green, &blue); //We don't want that alpha and Cyan, etc... [thechaosView setColors: cMap: mapLength: NXConvertRGBToColor(red, green, blue)]; return self; } - getnewChaosView:newView { thechaosView = newView; return self; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.