This is PenView.m in view mode; [Download] [Up]
/* Quite some Code came from the Lines Demo.
100 Generationen Squares stroked 50 sec
"" "" filled 74 sec
100 "" NXSquares filled 19 sec */
#import <dpsclient/wraps.h> // For PS and DPS function prototypes
#import <appkit/Control.h> // For intValue, etc
#import <appkit/Window.h> // We flushWindow at some point
#import <appkit/Application.h> // For NX_BASETHRESHOLD and peek event
#import <appkit/Panel.h>
#import <appkit/NXCursor.h>
#import <appkit/Form.h>
#import <appkit/graphics.h>
#import <appkit/OpenPanel.h>
#import <appkit/SavePanel.h>
#import <stdio.h>
#import "PenView.h"
#define Radius 3.0
#define Abstand 7.0 // 2*Radius +1
@implementation PenView
- open:sender
{
id openPanel;
const char *fileName;
const char *types[2] = {"life", NULL};
FILE *myfile;
int *f=feld1,x,y;
openPanel = [OpenPanel new];
[openPanel allowMultipleFiles:NO];
if ([openPanel runModalForTypes:types]) {
fileName=[openPanel filename];
myfile=fopen(fileName,"rb");
// fread(f,4,Feld_x*Feld_y,myfile);
for(y=1;y<=Win_y;y++){
for(x=1;x <= Win_x;x++){
if (fgetc(myfile)==42){
*(f+x+Offset_x+(y+Offset_y)*Feld_x)=1;
}
else{
*(f+x+Offset_x+(y+Offset_y)*Feld_x)=0;
}
}
fgetc(myfile);
}
fclose(myfile);
}
Redraw=1;
counter=0;
[self display];
[Count setIntValue: counter at:0];
return self;
}
- save:sender
{
id savePanel;
const char *fileName;
FILE *myfile;
int *f=feld1,x,y;
savePanel = [SavePanel new];
[savePanel setRequiredFileType:"life"];
if ([savePanel runModal]) {
fileName=[savePanel filename];
myfile=fopen(fileName,"wb");
// NXRunAlertPanel(NULL, "Couldn't write file", NULL, NULL, NULL);
// fwrite(f,sizeof(int),Feld_x*Feld_y,myfile);
for(y=1;y<=Win_y;y++){
for(x=1;x <= Win_x;x++){
if (*(f+x+Offset_x+(y+Offset_y)*Feld_x)){
fputc(42,myfile);
}
else{
fputc(32,myfile);
}
}
fputc(10,myfile);
}
fclose(myfile);
}
return self;
}
-showInfo:sender
{
if(!infoPanel) {
[NXApp loadNibSection:"info.nib" owner:self];
}
[infoPanel makeKeyAndOrderFront:self];
return self;
}
-initFrame:(const NXRect*)frameRect
{
[super initFrame:frameRect];
pencilCursor=[NXCursor newFromImage:[NXImage newFromSection:"Pipette.tiff"]];
hotSpot.x=0.0;
hotSpot.y=15.0;
[pencilCursor setHotSpot:&hotSpot];
running=NO;
ac=1;
return self;
}
- free
{
/* be sure to stop the timed entry */
if (running) {
DPSRemoveTimedEntry(linesTimedEntry);
}
return [super free];
}
void DrawIt(DPSTimedEntry te, double timeNow, void *data)
{
/* we set data to self so we can call this method from the timed entry */
[(id)data animate];
}
- toggleRun:sender
{
/* start or stop the timed entry (we're called by a two-state button) */
if (running) {
DPSRemoveTimedEntry(linesTimedEntry);
running = NO;
} else {
/* Call the DrawIt() function as often as possible... */
linesTimedEntry = DPSAddTimedEntry(0.0, &DrawIt, self,
NX_BASETHRESHOLD);
running = YES;
}
return self;
}
-square: (float) x:(float) y
{
NXRect mr;
mr.origin.x=x-3.0;
mr.origin.y=y-3.0;
mr.size.width=6.0;
mr.size.height=6.0;
NXRectFill(&mr);
return self;
}
- clearView:sender
{
int x;
int *f=feld1,*f2=feld2;
Redraw=0;
counter=0;
[self display];
for(x=0;x < Feld_x*Feld_y;x++){
*f++=0;
*f2++=0;
}
// ***** Testlinie ******
// for(x=1;x < 72;x++){
// *(feld1+x+30*80)=1;
// }
[Count setIntValue: counter at:0];
return self;
}
-drawSelf:(NXRect*)rects:(int) rectCount
{
int x,y;
int *f=ac?feld1:feld2;
PSsetgray(NX_WHITE);
NXRectFill(&bounds);
PSsetgray(NX_BLACK);
NXFrameRect(&bounds);
if(Redraw==1){
PSnewpath();
for(x=1;x <= Win_x;x++){
for(y=1;y<=Win_y;y++){
if (*(f+x+Offset_x+(y+Offset_y)*Feld_x)){
[self square:(x-1) * Abstand+Radius+2:
(y-1) * Abstand+Radius+2];
}
}
}
}
[window flushWindow];
return self;
}
-resetCursorRects
{
[self addCursorRect:&bounds cursor:pencilCursor];
return self;
}
// A friend of mine develloped this routine on a Atari ST.
// It doesn't look nice but it is about 6 times faster than a nice aproach.
-(void) calc:(int*)f:(int*)p
{
register int x,y,sum;
register int *rp=f,*wp=p+Feld_x+1,*ws;
for(y=1;y<=Feld_y-2;y++)
{
for(x=1;x<=Feld_x-2;x++)
{
ws=rp;
sum=0;
sum+=*ws++;
sum+=*ws++;
sum+=*ws;
ws+=Feld_x-2;
sum+=*ws;
ws+=2;
sum+=*ws;
ws+=Feld_x-2;
sum+=*ws++;
sum+=*ws++;
sum+=*ws;
*wp=0;
if(*(rp+Feld_x+1) && sum>1 && sum<4)
{
*wp=1;
}
if(!*(rp+Feld_x+1) && sum==3)
*wp=1;
wp++;
rp++;
}
wp+=2;
rp+=2;
}
}
- animate
/*
* animate gets called over and over by the timed entry. It does the main
* animation. Double-buffering is achieved by:
* -drawing the current state in WHITE in the backstore of our buffered window
* -computing the next state and making it the current state
* -drawing the current state in BLACK in the backstore of our buffered window
* -flushing the window...
*
* Note that this method gets called everytime the timed entry fires. The first
* thing this method does is to lock the focus; the last thing it does is to
* unlock the focus. Unfortunately, locking and unlocking the focus can be
* expensive; thus, to avoid this problem, we sit in a tight loop animating
* (with the focus locked) until we detect some event. Then we exit the animate
* method, and, unless the user broke the animation, we are assured that this
* method will be called asap by the timed entry. Another way to deal with the
* lock/unlockFocus expense might be to allocate a graphics state with
* allocateGState. (BreakApp example does both these tricks.)
*/
{
NXEvent dummyEvent; // For peeking at the event queue.
[self lockFocus];
do {
counter++;
[self calc:feld1:feld2];
Redraw=1;
ac=0;
[Count setIntValue: counter at:0];
[self display];
[self calc:feld2:feld1];
Redraw=1;
ac=1;
[self display];
} while ([NXApp peekNextEvent:NX_ALLEVENTS
into:&dummyEvent
waitFor:0.0
threshold:NX_BASETHRESHOLD] == NULL);
[self unlockFocus];
return self;
}
-mouseDown:(NXEvent*)theEvent
{
NXPoint currentPos;
NXEvent *nextEvent;
BOOL looping=1;
int oldMask;
int checkMask,tempx,tempy;
oldMask=[window eventMask];
checkMask= NX_MOUSEUPMASK|NX_MOUSEDRAGGEDMASK;
[window setEventMask:(oldMask| checkMask)];
[self lockFocus];
PSsetlinewidth(1.0);
while(looping){
nextEvent=[NXApp getNextEvent:checkMask];
looping=(nextEvent->type != NX_MOUSEUP);
currentPos=nextEvent->location;
[self convertPoint:¤tPos fromView:nil];
tempx=(int)((currentPos.x-2)/Abstand);
tempy=(int)((currentPos.y-2)/Abstand);
PSnewpath();
*(feld1+(tempy+Offset_y+1)*Feld_x+tempx+Offset_x+1)^=1;
Redraw=1;
[self display];
[window flushWindow];
} // end while
[self unlockFocus];
[window setEventMask: oldMask];
return self;
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.