home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1 / Nebula One.iso / Graphics / Misc / aa_m68k_Only / NDCamera.0.21 / Source / CameraController.m < prev    next >
Encoding:
Text File  |  1995-07-19  |  11.2 KB  |  553 lines

  1. #import "CameraController.h"
  2. #import "NDCInfo.h"
  3. #import <misckit/MiscString.h>
  4. #import <video/NXLiveVideoView.h>
  5.  
  6. static BOOL _NDIsGrabbing;
  7.  
  8. void handler( DPSTimedEntry teNumber, double now, void *userData )
  9. {
  10.     id grabber;
  11.     
  12.     if( _NDIsGrabbing ) return;
  13.     
  14.     _NDIsGrabbing = YES;
  15.     grabber = (id)userData;
  16.     [grabber grab:nil];
  17. }
  18.  
  19. @implementation CameraController
  20.  
  21. - init
  22. {
  23.     id    ourServer;
  24.     NXSize destSize = { 300, 225};
  25.     
  26.     [super init];
  27.     
  28.     _destRect.origin.x = 0;
  29.     _destRect.origin.y = 0;
  30.  
  31.     _outputRect.origin.x = 0;
  32.     _outputRect.origin.y = 0;
  33.     _outputRect.size.width = 300;
  34.     _outputRect.size.height = 225;
  35.     // [outputView getFrame:&_outputRect];
  36.  
  37.     currentImage = [NXImage new];
  38.     [currentImage setSize:&destSize];
  39.  
  40.     outputImage = [NXImage new];    
  41.     // [outputImage setSize:&(outRect.size)];
  42.     [outputImage setSize:&destSize];
  43.  
  44.     // To allow outside remote grab-control ...puuh cool word :-)
  45.     // we install a plain DO entry.
  46.  
  47.     ourServer = [NXConnection registerRoot:self 
  48.                              withName:"localhost/NDCamera"];
  49.     [ourServer runFromAppKitWithPriority:NX_MODALRESPTHRESHOLD];
  50.  
  51.     return self;
  52. }
  53.  
  54. - showInfo:sender
  55. {
  56.     if( !info ) info = [NDCInfo new];
  57.  
  58.     [info makeKeyAndOrderFront:self];
  59.     return self;
  60. }
  61.  
  62. - start:sender
  63. {
  64.     int    i;
  65.     id    aWindow;
  66.     _cameraOn = YES;
  67.  
  68.     // Slide the button to open..
  69.     // I don't think we have to take care of timed animation because this
  70.     // app will always run on a NeXT Dimension which has fixed speed
  71.     // ...perhaps the Turbos a a little faster...who cares anyway.
  72.  
  73.     aWindow = [onOffButton window];
  74.  
  75.     for( i=0; i<7; i++ )
  76.     {
  77.         [onOffButton moveBy:0 :3];
  78.         [aWindow display];
  79.     }
  80.     [self adjustGrabRect:self];    
  81.     [self _adjustOcularTitle];
  82.  
  83.     [self adjustCameraSource:self];
  84.     [recButton setEnabled:YES];
  85.     [camera start:self];
  86.     [onOffButton setAction:@selector(stop:)];
  87.     [recButton setAction:@selector(startGrabbing:)];
  88.     
  89.     // Grab an initial image...I know that grab will increase the count
  90.     // so lets start with something ueful.
  91.  
  92.     _frameCount = -1;
  93.     [self grab:self];
  94.  
  95.     return self;
  96. }
  97.  
  98. - stop:sender
  99. {
  100.     int    i;
  101.     id    aWindow;
  102.  
  103.     _cameraOn = NO;
  104.     [recButton setEnabled:NO];
  105.     [self stopGrabbing:self];
  106.     [camera stop:self];
  107.  
  108.     // Slide the button to close..
  109.  
  110.     aWindow = [onOffButton window];
  111.     for( i=0; i<7; i++ )
  112.     {
  113.         [onOffButton moveBy:0 :-3];
  114.         [aWindow display];
  115.     }
  116.     [self adjustGrabRect:self];    
  117.     [onOffButton setAction:@selector(start:)];
  118.     return self;
  119. }
  120.  
  121. - grab:sender
  122. {
  123.     _NDIsGrabbing = YES;
  124.     [camera grabIn:currentImage 
  125.                 fromRect:&_sourceRect 
  126.                 toRect:&_destRect];
  127.  
  128.     _frameCount++;
  129.     [frameNumber setIntValue:_frameCount];
  130.  
  131.     [currentImage setScalable:YES];
  132.     [outputImage lockFocus];
  133.  
  134.     // One possible way of getting the image where we want it:
  135.     //
  136.     //    [currentImage setSize:&(_outputRect.size)];
  137.     //    [currentImage composite:NX_COPY toPoint:&aPoint];
  138.     //    [currentImage setSize:&(_destRect.size)];
  139.  
  140.     // Our way to do it
  141.  
  142.     [currentImage drawRepresentation:[currentImage bestRepresentation]
  143.                 inRect:&_outputRect];
  144.  
  145.     // another way....
  146.     //
  147.     //    aImageRep = [currentImage bestRepresentation];
  148.     //    [aImageRep drawIn:&_outputRect];
  149.     
  150.     [outputImage unlockFocus];
  151.  
  152.     [outputView setImage:outputImage];
  153.     NXPing();
  154.  
  155.     // Lets see if we have to save that stuff ??
  156.  
  157.     if( grabOutput != nil )[self _saveCurrentFrame];
  158.  
  159.     _NDIsGrabbing = NO;
  160.  
  161.     return self;
  162. }
  163.  
  164. - _saveCurrentFrame
  165. {
  166.     id    aString;
  167.     id    filename;
  168.     FILE     *         dummyStream;
  169.     NXStream *     aStream;
  170.     float    compressionFactor;
  171.  
  172.     filename = [grabOutput copy];
  173.     aString = [filename fileBasename];
  174.     [filename cat:"/"];
  175.     [filename concatenate:aString];
  176.     [filename cat:"."];
  177.     [aString setIntValue:_frameCount];
  178.     [filename concatenate:aString];
  179.     [filename cat:".tiff"];
  180.     NXLogError( [filename stringValue] );
  181.  
  182.     // Well the streams won't truncate a file so we have to do it on
  183.     // our own.
  184.     // We should do a backup of existing files here if requested.
  185.  
  186.     dummyStream = fopen( [filename stringValue], "w" );
  187.     if( dummyStream ) fclose( dummyStream );
  188.         
  189.     aStream = NXMapFile( [filename stringValue], NX_WRITEONLY );
  190.  
  191.     [outputImage writeTIFF:aStream 
  192.         allRepresentations:NO
  193. //        usingCompression:NX_TIFF_COMPRESSION_LZW
  194.         usingCompression:NX_TIFF_COMPRESSION_NONE
  195.         andFactor:0];
  196.  
  197.     NXSaveToFile( aStream, [filename stringValue] );
  198.     NXCloseMemory( aStream, NX_FREEBUFFER );
  199.  
  200.     [aString free];
  201.     [filename free];
  202.     return self;
  203. }
  204.  
  205. - startGrabbing:sender
  206. {
  207.     // Now if we have to do autorecording lets init the timed entry...
  208.  
  209.     if( [autoGrabButton state] == YES )
  210.     {
  211.         [self _startTimer];
  212.         [recButton setAction:@selector(stopGrabbing:)];
  213.         [recButton setState:1];
  214.     }
  215.     // otherwise we will just grab a single frame.
  216.  
  217.     else
  218.     {
  219.         [recButton setState:1];
  220.         [self grab:self];
  221.         [recButton setState:0];
  222.     }
  223.     return self;
  224. }
  225.  
  226. - adjustOutputFile:pathString
  227. {
  228.     _frameCount = 0;
  229.     [frameNumber setIntValue:_frameCount];
  230.  
  231.     if( !grabOutput )
  232.         grabOutput = [MiscString new];
  233.  
  234.     [grabOutput takeStringValueFrom:pathString];
  235.  
  236.     if( ![grabOutput isFileOfType:Misc_Directory] ||
  237.         [grabOutput isEmpty] )
  238.     {
  239.         [grabOutput free];
  240.         grabOutput = nil;
  241.         [grabOutputField setStringValue:""];
  242.     }
  243.     else
  244.     {
  245.         [grabOutputField setStringValue:[grabOutput stringValue]];
  246.     }
  247.     return self;
  248. }
  249.  
  250. - stopGrabbing:sender
  251. {
  252.     [self _stopTimer];
  253.     [recButton setAction:@selector(startGrabbing:)];
  254.     [recButton setState:0];
  255.     return self;
  256. }
  257.  
  258. - (BOOL)isGrabbing
  259. {
  260.     return (BOOL)[recButton state];
  261. }
  262.  
  263. - adjustSpeed:sender
  264. {
  265.     if( !_cameraOn ) return self;
  266.     [self stopGrabbing:self];
  267.     [self startGrabbing:self];
  268.     return self;
  269. }
  270.  
  271. - _startTimer
  272. {
  273.     double    frameDelay;
  274.     float    aBaseRate;
  275.  
  276.     if( animateTE == 0 )
  277.     {
  278.         aBaseRate = [fpsBaseRateField floatValue];
  279.         if( aBaseRate < 0.001 ) aBaseRate = 0.001;
  280.  
  281.         frameDelay = 1 / ([[speedMatrix selectedCell] tag] * aBaseRate);
  282.         animateTE = DPSAddTimedEntry( frameDelay, (DPSTimedEntryProc)handler,
  283.                                       self, NX_BASETHRESHOLD );
  284.     }
  285.     return self;
  286. }
  287.  
  288. - _stopTimer
  289. {
  290.     if( animateTE )
  291.     {    
  292.         DPSRemoveTimedEntry( animateTE );
  293.         animateTE = 0;
  294.     }
  295.     return self;
  296. }
  297.  
  298. - baseFpsRateChanged:sender
  299. {
  300.  
  301.     return self;
  302. }
  303.  
  304. - adjustCameraSource:sender
  305. {
  306.     [camera selectInput:[[inputMatrix selectedCell] tag]];
  307.     return self;
  308. }
  309.  
  310. - adjustGrabRect:sender
  311. {
  312.     [self _adjustGrabRect];
  313.     
  314.     _refFrameSize.width = _sourceRect.size.width;
  315.     _refFrameSize.height = _sourceRect.size.height;
  316.  
  317.     return self;
  318. }
  319.  
  320. - _adjustGrabRect
  321. {
  322.     // BUG: We really should make some sanity checks !!
  323.  
  324.     _sourceRect.origin.x = [grabOriginXField intValue];
  325.     _sourceRect.origin.y = [grabOriginYField intValue];
  326.     _sourceRect.size.width = [grabSizeWidthField intValue];
  327.     _sourceRect.size.height = [grabSizeHeightField intValue];    
  328.     // Lets get a new image with the right size...Remember that this size
  329.     // does not reflex the size of the saved image !! This has to be resized
  330.     // to reflect the different scale.
  331.  
  332.     _destRect.size.width = _sourceRect.size.width;
  333.     _destRect.size.height = _sourceRect.size.height;
  334.  
  335.     if( currentImage ) [currentImage free];
  336.     currentImage = [NXImage new];
  337.     [currentImage setSize:&(_destRect.size)];
  338.  
  339.     return self;
  340. }
  341.  
  342. - zoomIn:sender
  343. {
  344.     float    xInc;
  345.     float    yInc;
  346.  
  347.     // Be sure that there will be still a useful rect to see.
  348.  
  349.     xInc = _refFrameSize.width / 100;
  350.     if( xInc < 2 ) xInc = 2;
  351.  
  352.     yInc = _refFrameSize.height / 100;
  353.     if( yInc < 2 ) yInc = 2;
  354.  
  355.     if( _sourceRect.size.width > 20 &&
  356.         _sourceRect.size.height > 20 )
  357.     {
  358.         [grabOriginXField setIntValue:_sourceRect.origin.x + xInc];
  359.         [grabOriginYField setIntValue:_sourceRect.origin.y + yInc];
  360.         [grabSizeWidthField setIntValue:_sourceRect.size.width - 2* xInc];
  361.         [grabSizeHeightField setIntValue:_sourceRect.size.height - 2* yInc];
  362.     }
  363.     [self _adjustGrabRect];    
  364.     [self grab:self];
  365.     return self;
  366. }
  367.  
  368. - zoomOut:sender
  369. {
  370.     float    xInc;
  371.     float    yInc;
  372.  
  373.     // lets not pass the lower left corner..
  374.  
  375.     xInc = _refFrameSize.width / 100;
  376.     if( xInc < 2 ) xInc = 2;
  377.  
  378.     yInc = _refFrameSize.height / 100;
  379.     if( yInc < 2 ) yInc = 2;
  380.  
  381.     if( _sourceRect.origin.x > 4 &&
  382.         _sourceRect.origin.y > 4 )
  383.     {
  384.         [grabOriginXField setIntValue:_sourceRect.origin.x - xInc];
  385.         [grabOriginYField setIntValue:_sourceRect.origin.y - yInc];
  386.         [grabSizeWidthField setIntValue:_sourceRect.size.width + 2* xInc];
  387.         [grabSizeHeightField setIntValue:_sourceRect.size.height + 2* yInc];
  388.     }
  389.     [self _adjustGrabRect];    
  390.     [self grab:self];
  391.     return self;
  392. }
  393.  
  394. - openVideoControls:sender
  395. {
  396.     int    i;
  397.     int    stepSize;
  398.     int    direction;
  399.     id    aWindow;
  400.     NXRect    aFrame;
  401.  
  402.     // opens and closes the controls area...the name is not very cleaver..
  403.     // but who cares.
  404.  
  405.     [sender getFrame:&aFrame];
  406.  
  407.     if( aFrame.origin.x < 100 )
  408.             direction = +1;
  409.     else    direction = -1;
  410.  
  411.     stepSize = 6 * direction;
  412.  
  413.     aWindow = [sender window];
  414.     for( i=0; i<14; i++ )
  415.     {
  416.         [sender moveBy:stepSize :0];
  417.         [aWindow display];
  418.     }
  419.  
  420.     stepSize = 3 * direction;
  421.  
  422.     for( i=0; i<3; i++ )
  423.     {
  424.         [sender moveBy:stepSize :0];
  425.         [aWindow display];
  426.     }
  427.  
  428.     return self;
  429. }
  430.  
  431. - changeHue:sender
  432. {
  433.     [camera setInputHue:
  434.         [camera inputHue] + ([sender tag] * 36.0)];
  435.     [sender setState:0];
  436.     
  437.     // We lack any visual feedback for the single values...so we'll use the
  438.     // console...sorry...thats nasty; I know.
  439.  
  440.     NXLogError( "Hue: %f", [camera inputHue] );
  441.     return self;
  442. }
  443.  
  444. - changeBrightness:sender
  445. {
  446.     [camera setInputBrightness:
  447.         [camera inputBrightness] + ([sender tag] / 10.0)];
  448.     [sender setState:0];
  449.  
  450.     // We lack any visual feedback for the single values...so we'll use the
  451.     // console...sorry...thats nasty; I know.
  452.  
  453.     NXLogError( "Brightness: %f", [camera inputBrightness] );
  454.     return self;
  455. }
  456.  
  457. - changeSaturation:sender
  458. {
  459.     [camera setInputSaturation:
  460.         [camera inputSaturation] + ([sender tag] / 10.0)];
  461.     [sender setState:0];
  462.  
  463.     // We lack any visual feedback for the single values...so we'll use the
  464.     // console...sorry...thats nasty; I know.
  465.  
  466.     NXLogError( "Saturation: %f", [camera inputSaturation] );
  467.     return self;
  468. }
  469.  
  470. - changeGamma:sender
  471. {
  472.     [camera setInputGamma:
  473.         [camera inputGamma] + ([sender tag] / 10.0)];
  474.     [sender setState:0];
  475.  
  476.     // We lack any visual feedback for the single values...so we'll use the
  477.     // console...sorry...thats nasty; I know.
  478.  
  479.     NXLogError( "Gamma: %f", [camera inputGamma] );
  480.     return self;
  481. }
  482.  
  483. - changeSharpness:sender
  484. {
  485.     [camera setInputSharpness:
  486.         [camera inputSharpness] + ([sender tag] / 10.0)];
  487.     [sender setState:0];
  488.  
  489.     // We lack any visual feedback for the single values...so we'll use the
  490.     // console...sorry...thats nasty; I know.
  491.  
  492.     NXLogError( "Sharpness: %f", [camera inputSharpness] );
  493.     return self;
  494. }
  495.  
  496. - windowDidMove:sender
  497. {
  498.     // If the window should stick together...we'll do it.
  499.  
  500.     // if( !keepWindowsTogether ) return self;
  501.  
  502.     return self;
  503. }
  504.  
  505. - windowDidResize:sender
  506. {
  507.     NXRect    aFrame;
  508.  
  509.     // If our ocular has changed we should adjust the title and the 
  510.     // image grabbing area.
  511.  
  512.     if( sender != [outputView window] ) return self;
  513.  
  514.     [outputView getBounds:&aFrame];
  515.     [outputImage setSize:&(aFrame.size)];
  516.     _outputRect.size.width = aFrame.size.width;
  517.     _outputRect.size.height = aFrame.size.height;
  518.  
  519.     [self _adjustOcularTitle];
  520.  
  521.     // We should grab the image again...but it would be faster to just scale
  522.     // the old one...
  523.  
  524.     // [self grab:self];
  525.  
  526.     return self;
  527. }
  528.  
  529. - _adjustOcularTitle
  530. {
  531.     id    ourWindow;
  532.     id    aString;
  533.     id    intString;
  534.  
  535.     ourWindow = [outputView window];
  536.     aString = [MiscString newWithString:"("];
  537.     intString = [MiscString new];
  538.     [intString setIntValue:_outputRect.size.width];
  539.     [aString concatenate:intString];
  540.     [aString cat:" x "];
  541.     [intString setIntValue:_outputRect.size.height];
  542.     [aString concatenate:intString];
  543.     [aString cat:") Ocular"];
  544.  
  545.     [ourWindow setTitle:[aString stringValue]];
  546.  
  547.     [aString free];
  548.     [intString free];    
  549.  
  550.     return self;
  551. }
  552.  
  553. @end