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.