1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        qtexport.cpp
3 // Purpose:
4 // Author:      Brett Bode
5 // Modified by:
6 // Created:     Fri 23 Feb 08:44:29 2007
7 // RCS-ID:
8 // Copyright:   (c) 2007 Iowa State University
9 // Licence:
10 /////////////////////////////////////////////////////////////////////////////
11 
12 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
13 #pragma implementation "qtexport.h"
14 #endif
15 
16 // For compilers that support precompilation, includes "wx/wx.h".
17 #include "wx/wxprec.h"
18 
19 #ifdef __BORLANDC__
20 #pragma hdrstop
21 #endif
22 
23 #ifndef WX_PRECOMP
24 #include "wx/wx.h"
25 #endif
26 
27 ////@begin includes
28 ////@end includes
29 
30 #include "Globals.h"
31 #include "qtexport.h"
32 #include "energyplotdialog.h"
33 
34 ////@begin XPM images
35 ////@end XPM images
36 
37 /*!
38  * QTExport type definition
39  */
40 
IMPLEMENT_DYNAMIC_CLASS(QTExport,wxDialog)41 IMPLEMENT_DYNAMIC_CLASS( QTExport, wxDialog )
42 
43 /*!
44  * QTExport event table definition
45  */
46 
47 BEGIN_EVENT_TABLE( QTExport, wxDialog )
48 
49 ////@begin QTExport event table entries
50 	EVT_RADIOBOX( ID_QT_MOVIE_RADIO, QTExport::OnQtMovieRadioSelected )
51 
52 ////@end QTExport event table entries
53 
54 END_EVENT_TABLE()
55 
56 /*!
57  * QTExport constructors
58  */
59 
60 QTExport::QTExport()
61 {
62     Init();
63 }
64 
QTExport(wxWindow * parent,wxWindowID id,const wxString & caption,const wxPoint & pos,const wxSize & size,long style)65 QTExport::QTExport( wxWindow* parent, wxWindowID id, const wxString& caption, const wxPoint& pos, const wxSize& size, long style )
66 {
67     Init();
68     Create(parent, id, caption, pos, size, style);
69 }
70 
71 /*!
72  * QTExport creator
73  */
74 
Create(wxWindow * parent,wxWindowID id,const wxString & caption,const wxPoint & pos,const wxSize & size,long style)75 bool QTExport::Create( wxWindow* parent, wxWindowID id, const wxString& caption, const wxPoint& pos, const wxSize& size, long style )
76 {
77 ////@begin QTExport creation
78     SetExtraStyle(wxWS_EX_BLOCK_EVENTS);
79     wxDialog::Create( parent, id, caption, pos, size, style );
80 
81     CreateControls();
82     if (GetSizer())
83     {
84         GetSizer()->SetSizeHints(this);
85     }
86     Centre();
87 ////@end QTExport creation
88     return true;
89 }
90 
91 /*!
92  * QTExport destructor
93  */
94 
~QTExport()95 QTExport::~QTExport()
96 {
97 ////@begin QTExport destruction
98 ////@end QTExport destruction
99 }
100 
101 /*!
102  * Member initialisation
103  */
104 
Init()105 void QTExport::Init()
106 {
107 ////@begin QTExport member initialisation
108     mMovieType = NULL;
109     mEPlotCheck = NULL;
110     mQTChoice = NULL;
111     mKeyFrameEdit = NULL;
112 ////@end QTExport member initialisation
113 }
114 /*!
115  * Control creation for QTExport
116  */
117 
CreateControls()118 void QTExport::CreateControls()
119 {
120 ////@begin QTExport content construction
121     QTExport* itemDialog1 = this;
122 
123     wxBoxSizer* itemBoxSizer2 = new wxBoxSizer(wxVERTICAL);
124     itemDialog1->SetSizer(itemBoxSizer2);
125 
126     wxString mMovieTypeStrings[] = {
127         _("&Frame Animation"),
128         _("&Normal Mode animation")
129     };
130     mMovieType = new wxRadioBox( itemDialog1, ID_QT_MOVIE_RADIO, _("Type of Movie"), wxDefaultPosition, wxDefaultSize, 2, mMovieTypeStrings, 0, wxRA_SPECIFY_ROWS );
131     mMovieType->SetSelection(0);
132     itemBoxSizer2->Add(mMovieType, 0, wxALIGN_CENTER_HORIZONTAL|wxALL, 5);
133 
134     mEPlotCheck = new wxCheckBox( itemDialog1, ID_EPLOT_CHECK, _("Include Energy Plot"), wxDefaultPosition, wxDefaultSize, 0 );
135     mEPlotCheck->SetValue(false);
136     if (ShowToolTips())
137         mEPlotCheck->SetToolTip(_("click to display the energy plot next to the animation for the frame animation."));
138     itemBoxSizer2->Add(mEPlotCheck, 0, wxALIGN_CENTER_HORIZONTAL|wxALL, 5);
139 
140     wxStaticLine* itemStaticLine5 = new wxStaticLine( itemDialog1, wxID_STATIC, wxDefaultPosition, wxDefaultSize, wxLI_HORIZONTAL );
141     itemBoxSizer2->Add(itemStaticLine5, 0, wxGROW|wxALL, 5);
142 
143     wxBoxSizer* itemBoxSizer6 = new wxBoxSizer(wxHORIZONTAL);
144     itemBoxSizer2->Add(itemBoxSizer6, 0, wxALIGN_CENTER_HORIZONTAL|wxALL, 5);
145 
146     wxStaticText* itemStaticText7 = new wxStaticText( itemDialog1, wxID_STATIC, _("QuickTime Compressor:"), wxDefaultPosition, wxDefaultSize, 0 );
147     itemBoxSizer6->Add(itemStaticText7, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);
148 
149     wxString mQTChoiceStrings[] = {
150         _("Cinepak"),
151         _("Graphics"),
152         _("Animation"),
153         _("MPEG4")
154     };
155     mQTChoice = new wxChoice( itemDialog1, ID_QT_COMPRESSOR_CHOICE, wxDefaultPosition, wxDefaultSize, 4, mQTChoiceStrings, 0 );
156     itemBoxSizer6->Add(mQTChoice, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);
157 
158     wxBoxSizer* itemBoxSizer9 = new wxBoxSizer(wxHORIZONTAL);
159     itemBoxSizer2->Add(itemBoxSizer9, 0, wxALIGN_CENTER_HORIZONTAL|wxALL, 5);
160 
161     wxStaticText* itemStaticText10 = new wxStaticText( itemDialog1, wxID_STATIC, _("Key frame rate:"), wxDefaultPosition, wxDefaultSize, 0 );
162     itemBoxSizer9->Add(itemStaticText10, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);
163 
164     mKeyFrameEdit = new wxTextCtrl( itemDialog1, ID_KEY_FRAME_EDIT, _T(""), wxDefaultPosition, wxDefaultSize, 0 );
165     if (ShowToolTips())
166         mKeyFrameEdit->SetToolTip(_("0 or 1 will produce a key frame every frame, higher values will result in smaller files, but lower quality."));
167     itemBoxSizer9->Add(mKeyFrameEdit, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);
168 
169     wxBoxSizer* itemBoxSizer12 = new wxBoxSizer(wxHORIZONTAL);
170     itemBoxSizer2->Add(itemBoxSizer12, 0, wxALIGN_RIGHT|wxALL, 5);
171 
172     wxButton* itemButton13 = new wxButton( itemDialog1, wxID_CANCEL, _("&Cancel"), wxDefaultPosition, wxDefaultSize, 0 );
173     itemBoxSizer12->Add(itemButton13, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);
174 
175     wxButton* itemButton14 = new wxButton( itemDialog1, wxID_OK, _("&OK"), wxDefaultPosition, wxDefaultSize, 0 );
176     itemButton14->SetDefault();
177     itemBoxSizer12->Add(itemButton14, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5);
178 
179 ////@end QTExport content construction
180 	mQTChoice->SetSelection(3);
181 	mKeyFrameEdit->SetValue(_T("2"));
182 }
183 
184 /*!
185 * wxEVT_COMMAND_RADIOBOX_SELECTED event handler for ID_QT_MOVIE_RADIO
186  */
187 
OnQtMovieRadioSelected(wxCommandEvent & event)188 void QTExport::OnQtMovieRadioSelected( wxCommandEvent& event )
189 {
190 	mEPlotCheck->Enable(mMovieType->GetSelection() == 0);
191 	event.Skip();
192 }
193 
194 /*!
195  * Should we show tooltips?
196  */
197 
ShowToolTips()198 bool QTExport::ShowToolTips()
199 {
200     return true;
201 }
202 
203 /*!
204  * Get bitmap resources
205  */
206 
GetBitmapResource(const wxString & name)207 wxBitmap QTExport::GetBitmapResource( const wxString& name )
208 {
209     // Bitmap retrieval
210 ////@begin QTExport bitmap retrieval
211     wxUnusedVar(name);
212     return wxNullBitmap;
213 ////@end QTExport bitmap retrieval
214 }
215 
216 /*!
217  * Get icon resources
218  */
219 
GetIconResource(const wxString & name)220 wxIcon QTExport::GetIconResource( const wxString& name )
221 {
222     // Icon retrieval
223 ////@begin QTExport icon retrieval
224     wxUnusedVar(name);
225     return wxNullIcon;
226 ////@end QTExport icon retrieval
227 }
228 
EnableFrameMovie(bool state)229 void QTExport::EnableFrameMovie(bool state) {
230 	if (state) {
231 		mMovieType->SetSelection(0);
232 		mMovieType->Enable(0, true);
233 		mEPlotCheck->Enable(true);
234 	} else {
235 		mMovieType->SetSelection(1);
236 		mMovieType->Enable(0, false);
237 		mEPlotCheck->Enable(false);
238 	}
239 }
SetMovieChoice(int v)240 void QTExport::SetMovieChoice(int v) {
241 	mMovieType->SetSelection(v);
242 }
EnableModeMovie(bool state)243 void QTExport::EnableModeMovie(bool state) {
244 	mMovieType->SetSelection(0);
245 	mMovieType->Enable(1, state);
246 }
247 
GetMovieChoice(void) const248 int QTExport::GetMovieChoice(void) const {
249 	return mMovieType->GetSelection();
250 }
AddEnergyPlot(void) const251 bool QTExport::AddEnergyPlot(void) const {
252 	return mEPlotCheck->IsChecked();
253 }
GetCompressorChoice(void) const254 int QTExport::GetCompressorChoice(void) const {
255 	return mQTChoice->GetSelection();
256 }
GetKeyFrameRate(void) const257 int QTExport::GetKeyFrameRate(void) const {
258 	long result = 0;
259 	wxString val = mKeyFrameEdit->GetValue();
260 	val.ToLong(&result);
261 	return result;
262 }
263 
264 #ifdef __MAC_USE_QUICKTIME__
265 #include "GlobalExceptions.h"
266 #include "Progress.h"
267 #include "MoleculeData.h"
268 #include "MolDisplayWin.h"
269 #include <QuickTime/Movies.h>
270 
271 #if wxCHECK_VERSION(2, 9, 0)
272 #include <wx/osx/private.h>
273 //This is a gross hack to get access to the picHandle in the wxBitmapRefData class
274 //that is no longer provided in the wx headers
275 class wxBitmapRefData {
276 public:
277 	PicHandle     GetPictHandle();
278 };
279 #else
280 #include <wx/mac/carbon/private.h>
281 #endif
282 
283 typedef struct qtData {
284 	Media theMedia;
285 	ImageDescriptionHandle imageDesc;
286 	ImageSequence seqID;
287 	Rect DisplayRect;
288 	Rect FullRect;
289 };
290 
WriteQTMovie(wxString & filepath)291 void MolDisplayWin::WriteQTMovie(wxString & filepath) {
292 	//Create a QuickTime movie using the standard animation codecs with normal quality, and
293 	//temporal compression. The final file is flattened for cross platform compatability
294 
295 	QTExport * QTOptions = new QTExport(this);
296 	//setup controls for the current data
297 	if (MainData->GetNumFrames() > 1) { //default to frame animation
298 		QTOptions->SetMovieChoice(0);
299 	} else {
300 		QTOptions->EnableFrameMovie(false);
301 	}
302 	if (MainData->cFrame->GetNumberNormalModes() <= 0) {
303 		QTOptions->EnableModeMovie(false);
304 	}
305 
306 	if (QTOptions->ShowModal() != wxID_OK) {
307 		//user cancelled the operation
308 		QTOptions->Destroy();
309 		return;
310 	}
311 	//retrieve the value of each option
312 	int MovieType = QTOptions->GetMovieChoice();
313 	bool IncludeEPlot = QTOptions->AddEnergyPlot();
314 	int compressorChoice = QTOptions->GetCompressorChoice();
315 	int keyFrameRate = QTOptions->GetKeyFrameRate();
316 	if (keyFrameRate < 0) keyFrameRate = 0;
317 
318 	QTOptions->Destroy();
319 
320 	CodecType mCodec;
321 	switch (compressorChoice) {
322 		case 0:
323 			mCodec = kCinepakCodecType;
324 			break;
325 		case 1:
326 			mCodec = kGraphicsCodecType;
327 			break;
328 		case 2:
329 			mCodec = kAnimationCodecType;
330 			break;
331 		case 3:
332 		default:
333 			mCodec = kMPEG4VisualCodecType;
334 	}
335 
336 	OSStatus s;
337 	OSErr myErr = myErr;
338 	FSSpec targetSpec;
339 	//ugh I need to get an FSSpec to hand to quicktime, but these calls only seem to work if
340 	//the file already exists...
341 	const char * t = filepath.mb_str(wxConvUTF8);
342 	FILE * temp = fopen(t, "wb");
343 	fclose(temp);
344 
345 #ifdef __WXOSX_COCOA__
346 	//This function is not found in the wxCocoa implementation, it is probably possible to work around it
347 	//Otherwise the code appears to link and run currently. However, it is probably better to redue the
348 	//code to use the Cocoa qtKit framework rather than the old Carbon QT library.
349 
350 	//This path is not tested as the current Cocoa code does not properly support the extended save dialog.
351 	//	void wxMacFilename2FSSpec( const wxString& path , FSSpec *spec )
352 	{
353 		OSStatus err = noErr;
354 		FSRef fsRef;
355 		wxMacPathToFSRef( filepath , &fsRef );
356 		err = FSGetCatalogInfo(&fsRef, kFSCatInfoNone, NULL, NULL, &targetSpec, NULL);
357 		verify_noerr( err );
358 	}
359 #else
360 	wxMacFilename2FSSpec(filepath, &targetSpec);
361 #endif
362 
363 	Movie	theMovie = NULL;
364 
365 	FSSpec tempSpec = targetSpec;
366 	strcpy((char *) &(tempSpec.name[1]), "MacMolPlt8933tempMovie");
367 	tempSpec.name[0] = 22;
368 
369 	BeginOperation();
370 	ProgressInd->ChangeText("Creating movie...");
371 
372 	myErr = EnterMovies();	//initialize the quicktime manager
373 	if (myErr != noErr) {
374 		FinishOperation();
375 		MessageAlert("Error initializing QuickTime!");
376 		return;
377 	}
378 		//Create the movie file and initialize file data
379 		//Use Quicktime creator code 'TVOD' instead of simpletext 'ttxt'
380 	short	resRefNum = 0;
381 	short	resId = 0;
382 	myErr = CreateMovieFile(&tempSpec, 'TVOD', smCurrentScript, createMovieFileDeleteCurFile,
383 							&resRefNum, &theMovie);
384 	if (myErr != noErr) {
385 		MessageAlert("Error creating movie file!");
386 	} else {
387 		bool KillEPlot = false;
388 		int width, height, savedEPlotWidth, savedEPlotHeight;
389 		glCanvas->GetClientSize(&width, &height);
390 		Rect lDisplayRect={0,0,0,0};
391 		lDisplayRect.right = width;
392 		lDisplayRect.bottom = height;
393 		Rect		gRect = lDisplayRect;
394 
395 		Rect EPlotRect = lDisplayRect;
396 		//If we are including an energy plot add space for it here
397 		if (IncludeEPlot && (MovieType == 0)) {
398 			EPlotRect.left = EPlotRect.right;
399 			EPlotRect.right = EPlotRect.left + height;
400 			if (!energyPlotWindow) {
401 				energyPlotWindow = new EnergyPlotDialog(this);
402 				KillEPlot = true;
403 			} else {
404 				energyPlotWindow->GetSize(&savedEPlotWidth, &savedEPlotHeight);
405 			}
406 			gRect.right += height;
407 			width += height;
408 			energyPlotWindow->Show(false);
409 			energyPlotWindow->SetSize(height, height);
410 			energyPlotWindow->Update();	//This is needed to initialise the window if we just created it
411 		}
412 
413 		LocalToGlobal ((Point *) &(gRect.top));
414 		LocalToGlobal ((Point *) &(gRect.bottom));
415 		WindowRef TempWindow;
416 		s = CreateNewWindow(kDocumentWindowClass, kWindowNoAttributes, &gRect, &TempWindow);
417 		if (s == noErr) {
418 													//Create the video track
419 			Track theTrack = NewMovieTrack (theMovie, FixRatio(width,1),
420 											FixRatio(height,1), kNoVolume);
421 			if ((noErr == GetMoviesError())&&theTrack) {
422 				Media theMedia = NewTrackMedia (theTrack, VideoMediaType,
423 												60, // Video Time Scale
424 												NULL, 0);
425 				if ((noErr == GetMoviesError())&&theMedia) {
426 					myErr = BeginMediaEdits (theMedia);
427 					if (myErr == noErr) {
428 						//create the actual movie frames
429 						GWorldPtr	lgWorld=NULL;
430 
431 						if (! NewGWorld (&lgWorld, 0, &gRect, (CTabHandle) NULL, (GDHandle) NULL,
432 										 (GWorldFlags) (pixPurge + useTempMem))) {
433 							long MaxCompressedSize;
434 							ImageSequence seqID;
435 							ImageDescriptionHandle imageDesc = (ImageDescriptionHandle)NewHandle(4);
436 							PixMapHandle myPixMap = GetPortPixMap(lgWorld);
437 							LockPixels (myPixMap);
438 							myErr = CompressSequenceBegin(&seqID, myPixMap, NULL, &gRect, &gRect, 0,
439 														  mCodec, bestCompressionCodec, codecNormalQuality, codecNormalQuality, keyFrameRate, NULL,
440 														  codecFlagUpdatePreviousComp, imageDesc);
441 							GetMaxCompressionSize (myPixMap, &gRect,
442 												   0, codecNormalQuality, mCodec, (CompressorComponent) anyCodec, &MaxCompressedSize);
443 							Handle Buffer = TempNewHandle(MaxCompressedSize, &myErr);
444 							if (!Buffer)
445 								Buffer = NewHandle(MaxCompressedSize);
446 							if (Buffer) {
447 								qtData myqtData = {theMedia, imageDesc, seqID, lDisplayRect, gRect};
448 								if (MovieType == 0) {
449 									CreateFrameMovie(lgWorld, Buffer, myqtData, IncludeEPlot);
450 								} else {
451 									CreateModeMovie(lgWorld, Buffer, myqtData);
452 								}
453 								DisposeHandle(Buffer);
454 							}
455 							myErr = CDSequenceEnd(seqID);
456 							if (lgWorld != NULL) DisposeGWorld (lgWorld);
457 							if (imageDesc) DisposeHandle((Handle) imageDesc);
458 						}
459 
460 						myErr = EndMediaEdits (theMedia);
461 					}
462 					myErr = InsertMediaIntoTrack (theTrack, 0,/* track start time */
463 						0,        /* media start time */
464 						GetMediaDuration (theMedia),
465 						FixRatio(1,1));
466 				}
467 				myErr = AddMovieResource (theMovie, resRefNum, &resId, NULL);
468 			}
469 			if (resRefNum) {
470 						//Create the actual file as a flat data fork so it can be placed on the www
471 				ProgressInd->ChangeText("Flattening movie�");
472 				FlattenMovie(theMovie, flattenAddMovieToDataFork, &targetSpec, 'TVOD', smCurrentScript,
473 							 createMovieFileDeleteCurFile, &resId, NULL);
474 				CloseMovieFile (resRefNum);
475 			}
476 			DisposeWindow(TempWindow);
477 		}
478 		DisposeMovie (theMovie);
479 		DeleteMovieFile (&tempSpec);	//delete the temp file after disposing of the movie
480 
481 		if (energyPlotWindow) {
482 			if (KillEPlot) {
483 				delete energyPlotWindow;
484 				energyPlotWindow = NULL;
485 			} else {
486 				energyPlotWindow->SetSize(savedEPlotWidth, savedEPlotHeight);
487 				energyPlotWindow->FrameChanged();
488 				energyPlotWindow->Show(true);
489 			}
490 		}
491 	}
492 	ExitMovies();	//Close out quicktime as we are done with it for now
493 	FinishOperation();
494 }
CreateFrameMovie(GWorldPtr lgWorld,Handle CompressedData,const qtData & myqtData,bool IncludeEPlot)495 void MolDisplayWin::CreateFrameMovie(GWorldPtr lgWorld, Handle CompressedData,
496 									 const qtData & myqtData, bool IncludeEPlot) {
497 	OSErr	myErr;
498 	long AnimateTime = Prefs->GetAnimateTime();
499 	if (AnimateTime <= 0) AnimateTime = 1;
500 	long SavedFrameNum = MainData->GetCurrentFrame();
501 	Rect	lDisplayRect = myqtData.DisplayRect;
502 	Rect	EPlotRect;
503 	EPlotRect = myqtData.DisplayRect;
504 	EPlotRect.left = EPlotRect.right;
505 	EPlotRect.right = myqtData.FullRect.right;
506 	ProgressInd->SetScaleFactor(100.0/((float) MainData->NumFrames));
507 
508 	for (long i=1; i<=MainData->NumFrames; i++) {
509 		ProgressInd->UpdateProgress(i);
510 		MainData->SetCurrentFrame(i);
511 		//Check for and update any surfaces depending on the screen plane
512 		Surface * temp = MainData->cFrame->SurfaceList;
513 		while (temp) {
514 			temp->RotateEvent(MainData);
515 			temp = temp->GetNextSurface();
516 		}
517 		MainData->ResetRotation();
518 		ReleaseLists();
519 		DrawGL();
520 
521 		//	create a pict of the current molecule display
522 		wxImage mImage = glCanvas->getImage(0,0);
523 		wxBitmap * mBitmap = new wxBitmap(mImage);
524 		//The following utilizes a Mac specific internal pair of calls
525 		//to get a PicHandle from a wxBitmap.
526 		wxBitmapRefData * mBitmapData = mBitmap->GetBitmapData();
527 		PicHandle tempPict = mBitmapData->GetPictHandle();
528 
529 		CGrafPtr	lSavedPort;
530 		GDHandle	lSavedGDH;
531 		long		dataSize;
532 		unsigned char similarity;
533 
534 		if (tempPict) {	//Got a PICT, draw it into the GWorld
535 			HLock(CompressedData);
536 			Ptr compressedDataPtr = *CompressedData;
537 			GetGWorld (&lSavedPort, &lSavedGDH);
538 			SetGWorld (lgWorld, NULL);
539 
540 			EraseRect(&lDisplayRect);
541 			DrawPicture(tempPict, &(lDisplayRect));
542 
543 			delete mBitmap;
544 
545 			if (IncludeEPlot) {
546 				energyPlotWindow->FrameChanged();
547 				wxBitmap * ePlotBitMap = NULL;
548 				energyPlotWindow->CopyToBitMap(&ePlotBitMap);
549 				if (ePlotBitMap) {
550 					wxBitmapRefData * mBitmapData = mBitmap->GetBitmapData();
551 					PicHandle tempPict = mBitmapData->GetPictHandle();
552 					if (tempPict) {
553 						SetGWorld (lgWorld, NULL);
554 
555 						EraseRect(&EPlotRect);
556 						DrawPicture(tempPict, &(EPlotRect));
557 					}
558 					delete ePlotBitMap;
559 				}
560 			}
561 
562 			SetGWorld (lSavedPort, lSavedGDH);
563 
564 			PixMapHandle myPixMap = GetPortPixMap(lgWorld);
565 			myErr = CompressSequenceFrame(myqtData.seqID, myPixMap, &(myqtData.FullRect),
566 										  codecFlagUpdatePreviousComp, compressedDataPtr, &dataSize, &similarity, NULL);
567 
568 			TimeValue test;//I don't use this value, but Carbon requires it
569 			myErr = AddMediaSample(myqtData.theMedia, CompressedData, 0,    /* no offset in data */
570 				dataSize, AnimateTime,
571 				(SampleDescriptionHandle)myqtData.imageDesc, 1,    /* one sample */
572 				0,    /* self-contained samples */
573 				&test);
574 		}
575 	}
576 	MainData->SetCurrentFrame(SavedFrameNum);
577 	MainData->ResetRotation();
578 	ReleaseLists();
579 	DrawGL();
580 }
CreateModeMovie(GWorldPtr lgWorld,Handle CompressedData,const qtData & myqtData)581 void MolDisplayWin::CreateModeMovie(GWorldPtr lgWorld, Handle CompressedData,
582 									const qtData & myqtData) {
583 	float		offsetFactor;
584 	bool		savedrawmode=false;
585 	Rect		lDisplayRect = myqtData.DisplayRect;
586 
587 	if (!MainData->cFrame->Vibs) return;
588 	Frame * lFrame = MainData->cFrame;
589 	if (MainData->GetDrawMode()) {
590 		savedrawmode = true;
591 		if (!Prefs->GetAnimateMode()) MainData->SetDrawMode(false);
592 	}
593 	long cmode = (lFrame->NumAtoms)*(lFrame->Vibs->CurrentMode);
594 	offsetFactor = 1.0/(4.5*Prefs->GetAnimationSpeed());
595 	float	VectorScale = Prefs->GetVectorScale();
596 	long AnimationSpeed = Prefs->GetAnimationSpeed();
597 	CPoint3D * ModeOffset = new CPoint3D[lFrame->NumAtoms];
598 	CPoint3D * SavedAtoms = new CPoint3D[lFrame->NumAtoms];
599 	if (!ModeOffset || !SavedAtoms) {
600 		return;	//insufficient memory
601 	}
602 	mpAtom * lAtoms = lFrame->Atoms;
603 	long iatm;
604 	for (iatm=0; iatm<(lFrame->NumAtoms); iatm++) {
605 		SavedAtoms[iatm] = lAtoms[iatm].Position;
606 		ModeOffset[iatm] = lFrame->Vibs->NormMode[iatm+cmode];
607 		ModeOffset[iatm] *= VectorScale;
608 	}
609 	MainData->ResetRotation();
610 	ReleaseLists();
611 	DrawGL();
612 
613 	OSErr	myErr;
614 	long npoint = 0;
615 	long inc = 1;
616 	ProgressInd->SetScaleFactor(100.0/((float) 4*AnimationSpeed));
617 	for (long i=0; i<4*AnimationSpeed; i++) {
618 		ProgressInd->UpdateProgress(i);
619 		if ((npoint==AnimationSpeed)||(npoint==-AnimationSpeed)) {
620 			inc *= -1;
621 			offsetFactor *= -1.0;
622 		}
623 		npoint += inc;
624 
625 		//	create a pict of the current molecule display
626 		wxImage mImage = glCanvas->getImage(0,0);
627 		wxBitmap * mBitmap = new wxBitmap(mImage);
628 		//The following utilizes a Mac specific internal pair of calls
629 		//to get a PicHandle from a wxBitmap.
630 		wxBitmapRefData * mBitmapData = mBitmap->GetBitmapData();
631 		PicHandle tempPict = mBitmapData->GetPictHandle();
632 
633 		CGrafPtr	lSavedPort;
634 		GDHandle	lSavedGDH;
635 		long		dataSize;
636 		unsigned char similarity;
637 
638 		if (tempPict) {	//Got a PICT, draw it into the GWorld
639 			HLock(CompressedData);
640 			Ptr compressedDataPtr = *CompressedData;
641 
642 			GetGWorld (&lSavedPort, &lSavedGDH);
643 			SetGWorld (lgWorld, NULL);
644 
645 			EraseRect(&lDisplayRect);
646 			DrawPicture(tempPict, &(lDisplayRect));
647 
648 			delete mBitmap;
649 
650 			SetGWorld (lSavedPort, lSavedGDH);
651 
652 			PixMapHandle myPixMap = GetPortPixMap(lgWorld);
653 			myErr = CompressSequenceFrame(myqtData.seqID, myPixMap, &lDisplayRect,
654 										  codecFlagUpdatePreviousComp, compressedDataPtr, &dataSize, &similarity, NULL);
655 
656 			TimeValue test;//I don't use this value, but Carbon requires it
657 			myErr = AddMediaSample(myqtData.theMedia, CompressedData, 0,    /* no offset in data */
658 					dataSize, 1,
659 					(SampleDescriptionHandle)myqtData.imageDesc, 1,    /* one sample */
660 					0,    /* self-contained samples */
661 					&test);
662 		}
663 		for (iatm=0; iatm<(lFrame->NumAtoms); iatm++) {
664 			lAtoms[iatm].Position.x += offsetFactor*(ModeOffset[iatm].x);
665 			lAtoms[iatm].Position.y += offsetFactor*(ModeOffset[iatm].y);
666 			lAtoms[iatm].Position.z += offsetFactor*(ModeOffset[iatm].z);
667 		}
668 
669 		MainData->ResetRotation();
670 		ReleaseLists();
671 		DrawGL();
672 	}
673 	for (iatm=0; iatm<(lFrame->NumAtoms); iatm++) {
674 		lAtoms[iatm].Position = SavedAtoms[iatm];
675 	}
676 	MainData->ResetRotation();
677 
678 	if (ModeOffset) delete [] ModeOffset;
679 	if (SavedAtoms) delete [] SavedAtoms;
680 	MainData->SetDrawMode(savedrawmode);
681 	ReleaseLists();
682 	DrawGL();
683 }
684 
685 #endif
686