|
|
Sample Programs from NeXSTEP 3.3
#import <appkit/appkit.h>
#import "SimpleCamera.h"
#import "SimpleShape.h"
/* SimpleCamera -- by Bill Bumgarner 6/1/92
* with assistance from Dave Springer.
*
* SimpleCamera demonstrates the creation of a very simple 3Dkit scene
* that has mouse control via the N3DRotator class, supports dumping RIB
* code to a file, contains light sources (ambient light and a point light),
* has a surface shader, supports both WireFrame and SmoothSolid rendering,
* and has a single custom N3DShape that generates a Torus (or teapot).
*
* Simple.app was created as an example of using the 3Dkit. Parts of it
* come from Teapot.app by Dave Springer (see SimpleShape.m).
*
* 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.
*/
@implementation SimpleCamera
- initFrame:(const NXRect *) theRect
{
// camera position points
// Note that the camera vector is in a left-handed coordinate system; this
// is the default for RenderMan. In order to look at the front of the
// scene, you have to step backwards along the z-axis; in other words, you
// have to move the eye point negatively in z.
RtPoint fromP = {0,0,-5.0}, toP = {0,0,0};
// light position point
// Notice the "-0.75" z-coordinate. This is because of the left-handed
// coordinate system.
RtPoint lFromP = {0.5,0.5,-0.75};
// the various 3Dkit object id''s that we will initialize here
id ambientLight;
id aLight;
id aShader;
id aShape;
// initialize camera and put it at (0,0,-5.0) looking at the origin (0,0,0)
// roll specifies the roll angle of the camera...
[super initFrame:theRect];
[self setEyeAt:fromP toward:toP roll:0.0];
// create a shader that will shade surfaces with a simple matte surface.
aShader=[[N3DShader alloc] init];
// Generate a blue matte surface.
// This is slow on a monochrome system.
[aShader setUseColor:YES];
[aShader setColor:NX_COLORBLUE];
[(N3DShader *)aShader setShader:"matte"];
// Comment the previous line and uncomment the following lines to generate
// a texture-mapped surface. The N3DShader object does all the necessary
// things to make a shader work properly: it sends all the Declare commands
// and a complete parameter string. All you need to do is change the
// parameters you want with the -setShaderArg:fooValue: family of methods.
// When you compile your own shader, all the information about the arguments
// and their default values are stored in the .slo file, and the N3DShader
// object knows how to read them.
//[(N3DShader *)aShader setShader:"texmap"];
//[aShader setShaderArg:"texname"
// stringValue:"/NextLibrary/Textures/pebbles.tx"];
// initialize the world shape and set its shader to be aShader
aShape=[[SimpleShape alloc] init];
[(N3DShape *) aShape setShader:aShader];
[[self setWorldShape:aShape] free]; // free the default world shape
// create an ambientlight source.
ambientLight=[[N3DLight alloc] init];
[ambientLight makeAmbientWithIntensity:0.1];
[self addLight:ambientLight];
// create a Point light and put it at (0.5, 0.5, -0.75) at
// full intensity (1.0).
aLight=[[N3DLight alloc] init];
[aLight makePointFrom:lFromP intensity:1.0];
[self addLight:aLight];
// create another Point light and put it at (-0.5, -0.5, -0.75) at
// full intensity (1.0).
N3D_XComp( lFromP ) = -0.5;
N3D_YComp( lFromP ) = -0.5;
aLight=[[N3DLight alloc] init];
[aLight makePointFrom:lFromP intensity:1.0];
[self addLight:aLight];
// set the surface type to generate smooth solids. The mouseDown:
// method automatically drops to N3D_WireFrame whenever the user manipulates
// the scene via the mouse (see the mouseDown: implementation below).
// This must be done after the setWorldShape: method (or after any new shape
// is added to the hierarchy).
[self setSurfaceTypeForAll:N3D_SmoothSolids chooseHider:YES];
// allocate and initialize the N3DRotator object that governs
// rotational control via the mouseDown: method
theRotator=[[N3DRotator alloc] initWithCamera:self];
return self;
}
- dumpRib:sender
{
static id savePanel=nil;
NXStream *ts;
char buf[MAXPATHLEN+1];
// initialize the savePanel, if it hasn''t been done so previously
if (!savePanel) {
savePanel=[SavePanel new];
[savePanel setRequiredFileType:"rib"];
}
// run the savepanel.
if([savePanel runModal]){
// returned w/pathname, open a stream and
ts=NXOpenMemory(NULL, 0, NX_WRITEONLY);
// process the file name for a custom display line such that
// "prman <<filename>>.rib" will put the resulting image somewhere
// predictably useful.
strcpy(buf, [savePanel filename]);
// remove the .rib extension from the path returned by the SavePanel
strrchr(buf,'.')[0]='\0';
// feed to NXPrintf to put in the custom Display command
NXPrintf(ts, "Display \"%s.tiff\" \"file\" \"rgba\"\n", buf);
// then feed the rib code to the stream and
[self copyRIBCode:ts];
// save the stream to the file selected in the savepanel
NXSaveToFile(ts, [savePanel filename]);
// and close the stream (which also flushes it), also making sure
// that the allocated memory is freed.
NXCloseMemory(ts,NX_FREEBUFFER);
}
return self;
}
#define ACTIVEBUTTONMASK (NX_MOUSEUPMASK|NX_MOUSEDRAGGEDMASK)
- mouseDown:(NXEvent *)theEvent
{
int oldMask;
NXPoint oldMouse, newMouse, dMouse;
RtMatrix rmat, irmat;
// find out what axis of rotation the rotator should be constrained to
switch([rotoMatrix selectedRow]){
case 0: [theRotator setRotationAxis:N3D_AllAxes]; break;
case 1: [theRotator setRotationAxis:N3D_XAxis]; break;
case 2: [theRotator setRotationAxis:N3D_YAxis]; break;
case 3: [theRotator setRotationAxis:N3D_ZAxis]; break;
case 4: [theRotator setRotationAxis:N3D_XYAxes]; break;
case 5: [theRotator setRotationAxis:N3D_XZAxes]; break;
case 6: [theRotator setRotationAxis:N3D_YZAxes]; break;
}
// track the mouse until a mouseUp event occurs, updating the display
// as tracking happens.
[self lockFocus];
oldMask = [window addToEventMask:ACTIVEBUTTONMASK];
// switch to the N3D_WireFrame surface type
[self setSurfaceTypeForAll:N3D_WireFrame chooseHider:YES];
oldMouse = theEvent->location;
[self convertPoint:&oldMouse fromView:nil];
while (1)
{
newMouse = theEvent->location;
[self convertPoint:&newMouse fromView:nil];
dMouse.x = newMouse.x - oldMouse.x;
dMouse.y = newMouse.y - oldMouse.y;
if (dMouse.x != 0.0 || dMouse.y != 0.0) {
[theRotator trackMouseFrom:&oldMouse to:&newMouse
rotationMatrix:rmat andInverse:irmat];
[worldShape concatTransformMatrix:rmat premultiply:NO];
[self display];
}
theEvent = [NXApp getNextEvent:ACTIVEBUTTONMASK];
if (theEvent->type == NX_MOUSEUP)
break;
oldMouse = newMouse;
}
// switch back to the N3D_SmoothSolids surface type
[self setSurfaceTypeForAll:N3D_SmoothSolids chooseHider:YES];
[self display];
[self unlockFocus];
[window setEventMask:oldMask];
return self;
}
@end
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.