|
|
1.1 root 1: #import <appkit/appkit.h>
2: #import "SimpleCamera.h"
3: #import "SimpleShape.h"
4:
5: /* SimpleCamera -- by Bill Bumgarner 6/1/92
6: * with assistance from Dave Springer.
7: *
8: * SimpleCamera demonstrates the creation of a very simple 3Dkit scene
9: * that has mouse control via the N3DRotator class, supports dumping RIB
10: * code to a file, contains light sources (ambient light and a point light),
11: * has a surface shader, supports both WireFrame and SmoothSolid rendering,
12: * and has a single custom N3DShape that generates a Torus (or teapot).
13: *
14: * Simple.app was created as an example of using the 3Dkit. Parts of it
15: * come from Teapot.app by Dave Springer (see SimpleShape.m).
16: *
17: * You may freely copy, distribute and reuse the code in this example.
18: * NeXT disclaims any warranty of any kind, expressed or implied,
19: * as to its fitness for any particular use.
20: */
21:
22: @implementation SimpleCamera
23: - initFrame:(const NXRect *) theRect
24: {
25: // camera position points
26: // Note that the camera vector is in a left-handed coordinate system; this
27: // is the default for RenderMan. In order to look at the front of the
28: // scene, you have to step backwards along the z-axis; in other words, you
29: // have to move the eye point negatively in z.
30: RtPoint fromP = {0,0,-5.0}, toP = {0,0,0};
31:
32: // light position point
33: // Notice the "-0.75" z-coordinate. This is because of the left-handed
34: // coordinate system.
35: RtPoint lFromP = {0.5,0.5,-0.75};
36:
37: // the various 3Dkit object id''s that we will initialize here
38: id ambientLight;
39: id aLight;
40: id aShader;
41: id aShape;
42:
43: // initialize camera and put it at (0,0,-5.0) looking at the origin (0,0,0)
44: // roll specifies the roll angle of the camera...
45: [super initFrame:theRect];
46: [self setEyeAt:fromP toward:toP roll:0.0];
47:
48: // create a shader that will shade surfaces with a simple matte surface.
49: aShader=[[N3DShader alloc] init];
50: // Generate a blue matte surface.
51: // This is slow on a monochrome system.
52: [aShader setUseColor:YES];
53: [aShader setColor:NX_COLORBLUE];
54: [(N3DShader *)aShader setShader:"matte"];
55: // Comment the previous line and uncomment the following lines to generate
56: // a texture-mapped surface. The N3DShader object does all the necessary
57: // things to make a shader work properly: it sends all the Declare commands
58: // and a complete parameter string. All you need to do is change the
59: // parameters you want with the -setShaderArg:fooValue: family of methods.
60: // When you compile your own shader, all the information about the arguments
61: // and their default values are stored in the .slo file, and the N3DShader
62: // object knows how to read them.
63: //[(N3DShader *)aShader setShader:"texmap"];
64: //[aShader setShaderArg:"texname"
65: // stringValue:"/NextLibrary/Textures/pebbles.tx"];
66:
67: // initialize the world shape and set its shader to be aShader
68: aShape=[[SimpleShape alloc] init];
69: [(N3DShape *) aShape setShader:aShader];
70: [[self setWorldShape:aShape] free]; // free the default world shape
71:
72: // create an ambientlight source.
73: ambientLight=[[N3DLight alloc] init];
74: [ambientLight makeAmbientWithIntensity:0.1];
75: [self addLight:ambientLight];
76:
77: // create a Point light and put it at (0.5, 0.5, -0.75) at
78: // full intensity (1.0).
79: aLight=[[N3DLight alloc] init];
80: [aLight makePointFrom:lFromP intensity:1.0];
81: [self addLight:aLight];
82:
83: // create another Point light and put it at (-0.5, -0.5, -0.75) at
84: // full intensity (1.0).
85: N3D_XComp( lFromP ) = -0.5;
86: N3D_YComp( lFromP ) = -0.5;
87: aLight=[[N3DLight alloc] init];
88: [aLight makePointFrom:lFromP intensity:1.0];
89: [self addLight:aLight];
90:
91: // set the surface type to generate smooth solids. The mouseDown:
92: // method automatically drops to N3D_WireFrame whenever the user manipulates
93: // the scene via the mouse (see the mouseDown: implementation below).
94: // This must be done after the setWorldShape: method (or after any new shape
95: // is added to the hierarchy).
96: [self setSurfaceTypeForAll:N3D_SmoothSolids chooseHider:YES];
97:
98: // allocate and initialize the N3DRotator object that governs
99: // rotational control via the mouseDown: method
100: theRotator=[[N3DRotator alloc] initWithCamera:self];
101:
102: return self;
103: }
104:
105: - dumpRib:sender
106: {
107: static id savePanel=nil;
108: NXStream *ts;
109: char buf[MAXPATHLEN+1];
110:
111: // initialize the savePanel, if it hasn''t been done so previously
112: if (!savePanel) {
113: savePanel=[SavePanel new];
114: [savePanel setRequiredFileType:"rib"];
115: }
116:
117: // run the savepanel.
118: if([savePanel runModal]){
119: // returned w/pathname, open a stream and
120: ts=NXOpenMemory(NULL, 0, NX_WRITEONLY);
121: // process the file name for a custom display line such that
122: // "prman <<filename>>.rib" will put the resulting image somewhere
123: // predictably useful.
124: strcpy(buf, [savePanel filename]);
125: // remove the .rib extension from the path returned by the SavePanel
126: strrchr(buf,'.')[0]='\0';
127: // feed to NXPrintf to put in the custom Display command
128: NXPrintf(ts, "Display \"%s.tiff\" \"file\" \"rgba\"\n", buf);
129: // then feed the rib code to the stream and
130: [self copyRIBCode:ts];
131: // save the stream to the file selected in the savepanel
132: NXSaveToFile(ts, [savePanel filename]);
133: // and close the stream (which also flushes it), also making sure
134: // that the allocated memory is freed.
135: NXCloseMemory(ts,NX_FREEBUFFER);
136: }
137: return self;
138: }
139:
140: #define ACTIVEBUTTONMASK (NX_MOUSEUPMASK|NX_MOUSEDRAGGEDMASK)
141: - mouseDown:(NXEvent *)theEvent
142: {
143: int oldMask;
144: NXPoint oldMouse, newMouse, dMouse;
145: RtMatrix rmat, irmat;
146:
147: // find out what axis of rotation the rotator should be constrained to
148: switch([rotoMatrix selectedRow]){
149: case 0: [theRotator setRotationAxis:N3D_AllAxes]; break;
150: case 1: [theRotator setRotationAxis:N3D_XAxis]; break;
151: case 2: [theRotator setRotationAxis:N3D_YAxis]; break;
152: case 3: [theRotator setRotationAxis:N3D_ZAxis]; break;
153: case 4: [theRotator setRotationAxis:N3D_XYAxes]; break;
154: case 5: [theRotator setRotationAxis:N3D_XZAxes]; break;
155: case 6: [theRotator setRotationAxis:N3D_YZAxes]; break;
156: }
157:
158: // track the mouse until a mouseUp event occurs, updating the display
159: // as tracking happens.
160: [self lockFocus];
161: oldMask = [window addToEventMask:ACTIVEBUTTONMASK];
162:
163: // switch to the N3D_WireFrame surface type
164: [self setSurfaceTypeForAll:N3D_WireFrame chooseHider:YES];
165:
166: oldMouse = theEvent->location;
167: [self convertPoint:&oldMouse fromView:nil];
168: while (1)
169: {
170: newMouse = theEvent->location;
171: [self convertPoint:&newMouse fromView:nil];
172: dMouse.x = newMouse.x - oldMouse.x;
173: dMouse.y = newMouse.y - oldMouse.y;
174: if (dMouse.x != 0.0 || dMouse.y != 0.0) {
175: [theRotator trackMouseFrom:&oldMouse to:&newMouse
176: rotationMatrix:rmat andInverse:irmat];
177: [worldShape concatTransformMatrix:rmat premultiply:NO];
178: [self display];
179: }
180: theEvent = [NXApp getNextEvent:ACTIVEBUTTONMASK];
181: if (theEvent->type == NX_MOUSEUP)
182: break;
183: oldMouse = newMouse;
184: }
185: // switch back to the N3D_SmoothSolids surface type
186: [self setSurfaceTypeForAll:N3D_SmoothSolids chooseHider:YES];
187: [self display];
188: [self unlockFocus];
189:
190: [window setEventMask:oldMask];
191: return self;
192: }
193: @end
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.