This is NeXTView.m in view mode; [Download] [Up]
#import "NeXTView.h"
#import <math.h>
#import "WireFrame.h"
#import <sys/dir.h>
#import <sys/types.h>
#import <objc/NXBundle.h>
// this code is copyright Darcy Brockbank, 1993
//
// You may freely reuse and distribute this code in any way shape or
// form, provided that this notice stays intact.
//
// darcy@hasc.ca, samurai@cs.mcgill.ca
//
// StefView was implemented out of WorldSpaceView and retains some of the
// movement properties...
//
// The code for WorldSpaceView was written by Sam Streeper at NeXT, I think,
// and there were two other contributors, but I can't find their names in the
// source for it.
//
// NeXTView shows a simple (ha!) spinning NeXTcube logo, in full 3D. The 3D code
// came from an app I wrote a long time ago called "WireFrame", and so the code
// is pretty scary. As well, this thing is only a quick hack, though a nice one.
//
// This thing has room for improvement, and if you do so, send me a copy!
//
// - darcy
@implementation NeXTView
#define X_PERIOD 15000.0
#define Y_PERIOD 12000.0
#define DEFAULT_FPS 10
#define PI 3.1415926535
#define MAX_IMAGE_WIDTH 256
#define MAX_IMAGE_HEIGHT 256
#define MAX_X_SPEED (26)
#define MAX_Y_SPEED (26)
#define BUFFER_WIDTH (MAX_IMAGE_WIDTH + MAX_X_SPEED + 1)
#define BUFFER_HEIGHT (MAX_IMAGE_HEIGHT + MAX_Y_SPEED + 1)
#define PRINT(a) printf(a)
#define MINX 0.0
#define MINY 0.0
#define ZOOM 680.0
- takeSpot:(float)x:(float)y;
{
[self draw];
return self;
}
- takeSnapshot;
{
return self;
}
- oneStep
{
NXRect black = {0,0,0,0};
NXRect ballRect;
BRECT new;
static float xdelta = 2.0;
static float ydelta = 2.0;
int changed = 0;
then = now;
now = currentTimeInMs();
xpos += xdelta;
if (xpos<MINX) {
xpos = MINX;
xdelta*=-1.0;
changed=1;
} else if (xpos>maxCoord.x){
xpos = maxCoord.x;
xdelta*=-1.0;
changed=1;
}
ypos += ydelta;
if (ypos<MINY) {
ypos = MINY;
ydelta*=-1.0;
changed=1;
} else if (ypos>maxCoord.y){
ypos = maxCoord.y;
ydelta*=-1.0;
changed=1;
}
if (changed){
#if 0
Axis flip[3]={y,y,y};
Direction dir[2]={positive,positive};
#else
Axis flip[3]={y,z,x};
Direction dir[2]={positive,negative};
#endif
axis = flip[axis];
spin = dir[spin];
}
new.l = floor(xpos);
new.b = floor(ypos);
new.r = new.l + imageSize.width;
new.t = new.b + imageSize.height;
ballRect.origin.x = 0;
ballRect.origin.y = 0;
ballRect.size.width = imageSize.width;
ballRect.size.height = imageSize.height;
redrawTo.x = MIN(new.l, old.l);
redrawTo.y = MIN(new.b, old.b);
redraw.origin.x = 0;
redraw.origin.y = 0;
redraw.size.width = (MAX(new.r, old.r)) - redrawTo.x + 1;
redraw.size.height = (MAX(new.t, old.t)) - redrawTo.y + 1;
black.size= redraw.size;
[buffer lockFocus];
PSsetgray(0);
NXRectFill(&black);
[self draw];
ballTo.x = new.l - redrawTo.x;
ballTo.y = new.b - redrawTo.y;
[buffer unlockFocus];
[buffer composite:NX_COPY toPoint:&redrawTo];
old = new;
return self;
}
#define SIZE 200.0
- initFrame:(const NXRect *)frameRect
{
const char *animSpeed;
NXRect black = {0, 0, SIZE, SIZE };
imageSize = black.size;
[super initFrame:frameRect];
[self allocateGState]; // For faster lock/unlockFocus
[self setClipping:NO]; // even faster...
PSsetlinewidth(0.15);
backgroundColour=NX_COLORBLACK;
worldOrigin.x=0.0;
worldOrigin.y=0.0;
worldOrigin.z=0.0;
translationRate = 3.0;
currentZoom=ZOOM;
list = [[List alloc] init];
axis = y;
spin = positive;
buffer = [[NXImage alloc] initSize:&black.size];
if ([buffer lockFocus])
{
PSsetgray(0);
NXRectFill(&black);
[buffer unlockFocus];
}
animSpeed = NXGetDefaultValue([NXApp appName], "animSpeed");
if (animSpeed == NULL) framesPerSecond = DEFAULT_FPS;
else framesPerSecond = atoi(animSpeed);
nextRotationTime = 0;
[self newViewSize];
return self;
}
- sizeTo:(NXCoord)width :(NXCoord)height
{
[super sizeTo:width :height];
[self newViewSize];
return self;
}
- newViewSize
{
//this is called every time View size changes
NXRect black = {0, 0, BUFFER_WIDTH, BUFFER_HEIGHT };
then = now = currentTimeInMs();
if (oldSize.width == bounds.size.width &&
oldSize.height == bounds.size.height)
return self;
else
{
oldSize.width = bounds.size.width;
oldSize.height = bounds.size.height;
}
maxCoord.x = bounds.size.width - imageSize.width - MINX;
maxCoord.y = bounds.size.height - imageSize.height - MINY;
if (maxCoord.x < 0) maxCoord.x = 0;
if (maxCoord.y < 0) maxCoord.y = 0;
old.l = old.r = maxCoord.x/2 + MINX;
old.b = old.t = maxCoord.y/2 + MINY;
ballTo.x = ballTo.y = 0;
if ([buffer lockFocus])
{
PSsetgray(0);
NXRectFill(&black);
[buffer unlockFocus];
}
return self;
}
- (const char *)windowTitle
{
return "NeXTView";
}
- inspector:sender
{
char buf[MAXPATHLEN];
if (!sharedInspectorPanel){
sprintf(buf,"%s/NeXTView.nib",[sender moduleDirectory:"NeXT"]);
[NXApp loadNibFile:buf owner:self withNames:NO];
[self loadDir:[sender moduleDirectory:"NeXT"]];
}
return sharedInspectorPanel;
}
- tryToChangeCentre
{
id object=[self firstObject];
if (object) {
[object getCentre:&curOrigin.x:&curOrigin.y:&curOrigin.z];
} else {
curOrigin.x = curOrigin.y = curOrigin.z = 0.0;
}
return self;
}
- firstObject
{
return [list objectAt:0];
}
- free
{
[list free];
return [super free];
}
- (const char *)world;
{
return "NeXTcube.world";
}
- loadDir:(const char *)dir
{
char world[MAXPATHLEN+1];
sprintf(world,"%s/%s",dir,[self world]);
[self loadWorld:world];
[self tryToChangeCentre];
[self display];
return self;
}
- loadWorld:(const char *)world
{
DIR *dirp;
id newFrame;
struct direct *dp;
char *tail;
char temp[1024];
dirp=opendir(world);
if (!dirp) {
NXRunAlertPanel("Directory Error", "Can't read directory: %s","OK",0,0,world);
} else {
for(dp=readdir(dirp);dp!=NULL;dp=readdir(dirp)){
if ((tail=(rindex(dp->d_name,'.')))!=NULL){
if (strcmp((tail+1),"wireframe")==0){
sprintf(temp,"%s/%s",world,dp->d_name);
newFrame = [[WireFrame alloc] init];
[newFrame makeWireFrame:temp];
[self addThisObject:newFrame];
}
if (strcmp((tail+1),"wireframeb")==0){
sprintf(temp,"%s/%s",world,dp->d_name);
newFrame = [[WireFrame alloc] init];
[newFrame readBinaryCodeFrom:temp];
[self addThisObject:newFrame];
}
}
}
}
return self;
}
- setTranslationRate:sender;
{
translationRate=[sender floatValue];
return self;
}
- (int)numberOfObjects
{
return [list count];
}
- addThisObject:anObject
{
[list addObject:anObject];
return self;
}
- setZoom: sender
{
currentZoom=[sender floatValue];
[self display];
return self;
}
- draw;
{
int i,count = [list count] ;
NXPoint zero = {0.0,0.0};
for (i=0;i<count;i++){
id wireFrame = [list objectAt:i];
[wireFrame rotate:spin aroundAxis:axis atOrigin:curOrigin];
[wireFrame drawYourself:currentZoom
centeredOn:imageSize.width/2.0 :imageSize.height/2.0];
}
return self;
}
- translate:(Direction)dir alongAxis:(Axis)a atRate:(float)rate
{
int i,count = [list count];
for (i=0;i<count;i++){
[[list objectAt:i] translate:dir
alongAxis:a
atRate:rate];
}
[self tryToChangeCentre];
return self;
}
- rotate:(Direction)dir aroundAxis:(Axis)a atOrigin:(Origin)orig
{
int i,count = [list count];
for (i=0;i<count;i++){
[[list objectAt:i] rotate:dir
aroundAxis:a
atOrigin:orig];
}
return self;
}
- rotatey:sender;
{
[self rotate:negative aroundAxis:y atOrigin:curOrigin];
return self;
}
- rotateY:sender;
{
[self rotate:positive aroundAxis:y atOrigin:curOrigin];
return self;
}
- rotatez:sender;
{
[self rotate:negative aroundAxis:z atOrigin:curOrigin];
return self;
}
- rotateZ:sender;
{
[self rotate:positive aroundAxis:z atOrigin:curOrigin];
return self;
}
- rotatex:sender;
{
[self rotate:negative aroundAxis:x atOrigin:curOrigin];
return self;
}
- rotateX:sender;
{
[self rotate:positive aroundAxis:x atOrigin:curOrigin];
return self;
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.