home *** CD-ROM | disk | FTP | other *** search
/ Otherware / Otherware_1_SB_Development.iso / mac / developm / source / image144.sit / Stacks.p < prev    next >
Encoding:
Text File  |  1992-03-30  |  23.3 KB  |  905 lines

  1. unit Stacks;
  2.  
  3. interface
  4.  
  5.     uses
  6.         QuickDraw, Palettes, PrintTraps, globals, Utilities, Graphics, Analysis, Camera, file1, file2, functions, sound;
  7.  
  8.     function MakeStackFromWindow: boolean;
  9.     procedure MakeStack;
  10.     procedure MakeWindowsFromStack;
  11.     function AddSlice (update: boolean): boolean;
  12.     procedure DeleteSlice;
  13.     procedure ShowNextSlice (item: integer);
  14.     procedure ShowFirstOrLastSlice (ich: integer);
  15.     procedure DoResliceOptions;
  16.     procedure Reslice;
  17.     procedure Animate;
  18.     procedure MakeMovie;
  19.     procedure CaptureFrames;
  20.  
  21. implementation
  22.  
  23.  
  24.     function MakeStackFromWindow: boolean;
  25.     begin
  26.         with info^ do begin
  27.                 StackInfo := StackInfoPtr(NewPtr(SizeOf(StackInfoRec)));
  28.                 if StackInfo = nil then begin
  29.                         MakeStackFromWindow := false;
  30.                         exit(MakeStackFromWindow);
  31.                     end;
  32.                 with StackInfo^ do begin
  33.                         nSlices := 1;
  34.                         CurrentSlice := 1;
  35.                         PicBaseH[1] := PicBaseHandle;
  36.                         SliceSpacing := 0.0;
  37.                         LoopTime := 0.0;
  38.                     end;
  39.                 PictureType := NewPicture;
  40.                 MakeStackFromWindow := true;
  41.             end;
  42.     end;
  43.  
  44.  
  45.     procedure MakeStack;
  46.         var
  47.             ok, isStack: boolean;
  48.             i, result: integer;
  49.             TempInfo, SaveInfo: InfoPtr;
  50.             str: str255;
  51.     begin
  52.         if not AllSameSize then begin
  53.                 PutMessage('All currently open images must be the same size in order to make a stack.');
  54.                 exit(MakeStack);
  55.             end;
  56.         isStack := false;
  57.         for i := 1 to nPics do begin
  58.                 TempInfo := pointer(WindowPeek(PicWindow[i])^.RefCon);
  59.                 isStack := isStack or (TempInfo^.StackInfo <> nil);
  60.             end;
  61.         if isStack then begin
  62.                 PutMessage('All stacks must be closed before making a new stack.');
  63.                 exit(MakeStack);
  64.             end;
  65.         if nPics > MaxSlices then begin
  66.                 NumToString(MaxSlices, str);
  67.                 PutMessage(concat('Maximun stack size is ', str, ' slices.'));
  68.                 exit(MakeStack);
  69.             end;
  70.         StopDigitizing;
  71.         DisableDensitySlice;
  72.         SelectWindow(PicWindow[1]);
  73.         Info := pointer(WindowPeek(PicWindow[1])^.RefCon);
  74.         ActivateWindow;
  75.         KillRoi;
  76.         UnZoom;
  77.         if not MakeStackFromWindow then
  78.             exit(MakeStack);
  79.         with info^ do begin
  80.                 StackInfo^.nSlices := nPics;
  81.                 title := 'Stack';
  82.                 UpdateTitleBar;
  83.                 Revertable := false;
  84.             end;
  85.         SaveInfo := Info;
  86.         MakingStack := true;
  87.         ShowWatch;
  88.         for i := 2 to nPics do begin
  89.                 TempInfo := pointer(WindowPeek(PicWindow[2])^.RefCon);
  90.                 with TempInfo^ do begin
  91.                         hunlock(PicBaseHandle);
  92.                         info^.StackInfo^.PicBaseH[i] := PicBaseHandle;
  93.                     end;
  94.                 result := CloseAWindow(PicWindow[2]);
  95.                 Info := SaveInfo;
  96.             end;
  97.         with info^ do
  98.             UpdateWindowsMenuItem(ImageSize * StackInfo^.nSlices, title, 1);
  99.         MakingStack := false;
  100.     end;
  101.  
  102.  
  103.     function AddSlice (update: boolean): boolean;
  104.         var
  105.             i: integer;
  106.             h: handle;
  107.             isRoi: boolean;
  108.     begin
  109.         with info^, info^.StackInfo^ do begin
  110.                 AddSlice := false;
  111.                 if nSlices = MaxSlices then
  112.                     exit(AddSlice);
  113.                 isRoi := RoiShowing;
  114.                 if isRoi then
  115.                     KillRoi;
  116.                 h := NewHandle(PixMapSize);
  117.                 if (h = nil) or (MaxBlock < MinFree) then begin
  118.                         if h <> nil then
  119.                             DisposHandle(h);
  120.                         PutMessage('Not enough memory available to add a slice to this stack.');
  121.                         macro := false;
  122.                         exit(AddSlice);
  123.                     end;
  124.                 for i := nSlices downto CurrentSlice + 1 do
  125.                     PicBaseH[i + 1] := PicBaseH[i];
  126.                 nSlices := nSlices + 1;
  127.                 CurrentSlice := CurrentSlice + 1;
  128.                 PicBaseH[CurrentSlice] := h;
  129.                 SelectSlice(CurrentSlice);
  130.                 if Update then begin
  131.                         SelectAll(false);
  132.                         DoOperation(EraseOp);
  133.                         UpdatePicWindow;
  134.                     end;
  135.                 UpdateTitleBar;
  136.                 if isRoi then
  137.                     RestoreRoi;
  138.                 WhatToUndo := NothingToUndo;
  139.                 AddSlice := true;
  140.                 changes := true;
  141.                 PictureType := NewPicture;
  142.                 UpdateWindowsMenuItem(ImageSize * nSlices, title, PicNum);
  143.             end;
  144.     end;
  145.  
  146.  
  147.     procedure DeleteSlice;
  148.         var
  149.             SliceToDelete, NextSlice, i: integer;
  150.             isRoi: boolean;
  151.     begin
  152.         with info^, info^.StackInfo^ do begin
  153.                 if nSlices = 1 then begin
  154.                         WhatToUndo := NothingToUndo;
  155.                         exit(DeleteSlice);
  156.                     end;
  157.                 isRoi := RoiShowing;
  158.                 if isRoi then
  159.                     KillRoi;
  160.                 SetupUndo;
  161.                 WhatToUndo := UndoSliceDelete;
  162.                 SliceToDelete := CurrentSlice;
  163.                 if CurrentSlice = 1 then begin
  164.                         NextSlice := 2;
  165.                         WhatToUndo := UndoFirstSliceDelete;
  166.                     end
  167.                 else
  168.                     NextSlice := CurrentSlice - 1;
  169.                 SelectSlice(NextSlice);
  170.                 UpdatePicWindow;
  171.                 DisposHandle(PicBaseH[SliceToDelete]);
  172.                 for i := SliceToDelete to nSlices - 1 do
  173.                     PicBaseH[i] := PicBaseH[i + 1];
  174.                 nSlices := nSlices - 1;
  175.                 if CurrentSlice <> 1 then
  176.                     CurrentSlice := CurrentSlice - 1;
  177.                 UpdateTitleBar;
  178.                 if isRoi then
  179.                     RestoreRoi;
  180.                 changes := true;
  181.                 UpdateWindowsMenuItem(ImageSize * nSlices, title, PicNum);
  182.             end;
  183.     end;
  184.  
  185.  
  186.     procedure MakeWindowsFromStack;
  187.         var
  188.             i, ignore, N: integer;
  189.             SaveInfo: InfoPtr;
  190.             tmp: longint;
  191.  
  192.         function MakeName (i: integer): str255;
  193.             var
  194.                 str: str255;
  195.         begin
  196.             RealToString(i, 3, 0, str);
  197.             if str[1] = ' ' then
  198.                 str[1] := '0';
  199.             if str[2] = ' ' then
  200.                 str[2] := '0';
  201.             MakeName := str;
  202.         end;
  203.  
  204.     begin
  205.         N := info^.StackInfo^.nSlices;
  206.         tmp := SizeOf(PicInfo);
  207.         if MaxBlock < (MinFree + info^.ImageSize + (SizeOf(PicInfo) + 2000) * LongInt(N)) then begin
  208.                 PutMessage('There is not enough memory available to convert this stack to windows.');
  209.                 exit(MakeWindowsFromStack);
  210.             end;
  211.         SaveInfo := Info;
  212.         KillRoi;
  213.         for i := 1 to N - 1 do begin
  214.                 SelectSlice(1);
  215.                 info^.StackInfo^.CurrentSlice := 1;
  216.                 if not Duplicate(MakeName(i), false) then
  217.                     exit(MakeWindowsFromStack);
  218.                 info := SaveInfo;
  219.                 DeleteSlice;
  220.             end;
  221.         if Duplicate(MakeName(N), false) then begin
  222.                 info := SaveInfo;
  223.                 info^.changes := false;
  224.                 ignore := CloseAWindow(info^.wptr);
  225.             end;
  226.     end;
  227.  
  228.  
  229.     procedure ShowNextSlice (item: integer);
  230.         var
  231.             isRoi: boolean;
  232.     begin
  233.         with info^, info^.StackInfo^ do begin
  234.                 if item = NextSliceItem then begin
  235.                         CurrentSlice := CurrentSlice + 1;
  236.                         if CurrentSlice > nSlices then
  237.                             CurrentSlice := nSlices;
  238.                     end
  239.                 else begin
  240.                         CurrentSlice := CurrentSlice - 1;
  241.                         if CurrentSlice < 1 then
  242.                             CurrentSlice := 1;
  243.                     end;
  244.                 isRoi := RoiShowing;
  245.                 if isRoi then
  246.                     KillRoi;
  247.                 SelectSlice(CurrentSlice);
  248.                 UpdatePicWindow;
  249.                 UpdateTitleBar;
  250.                 WhatToUndo := NothingToUndo;
  251.                 if isRoi then
  252.                     RestoreRoi;
  253.             end;
  254.     end;
  255.  
  256.  
  257.     procedure ShowFirstOrLastSlice (ich: integer);
  258.         var
  259.             isRoi: boolean;
  260.     begin
  261.         with info^, info^.StackInfo^ do begin
  262.                 if ich = EndKey then
  263.                     CurrentSlice := nSlices
  264.                 else
  265.                     CurrentSlice := 1;
  266.                 isRoi := RoiShowing;
  267.                 if isRoi then
  268.                     KillRoi;
  269.                 SelectSlice(CurrentSlice);
  270.                 UpdatePicWindow;
  271.                 UpdateTitleBar;
  272.                 WhatToUndo := NothingToUndo;
  273.                 if isRoi then
  274.                     RestoreRoi;
  275.             end;
  276.     end;
  277.  
  278.  
  279.     procedure GetObliqueLine (xstart, ystart: real; angle: extended; count: integer; var line: LineType);
  280.         var
  281.             i, xbase, ybase: integer;
  282.             LowerLeft, LowerRight, UpperLeft, UpperRight: integer;
  283.             x, y, xinc, yinc: extended;
  284.             xfraction, yfraction, UpperAverage, LowerAverage: extended;
  285.     begin
  286.         if angle = 0.0 then begin
  287.                 GetLine(trunc(xstart), trunc(ystart), count, line);
  288.                 exit(GetObliqueLine);
  289.             end;
  290.         if angle = 270.0 then begin
  291.                 GetColumn(trunc(xstart), trunc(ystart), count, line);
  292.                 exit(GetObliqueLine);
  293.             end;
  294.         x := xstart;
  295.         y := ystart;
  296.         angle := (angle / 180.0) * pi;
  297.         xinc := cos(angle);
  298.         yinc := -sin(angle);
  299.         for i := 0 to count - 1 do begin
  300.                 xbase := trunc(x);
  301.                 ybase := trunc(y);
  302.                 xFraction := x - xbase;
  303.                 yFraction := y - ybase;
  304.                 LowerLeft := MyGetPixel(xbase, ybase);
  305.                 LowerRight := MyGetPixel(xbase + 1, ybase);
  306.                 UpperRight := MyGetPixel(xbase + 1, ybase + 1);
  307.                 UpperLeft := MyGetPixel(xbase, ybase + 1);
  308.                 UpperAverage := UpperLeft + xfraction * (UpperRight - UpperLeft);
  309.                 LowerAverage := LowerLeft + xfraction * (LowerRight - LowerLeft);
  310.                 line[i] := round(LowerAverage + yfraction * (UpperAverage - LowerAverage));
  311.                 x := x + xinc;
  312.                 y := y + yinc;
  313.             end;
  314.     end;
  315.  
  316.  
  317.     procedure DoResliceOptions;
  318.         var
  319.             default, tmp: extended;
  320.             Canceled: boolean;
  321.     begin
  322.         with info^.StackInfo^ do begin
  323.                 if SliceSpacing = 0.0 then
  324.                     default := 1.0
  325.                 else
  326.                     default := SliceSpacing;
  327.                 tmp := GetReal('Slice Spacing(pixels):', default, Canceled);
  328.                 if not Canceled and (tmp > 0.0) then
  329.                     SliceSpacing := tmp;
  330.             end;
  331.     end;
  332.  
  333.  
  334.     procedure Reslice;
  335.         const
  336.             Scale = 1.0;
  337.         var
  338.             DstWidth, DstHeight, nSlices: integer;
  339.             dstLeft, dstTop, y, i, LineLength: integer;
  340.             SaveWindowFlag, SaveMacro: boolean;
  341.             SaveHScale, SaveVScale, angle, UncalibratedLineLength, CalibratedLineLength: extended;
  342.             Stack, Reconstruction: InfoPtr;
  343.             aLine: LineType;
  344.             name, str1, str2: str255;
  345.             MaskRect: rect;
  346.             x1, y1, x2, y2: real;
  347.  
  348.         procedure MakeRoi (Left, Top, Width, Height: integer);
  349.         begin
  350.             with info^ do begin
  351.                     RoiType := RectRoi;
  352.                     SetRect(RoiRect, left, top, left + width, top + height);
  353.                     MakeRegion;
  354.                     SetupUndo;
  355.                     RoiShowing := true;
  356.                 end;
  357.         end;
  358.  
  359.     begin
  360.         with info^, info^.StackInfo^ do begin
  361.                 if nSlices < 2 then begin
  362.                         PutMessage('Reslicing requires at least 2 slices.');
  363.                         macro := false;
  364.                         exit(Reslice);
  365.                     end;
  366.                 if not (RoiShowing and (RoiType = LineRoi)) then begin
  367.                         PutMessage('Please make a straight line selection first.');
  368.                         macro := false;
  369.                         exit(Reslice);
  370.                     end;
  371.                 Stack := info;
  372.                 GetLoiLength;
  373.                 LineLength := round(uLength);
  374.                 if LineLength = 0 then begin
  375.                         PutMessage('Line length cannot be zero.');
  376.                         macro := false;
  377.                         exit(Reslice);
  378.                     end;
  379.                 if SliceSpacing = 0.0 then
  380.                     DoResliceOptions;
  381.                 GetLoi(x1, y1, x2, y2);
  382.                 GetAngle(x2 - x1, y1 - y2, angle);
  383.                 if (angle = 0.0) or (angle = 270.0) then
  384.                     if NotInBounds then
  385.                         exit(Reslice);
  386.                 DstWidth := round(LineLength * scale);
  387.                 DstHeight := round(nSlices * SliceSpacing * scale);
  388.                 RealToString(y1, 3, 0, str1);
  389.                 RealToString(angle, 1, 2, str2);
  390.                 name := concat(str1, '-', str2);
  391.                 nSlices := nSlices;
  392.                 if not NewPicWindow(name, DstWidth, DstHeight) then
  393.                     exit(Reslice);
  394.                 Reconstruction := info;
  395.                 SaveWindowFlag := rsCreateNewWindow;
  396.                 SaveHScale := rsHScale;
  397.                 SaveVScale := rsVScale;
  398.                 rsCreateNewWindow := false;
  399.                 rsMethod := bilinear;
  400.                 dstLeft := round((dstWidth - LineLength) / 2);
  401.                 dstTop := round((dstHeight - nSlices) / 2);
  402.                 for i := 1 to nSlices do begin
  403.                         Info := Stack;
  404.                         SelectSlice(i);
  405.                         GetObliqueLine(x1, y1, angle, LineLength, aLine);
  406.                         info := Reconstruction;
  407.                         PutLine(dstLeft, dstTop + nSlices - i, LineLength, aLine);
  408.                         if i = 1 then {Draw extra line needed to get scaling to work right.}
  409.                             PutLine(dstLeft, dstTop + nSlices, LineLength, aLine);
  410.                         SetRect(MaskRect, dstLeft, dstTop + nSlices - i, dstLeft + LineLength, dstTop + nSlices - i + 1);
  411.                         UpdateScreen(MaskRect);
  412.                     end;
  413.                 MakeRoi(dstLeft, dstTop, LineLength, nSlices);
  414.                 rsHScale := scale;
  415.                 rsVScale := SliceSpacing * scale;
  416.                 rsAngle := 0;
  417.                 SaveMacro := macro;
  418.                 macro := true;
  419.                 ScaleAndRotate;
  420.                 macro := SaveMacro;
  421.                 Info := Stack;
  422.                 SelectSlice(CurrentSlice);
  423.                 Info := Reconstruction;
  424.                 rsCreateNewWindow := SaveWindowFlag;
  425.                 rsHScale := SaveHScale;
  426.                 rsVScale := SaveVScale;
  427.                 KillRoi;
  428.             end;
  429.     end;
  430.  
  431.  
  432.     procedure Animate;
  433.         var
  434.             n, SaveN, fpsInterval, DelayCount: integer;
  435.             Event: EventRecord;
  436.             ch: char;
  437.             b: boolean;
  438.             SingleStep, GoForward, NewKeyDown, PhotoMode: boolean;
  439.             nFrames, StartTicks, NextTicks, SaveTicks, ticks: LongInt;
  440.             fps, seconds: extended;
  441.  
  442.         procedure ShowFPS (fps: extended);
  443.             var
  444.                 hstart, vstart, ivalue: integer;
  445.                 key: str255;
  446.         begin
  447.             if PhotoMode then
  448.                 exit(ShowFPS);
  449.             hstart := ValuesHStart;
  450.             vstart := ValuesVStart;
  451.             SetPort(ValuesWindow);
  452.             MoveTo(xValueLoc, vstart);
  453.             case DelayTicks of
  454.                 0: 
  455.                     key := '9 ';
  456.                 2: 
  457.                     key := '8 ';
  458.                 3: 
  459.                     key := '7 ';
  460.                 4: 
  461.                     key := '6 ';
  462.                 6: 
  463.                     key := '5 ';
  464.                 8: 
  465.                     key := '4 ';
  466.                 12: 
  467.                     key := '3 ';
  468.                 30: 
  469.                     key := '2 ';
  470.                 60: 
  471.                     key := '1 ';
  472.             end;
  473.             if SingleStep then begin
  474.                     if GoForward then
  475.                         key := '->'
  476.                     else
  477.                         key := '<-';
  478.                 end;
  479.             DrawString(key);
  480.             MoveTo(yValueLoc, vstart + 10);
  481.             DrawReal(fps, 1, 2);
  482.             DrawChar(' ');
  483.         end;
  484.  
  485.     begin
  486.         if info^.StackInfo = nil then begin
  487.                 PutMessage('Animation requires a stack.');
  488.                 exit(Animate);
  489.             end;
  490.         with info^, info^.StackInfo^ do begin
  491.                 if nSlices < 2 then begin
  492.                         PutMessage('Animation requires at least two "slices".');
  493.                         exit(Animate);
  494.                     end;
  495.                 KillRoi;
  496.                 PhotoMode := OptionKeyDown or OptionKeyWasDown;
  497.                 if PhotoMode then
  498.                     EraseScreen
  499.                 else begin
  500.                         ShowWatch;
  501.                         ShowMessage(concat('Use 1...9 keys to control speed', cr, 'Use arrow keys to single step', cr, 'Press mouse button to stop'));
  502.                     end;
  503.                 FlushEvents(EveryEvent, 0);
  504.                 fpsInterval := 10;
  505.                 SaveN := -1;
  506.                 n := 1;
  507.                 GoForward := true;
  508.                 SingleStep := false;
  509.                 nFrames := 0;
  510.                 StartTicks := TickCount;
  511.                 NextTicks := StartTicks;
  512.                 SaveTicks := StartTicks;
  513.                 if not PhotoMode then begin
  514.                         DrawLabels('key:', 'fps:', '');
  515.                         SetPort(ValuesWindow);
  516.                         TextSize(9);
  517.                         TextFont(Monaco);
  518.                         TextMode(SrcCopy);
  519.                     end;
  520.                 repeat
  521.                     b := WaitNextEvent(EveryEvent, Event, 0, nil);
  522.                     NewKeyDown := (event.what = KeyDown) or (event.what = AutoKey);
  523.                     if NewKeyDown then begin
  524.                             Ch := chr(BitAnd(Event.message, 127));
  525.                             SingleStep := false;
  526.                             case ord(ch) of
  527.                                 28, 44, 60, PageUp: {<-, <}
  528.                                     begin
  529.                                         SingleStep := true;
  530.                                         GoForward := false;
  531.                                         n := n - 1;
  532.                                         if n < 1 then
  533.                                             n := 1;
  534.                                         DelayTicks := 0
  535.                                     end; {left}
  536.                                 29, 46, 62, PageDown:  {->, >}
  537.                                     begin
  538.                                         SingleStep := true;
  539.                                         GoForward := true;
  540.                                         n := n + 1;
  541.                                         if n > nSlices then
  542.                                             n := nSlices;
  543.                                         DelayTicks := 0
  544.                                     end;  {right}
  545.                                 57: 
  546.                                     DelayTicks := 0;  {'9'-max speed}
  547.                                 56: 
  548.                                     DelayTicks := 2;  {'8'-30 fps}
  549.                                 55: 
  550.                                     DelayTicks := 3;  {'7'-20 fps}
  551.                                 54: 
  552.                                     DelayTicks := 4;  {'6'-15 fps}
  553.                                 53: 
  554.                                     DelayTicks := 6;  {'5'-10 fps}
  555.                                 52: 
  556.                                     DelayTicks := 8; {'4'-7.5 fps}
  557.                                 51: 
  558.                                     DelayTicks := 12; {'3'-5 fps}
  559.                                 50: 
  560.                                     DelayTicks := 30; {'2'-2 fps}
  561.                                 49: 
  562.                                     DelayTicks := 60; {'1'-1 fps}
  563.                                 otherwise
  564.                             end; {case}
  565.                             if DelayTicks > 12 then
  566.                                 fpsInterval := 2
  567.                             else if DelayTicks > 3 then
  568.                                 fpsInterval := 5
  569.                             else
  570.                                 fpsInterval := 10;
  571.                         end; {if NewKeyDown}
  572.                     if GoForward then begin
  573.                             if not SingleStep then
  574.                                 n := n + 1;
  575.                             if n > nSlices then begin
  576.                                     if OscillatingMovies then begin
  577.                                             n := nSlices - 1;
  578.                                             GoForward := false;
  579.                                         end
  580.                                     else
  581.                                         n := 1;
  582.                                 end;
  583.                         end
  584.                     else begin
  585.                             if not SingleStep then
  586.                                 n := n - 1;
  587.                             if n < 1 then begin
  588.                                     if OscillatingMovies then begin
  589.                                             n := 2;
  590.                                             Goforward := true;
  591.                                         end
  592.                                     else
  593.                                         n := nSlices;
  594.                                 end;
  595.                         end;
  596.                     CurrentSlice := n;
  597.                     SelectSlice(CurrentSlice);
  598.                     UpdatePicWindow;
  599.                     nFrames := nFrames + 1;
  600.                     if SingleStep then begin
  601.                             if (not OptionKeyWasDown) and (n <> SaveN) then begin
  602.                                     UpdateTitleBar;
  603.                                     SaveN := n;
  604.                                 end;
  605.                             ShowFPS(0.0);
  606.                         end
  607.                     else if (nFrames mod fpsInterval) = 0 then begin
  608.                             ticks := TickCount;
  609.                             seconds := (ticks - SaveTicks) / 60.0;
  610.                             if seconds <> 0.0 then
  611.                                 fps := fpsInterval / seconds
  612.                             else
  613.                                 fps := 0.0;
  614.                             ShowFPS(fps);
  615.                             SaveTicks := ticks;
  616.                         end;
  617.                     DelayCount := 0;
  618.                     if DelayTicks > 0 then begin
  619.                             repeat
  620.                                 ticks := TickCount;
  621.                             until ticks >= NextTicks;
  622.                             NextTicks := ticks + DelayTicks;
  623.                         end;
  624.                 until (event.what = MouseDown) or (event.what = osEvt);
  625.                 if PhotoMode then
  626.                     RestoreScreen;
  627.                 FlushEvents(EveryEvent, 0);
  628.             end; {with}
  629.     end;
  630.  
  631.  
  632.     procedure MakeMovie;
  633.         var
  634.             nFrames, wleft, wtop, width, height, frame, i: integer;
  635.             ignore, SaveFW: integer;
  636.             OutOfMemory: boolean;
  637.             DisplayPoint: point;
  638.             StartTicks, NextTicks, interval, ElapsedTime: LongInt;
  639.             SecondsBetweenFrames, seconds: extended;
  640.             frect: rect;
  641.             MainDevice: GDHandle;
  642.             SourcePixMap: PixMapHandle;
  643.             str1, str2, str3: str255;
  644.             Canceled: boolean;
  645.     begin
  646.         with info^ do begin
  647.                 if (PictureType <> QuickCaptureType) and (PictureType <> ScionType) then begin
  648.                         PutMessage('You must be capturing in order to make a movie.');
  649.                         exit(MakeMovie);
  650.                     end;
  651.                 StopDigitizing;
  652.                 if not (RoiShowing and (RoiType = RectRoi)) then begin
  653.                         PutMessage('Please make a rectangular selection first.');
  654.                         exit(MakeMovie);
  655.                     end;
  656.                 if NotInBounds then
  657.                     exit(MakeMovie);
  658.                 SaveFW := FramesWanted;
  659.                 FramesWanted := GetInt('Number of Frames:', FramesWanted, Canceled);
  660.                 if Canceled then begin
  661.                         FramesWanted := SaveFW;
  662.                         exit(MakeMovie);
  663.                     end;
  664.                 if FramesWanted < 1 then
  665.                     FramesWanted := 1;
  666.                 if FramesWanted > MaxSlices then
  667.                     FramesWanted := MaxSlices;
  668.                 with RoiRect do begin
  669.                         left := band(left + 1, $fffc);   {Word align}
  670.                         right := band(right + 2, $fffc);
  671.                         if right > PicRect.right then
  672.                             right := PicRect.right;
  673.                         MakeRegion;
  674.                         wleft := left;
  675.                         wtop := top;
  676.                         width := right - left;
  677.                         height := bottom - top;
  678.                     end;
  679.             end; {with info^}
  680.         if FrameGrabber = Scion then begin
  681.                 with DisplayPoint do begin
  682.                         h := PicLeftBase;
  683.                         v := PicTopBase;
  684.                     end;
  685.                 with frect do begin
  686.                         left := PicLeftBase + wleft;
  687.                         top := PicTopBase + wtop;
  688.                         right := left + width;
  689.                         bottom := top + height;
  690.                     end;
  691.             end
  692.         else
  693.             with frect do begin
  694.                     left := wleft;
  695.                     top := wtop;
  696.                     right := left + width;
  697.                     bottom := top + height;
  698.                 end;
  699.         if not NewPicWindow('Movie', width, height) then
  700.             exit(MakeMovie);
  701.         if not MakeStackFromWindow then
  702.             exit(MakeMovie);
  703.         nFrames := 1;
  704.         OutOfMemory := false;
  705.         while (nFrames < FramesWanted) and (not OutOfMemory) do begin
  706.                 OutOfMemory := not AddSlice(false);
  707.                 if not OutOfMemory then
  708.                     nFrames := nFrames + 1;
  709.             end;
  710.         if ExternalTrigger then
  711.             SecondsBetweenFrames := 0.0
  712.         else
  713.             SecondsBetweenFrames := GetReal('Delay Between Frames(seconds):', 0.0, Canceled);
  714.         if Canceled then
  715.             with info^ do begin
  716.                     changes := false;
  717.                     ignore := CloseAWindow(wptr);
  718.                     Exit(MakeMovie);
  719.                 end;
  720.         if SecondsBetweenFrames < 0.0 then
  721.             SecondsBetweenFrames := 0.0;
  722.         interval := round(60.0 * SecondsBetweenFrames);
  723.         if FrameGrabber = Scion then begin
  724.                 HideCursor;
  725.                 MainDevice := GetMainDevice;
  726.                 SourcePixMap := MainDevice^^.gdPMap;
  727.             end
  728.         else begin
  729.                 ShowWatch;
  730.                 SourcePixMap := qcPort^.portPixMap;
  731.                 ResetQuickCapture;
  732.             end;
  733.         ShowTriggerMessage;
  734.         StartTicks := TickCount;
  735.         NextTicks := StartTicks;
  736.         with info^, info^.StackInfo^ do begin
  737.                 if Interval >= 30 then
  738.                     ShowMessage(CmdPeriodToStop)
  739.                 else
  740.                     DrawLabels('Frame:', 'Total:', '');
  741.                 for frame := 1 to nFrames do begin
  742.                         CurrentSlice := frame;
  743.                         SelectSlice(CurrentSlice);
  744.                         NextTicks := NextTicks + Interval;
  745.                         if FrameGrabber = QuickCapture then begin
  746.                                 if Interval >= 30 then
  747.                                     UpdateTitleBar
  748.                                 else
  749.                                     Show2Values(CurrentSlice, nSlices);
  750.                                 GetQuickCaptureFrame;
  751.                                 CopyOffscreen(SourcePixMap, osPort^.portPixMap, frect, SrcRect);
  752.                                 if not BlindMovieCapture then
  753.                                     UpdatePicWindow;
  754.                             end
  755.                         else begin
  756.                                 GetScionFrame(DisplayPoint);
  757.                                 CopyOffscreen(SourcePixMap, osPort^.portPixMap, frect, SrcRect);
  758.                             end;
  759.                         while TickCount < NextTicks do
  760.                             if CommandPeriod then begin
  761.                                     beep;
  762.                                     wait(60);
  763.                                     exit(MakeMovie);
  764.                                 end;
  765.                     end; {for}
  766.                 seconds := (TickCount - StartTicks) / 60.0;
  767.                 LoopTime := seconds;
  768.             end; {with}
  769.         RealToString(seconds, 1, 2, str1);
  770.         str1 := concat(long2str(nFrames), ' frames', cr, str1, ' seconds', cr);
  771.         RealToString(seconds / nFrames, 1, 3, str2);
  772.         str3 := concat(str1, str2, ' seconds/frame', cr);
  773.         if nFrames >= seconds then
  774.             ShowFrameRate(str3, StartTicks, nFrames)
  775.         else
  776.             ShowMessage(str3);
  777.         ShowFirstOrLastSlice(HomeKey);
  778.     end;
  779.  
  780.  
  781.     procedure CaptureFrames;
  782.         var
  783.             nFrames, wleft, wtop, width, height, i: integer;
  784.             ignore, SaveFW: integer;
  785.             OutOfMemory, AdvanceFrame, b: boolean;
  786.             DisplayPoint: point;
  787.             frect: rect;
  788.             MainDevice: GDHandle;
  789.             SourcePixMap: PixMapHandle;
  790.             Event: EventRecord;
  791.             ShutterSound: handle;
  792.             err: OSErr;
  793.  
  794.         procedure CheckButton;
  795.         begin
  796.             if Button and not AdvanceFrame then
  797.                 with Info^.StackInfo^ do begin
  798.                         AdvanceFrame := true;
  799.                         ShutterSound := GetResource('snd ', 100);
  800.                         if ShutterSound <> nil then
  801.                             err := SndPlay(nil, ShutterSound, false);
  802.                         if CurrentSlice < nSlices then begin
  803.                                 CurrentSlice := CurrentSlice + 1;
  804.                                 UpdateTitleBar;
  805.                                 CurrentSlice := CurrentSlice - 1;
  806.                             end;
  807.                     end;
  808.         end;
  809.  
  810.     begin
  811.         with info^ do begin
  812.                 if (PictureType <> QuickCaptureType) and (PictureType <> ScionType) then begin
  813.                         PutMessage('You must be capturing in order to capture frames.');
  814.                         exit(CaptureFrames);
  815.                     end;
  816.                 StopDigitizing;
  817.                 if not (RoiShowing and (RoiType = RectRoi)) then begin
  818.                         PutMessage('Please make a rectangular selection first.');
  819.                         exit(CaptureFrames);
  820.                     end;
  821.                 if NotInBounds then
  822.                     exit(CaptureFrames);
  823.                 SaveFW := FramesWanted;
  824.                 ShutterSound := nil;
  825.                 with RoiRect do begin
  826.                         left := band(left + 1, $fffc);   {Word align}
  827.                         right := band(right + 2, $fffc);
  828.                         if right > PicRect.right then
  829.                             right := PicRect.right;
  830.                         MakeRegion;
  831.                         wleft := left;
  832.                         wtop := top;
  833.                         width := right - left;
  834.                         height := bottom - top;
  835.                     end;
  836.             end; {with info^}
  837.         if FrameGrabber = Scion then begin
  838.                 with DisplayPoint do begin
  839.                         h := PicLeftBase;
  840.                         v := PicTopBase;
  841.                     end;
  842.                 with frect do begin
  843.                         left := PicLeftBase + wleft;
  844.                         top := PicTopBase + wtop;
  845.                         right := left + width;
  846.                         bottom := top + height;
  847.                     end;
  848.             end
  849.         else
  850.             with frect do begin
  851.                     left := wleft;
  852.                     top := wtop;
  853.                     right := left + width;
  854.                     bottom := top + height;
  855.                 end;
  856.         if not NewPicWindow('Frames', width, height) then
  857.             exit(CaptureFrames);
  858.         if not MakeStackFromWindow then
  859.             exit(CaptureFrames);
  860.         UpdateTitleBar;
  861.         if FrameGrabber = Scion then begin
  862.                 HideCursor;
  863.                 MainDevice := GetMainDevice;
  864.                 SourcePixMap := MainDevice^^.gdPMap;
  865.             end
  866.         else begin
  867.                 ShowWatch;
  868.                 SourcePixMap := qcPort^.portPixMap;
  869.                 ResetQuickCapture;
  870.             end;
  871.         FlushEvents(EveryEvent, 0);
  872.         ExternalTrigger := false;
  873.         with info^, info^.StackInfo^ do begin
  874.                 ShowMessage(CmdPeriodToStop);
  875.                 OutOfMemory := false;
  876.                 AdvanceFrame := false;
  877.                 while (not OutOfMemory) and (CurrentSlice <= MaxSlices) do begin
  878.                         if AdvanceFrame then begin
  879.                                 OutOfMemory := not AddSlice(false);
  880.                                 AdvanceFrame := false;
  881.                             end;
  882.                         if FrameGrabber = QuickCapture then begin
  883.                                 GetQuickCaptureFrame;
  884.                                 CheckButton;
  885.                                 CopyOffscreen(SourcePixMap, osPort^.portPixMap, frect, SrcRect);
  886.                                 CheckButton;
  887.                                 UpdatePicWindow;
  888.                                 CheckButton;
  889.                             end
  890.                         else begin
  891.                                 GetScionFrame(DisplayPoint);
  892.                                 CheckButton;
  893.                                 CopyOffscreen(SourcePixMap, osPort^.portPixMap, frect, SrcRect);
  894.                                 CheckButton;
  895.                             end;
  896.                         b := WaitNextEvent(EveryEvent, Event, 0, nil);
  897.                         if event.what = KeyDown then
  898.                             leave;
  899.                     end; {while}
  900.             end; {with}
  901.         if ShutterSound <> nil then
  902.             ReleaseResource(ShutterSound);
  903.     end;
  904.  
  905. end.