home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
NeXTSTEP 3.0
/
NeXTSTEP3.0.iso
/
NextDeveloper
/
Examples
/
3Dkit
/
Simple
/
SimpleCamera.m
< prev
next >
Wrap
Text File
|
1992-06-02
|
6KB
|
169 lines
#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
RtPoint fromP = {0,0,5.0}, toP = {0,0,0};
// light position point
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];
// uncomment the following lines to generate a blue matte surface.
// This is slow on a monochrome system.
// [aShader setUseColor:YES];
// [aShader setColor:NX_COLORBLUE];
[(N3DShader *)aShader setShader:"matte"];
// initialize the world shape and set its shader to be aShader
aShape=[[SimpleShape alloc] init];
[(N3DShape *) aShape setShader:aShad@I
[[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];
// 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, new@Pe, 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