|
|
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.