FreeWRL/FreeX3D  3.0.0
Snapshot.c
1 /*
2 
3 
4 CProto ???
5 
6 */
7 
8 
9 /****************************************************************************
10  This file is part of the FreeWRL/FreeX3D Distribution.
11 
12  Copyright 2009 CRC Canada. (http://www.crc.gc.ca)
13 
14  FreeWRL/FreeX3D is free software: you can redistribute it and/or modify
15  it under the terms of the GNU Lesser Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  FreeWRL/FreeX3D is distributed in the hope that it will be useful,
20  but WITHOUT ANY WARRANTY; without even the implied warranty of
21  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22  GNU General Public License for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with FreeWRL/FreeX3D. If not, see <http://www.gnu.org/licenses/>.
26 ****************************************************************************/
27 
28 
29 #include <config.h>
30 
31 #if !defined(FRONTEND_DOES_SNAPSHOTS)
32 
33 #include <system.h>
34 #include <display.h>
35 #include <internal.h>
36 
37 #include <libFreeWRL.h>
38 
39 #include "../vrml_parser/Structs.h"
40 #include "headers.h"
41 #include "../vrml_parser/CParseGeneral.h"
42 #include "../world_script/CScripts.h"
43 #include "Snapshot.h"
44 #include "../scenegraph/Collision.h"
45 #include "../scenegraph/quaternion.h"
46 #include "../scenegraph/Viewer.h"
47 #include "../input/SensInterps.h"
48 #include "../x3d_parser/Bindable.h"
49 
50 #if HAVE_DIRENT_H
51 # include <dirent.h>
52 #endif
53 
54 
56 //int snapRawCount=0;
57 //int snapGoodCount=0;
58 //
59 //#if defined(DOSNAPSEQUENCE)
61 //int snapsequence=FALSE; /* --seq - snapshot sequence, not single click */
62 //int maxSnapImages=100; /* --maximg command line parameter */
63 //char *snapseqB = NULL; /* --seqb - snap sequence base filename */
64 //#endif
65 //
66 //int snapGif = FALSE; /* --gif save as an animated GIF, not mpg */
67 //char *snapsnapB = NULL; /* --snapb -single snapshot files */
68 //const char default_seqtmp[] = "freewrl_tmp"; /* default value for seqtmp */
69 //char *seqtmp = NULL; /* --seqtmp - directory for temp files */
70 //int doSnapshot = FALSE; /* are we doing a snapshot? */
71 //int doPrintshot = FALSE; /* are we taking a snapshot in order to print? */
72 //int savedSnapshot = FALSE;
73 
74 
75 typedef struct pSnapshot{
76  /* snapshot stuff */
77  int snapRawCount;//=0;
78  int snapGoodCount;//=0;
79 
80 #if defined(DOSNAPSEQUENCE)
81  /* need to re-implement this for OSX generating QTVR */
82  int snapsequence;//=FALSE; /* --seq - snapshot sequence, not single click */
83  int maxSnapImages;//=100; /* --maximg command line parameter */
84  char *snapseqB;// = NULL; /* --seqb - snap sequence base filename */
85 #endif
86 
87  int snapGif;// = FALSE; /* --gif save as an animated GIF, not mpg */
88  char *snapsnapB;// = NULL; /* --snapb -single snapshot files */
89  const char *default_seqtmp;// = "freewrl_tmp"; /* default value for seqtmp */
90  char *seqtmp;// = NULL; /* --seqtmp - directory for temp files */
91  int doSnapshot;// = FALSE; /* are we doing a snapshot? */
92  int doPrintshot;// = FALSE; /* are we taking a snapshot in order to print? */
93  int savedSnapshot;// = FALSE;
94  int modeTesting; //when generating test fixtures and playback with commandline -R,-F,-P - for linux just save .rgb don't convert image
95 }* ppSnapshot;
96 void *Snapshot_constructor()
97 {
98  void *v = MALLOCV(sizeof(struct pSnapshot));
99  memset(v,0,sizeof(struct pSnapshot));
100  return v;
101 }
102 //void Snapshot_destructor(void *t)
103 //{
104 // struct pSnapshot* tt = (struct tSnapshot*)t;
105 // free(tt);
106 //}
107 void Snapshot_init(struct tSnapshot* t)
108 {
109  //public
110  t->doSnapshot = FALSE;
111  //private
112  t->prv = Snapshot_constructor();
113  {
114  ppSnapshot p = (ppSnapshot)t->prv;
115  /* snapshot stuff */
116  p->snapRawCount=0;
117  p->snapGoodCount=0;
118 
119  #if defined(DOSNAPSEQUENCE)
120  /* need to re-implement this for OSX generating QTVR */
121  p->snapsequence=FALSE; /* --seq - snapshot sequence, not single click */
122  p->maxSnapImages=100; /* --maximg command line parameter */
123  p->snapseqB = NULL; /* --seqb - snap sequence base filename */
124  #endif
125 
126  p->snapGif = FALSE; /* --gif save as an animated GIF, not mpg */
127  p->snapsnapB = NULL; /* --snapb -single snapshot files */
128  p->default_seqtmp = "freewrl_tmp"; /* default value for seqtmp */
129  p->seqtmp = NULL; /* --seqtmp - directory for temp files */
130  p->doSnapshot = FALSE; /* are we doing a snapshot? */
131  p->doPrintshot = FALSE; /* are we taking a snapshot in order to print? */
132  p->savedSnapshot = FALSE;
133  p->modeTesting = FALSE;
134 
135  }
136 }
137 //bool do_Snapshot(){
138 // if( ((struct tSnapshot*)(gglobal()->Snapshot))->doSnapshot )return true;
139 // return false;
140 //}
141 void set_snapsequence(int on)
142 {
143 #ifdef DOSNAPSEQUENCE
144  //struct pSnapshot* p = (struct pSnapshot*)gglobal()->Snapshot.prv;
145  ppSnapshot p = (ppSnapshot)gglobal()->Snapshot.prv;
146  p->snapsequence = on;
147 #endif
148 }
149 #ifdef DOSNAPSEQUENCE
150 /* need to re-implement this for OSX generating QTVR */
151 void saveSnapSequence();
152 #endif
153 void set_snapshotModeTesting(int value)
154 {
155  ppSnapshot p = (ppSnapshot)gglobal()->Snapshot.prv;
156  p->modeTesting = value;
157 }
158 int isSnapshotModeTesting()
159 {
160  struct tSnapshot* t = &gglobal()->Snapshot;
161  struct pSnapshot* p = (struct pSnapshot*)t->prv;
162  return p->modeTesting;
163 }
164 
165 void fwl_set_SeqFile(const char* file)
166 {
167 #if defined(DOSNAPSEQUENCE)
168  /* need to re-implement this for OSX generating QTVR */
169  //struct pSnapshot* p = (struct pSnapshot*)gglobal()->Snapshot.prv;
170  ppSnapshot p = (ppSnapshot)gglobal()->Snapshot.prv;
171  p->snapseqB = STRDUP(file);
172  printf("snapseqB is %s\n", p->snapseqB);
173 #else
174  WARN_MSG("Call to fwl_set_SeqFile when Snapshot Sequence not compiled in.\n");
175 #endif
176 }
177 
178 void fwl_set_SnapFile(const char* file)
179 {
180  ppSnapshot p = (ppSnapshot)gglobal()->Snapshot.prv;
181 
182  p->snapsnapB = STRDUP(file);
183  TRACE_MSG("snapsnapB set to %s\n", p->snapsnapB);
184  printf("%s\n",p->snapsnapB);
185 }
186 
187 void fwl_set_MaxImages(int max)
188 {
189 #if defined(DOSNAPSEQUENCE)
190  /* need to re-implement this for OSX generating QTVR */
191  //struct pSnapshot* p = (struct pSnapshot*)gglobal()->Snapshot.prv;
192  ppSnapshot p = (ppSnapshot)gglobal()->Snapshot.prv;
193 
194  if (max <=0)
195  max = 100;
196  p->maxSnapImages = max;
197 #else
198  WARN_MSG("Call to fwl_set_MaxImages when Snapshot Sequence not compiled in.\n");
199 #endif
200 }
201 //typedef struct tSnapshot* ttSnapshot;
202 //typedef struct pSnapshot* ppSnapshot;
203 //#define TSNAPSHOT &gglobal()->Snapshot
204 //#define PSNAPSHOT (ppSnapshot)&gglobal()->Snapshot.prv
205 //typedef tglobal* ttglobal;
206 void fwl_set_SnapTmp(const char* file)
207 {
208  {
209  ttglobal tg = gglobal();
210  tg->Snapshot.doSnapshot = FALSE;
211  //{
212  // ((ppSnapshot)tg->Snapshot.prv)->seqtmp = STRDUP(file);
213  //}
214  {
215  ppSnapshot p = (ppSnapshot)tg->Snapshot.prv;
216  p->seqtmp = STRDUP(file);
217  TRACE_MSG("seqtmp set to %s\n", p->seqtmp);
218  }
219 
220  }
221  //{
222  // ttSnapshot t = TSNAPSHOT;
223  // ppSnapshot p = PSNAPSHOT;
224  // t->doSnapshot = FALSE;
225  // p->seqtmp = STRDUP(file);
226  // TRACE_MSG("seqtmp set to %s\n", p->seqtmp);
227  //}
228  //{
229  // struct tSnapshot* t = &gglobal()->Snapshot;
230  // struct pSnapshot* p = (struct pSnapshot*)t->prv;
231  // p->seqtmp = STRDUP(file);
232  // TRACE_MSG("seqtmp set to %s\n", p->seqtmp);
233  //}
234  //{
235  // struct pSnapshot* p = (struct pSnapshot*)gglobal()->Snapshot.prv;
236  // p->seqtmp = STRDUP(file);
237  // TRACE_MSG("seqtmp set to %s\n", p->seqtmp);
238  //}
239 }
240 
241 
242 
243 #ifdef _MSC_VER
244 static char * grabScreen(int bytesPerPixel, int x, int y, int width, int height)
245 {
246  /* copies opengl window pixels into a buffer */
247  int pixelType;
248  char *buffer;
249  if(bytesPerPixel == 3) pixelType = GL_RGB;
250  if(bytesPerPixel == 4) pixelType = GL_RGBA;
251  buffer = MALLOC (GLvoid *, bytesPerPixel*width*height*sizeof(char));
252 
253  /* grab the data */
254  FW_GL_PIXELSTOREI (GL_UNPACK_ALIGNMENT, 1);
255  FW_GL_PIXELSTOREI (GL_PACK_ALIGNMENT, 1);
256 
257  FW_GL_READPIXELS (x,y,width,height,pixelType,GL_UNSIGNED_BYTE, buffer);
258  return buffer;
259 }
260 #endif //_MSC_VER
261 
262 #if defined( _MSC_VER) || defined (IPHONE)
263 /* stubbs for now */
264 void setSnapshot() {}
265 void fwl_toggleSnapshot(){}
266 void fwl_init_SnapGif(){}
267 void saveSnapSequence() {}
268 #endif
269 
270 #ifdef IPHONE
271 void Snapshot () {}
272 #endif
273 
274 #ifndef IPHONE
275 
276 //#ifndef _MSC_VER
277 //#include <windows.h>
278 //#define FDWORD DWORD
279 //#define FLONG LONG
280 //#define FWORD WORD
281 //#define FBYPTE BYTE
282 //#define FBI_RGB BI_RGB
283 //#define FWBITMAPINFOHEADER BITMAPINFOHEADER
284 //#define FWBITMAPFILEHEADER BITMAPFILEHEADER
285 //#define FWBITMAPINFO BITMAPINFO
286 //#else
288 #define FDWORD unsigned long
289 #define FLONG long
290 #define FWORD unsigned short
291 #define FBYTE unsigned char
292 #define FBI_RGB 0L
293 
294 typedef struct {
295  FDWORD biSize;
296  FLONG biWidth;
297  FLONG biHeight;
298  FWORD biPlanes;
299  FWORD biBitCount;
300  FDWORD biCompression;
301  FDWORD biSizeImage;
302  FLONG biXPelsPerMeter;
303  FLONG biYPelsPerMeter;
304  FDWORD biClrUsed;
305  FDWORD biClrImportant;
307 //#include <pshpack2.h> //puspack and poppack are all to fix the WORD bfType struct 4-byte alignment problem
308 //I just took bfType out, then I don't need special packing on a 32bit system. Not sure about 64.
309 typedef struct {
310  //FWORD bfType;
311  FDWORD bfSize;
312  FWORD bfReserved1;
313  FWORD bfReserved2;
314  FDWORD bfOffBits;
316 //#include <poppack.h>
317 typedef struct {
318  FBYTE rgbBlue;
319  FBYTE rgbGreen;
320  FBYTE rgbRed;
321  FBYTE rgbReserved;
322 } FWRGBQUAD;
323 
324 typedef struct {
325  FWBITMAPINFOHEADER bmiHeader;
326  FWRGBQUAD bmiColors[1];
327 } FWBITMAPINFO;
328 //#endif
329 
330 //is this like htonl ?
331 static void fromLong(unsigned long myword, char *buffer)
332 {
333  buffer[0] = (unsigned char)((myword & 0x000000ff) >> 0);
334  buffer[1] = (unsigned char)((myword & 0x0000ff00) >> 8);
335  buffer[2] = (unsigned char)((myword & 0x00ff0000) >> 16);
336  buffer[3] = (unsigned char)((myword & 0xff000000) >> 24);
337 }
338 
339 //is this like htons ?
340 static void fromShort(unsigned short myword, char *buffer)
341 {
342  buffer[0] = (myword & 0x00ff) >> 0;
343  buffer[1] = (myword & 0xff00) >> 8;
344 }
345 
346 
347 //#include "Vfw.h" //.avi headers
348 void saveSnapshotBMP(char *pathname, char *buffer,int bytesPerPixel,int width, int height)
349 {
350  //tested for bytesPerPixel == 3 and incoming alignment 1 only
351  //(outgoing/written is byte-aligned 4)
352  int rowlength, extra, alignedwidth, i;
353 
354  FWBITMAPINFOHEADER bi;
355  FWORD bfType;
356  FWBITMAPFILEHEADER bmph;
357  char filler[3] = {'\0','\0','\0'};
358  FILE *fout;
359 
360  //fname = "freewrl_snapshot.bmp";
361  //if(p->snapsnapB) fname = p->snapsnapB;
362  fout = fopen(pathname,"w+b");
363 
364  if(bytesPerPixel == 3) bi.biCompression = FBI_RGB;
365  bi.biHeight = height;
366  bi.biWidth = width;
367  bi.biPlanes = 1;
368  bi.biBitCount = 8 * bytesPerPixel;
369  bi.biXPelsPerMeter = 0;
370  bi.biYPelsPerMeter = 0;
371  //bi.biSizeImage = bytesPerPixel*bi.biHeight*bi.biWidth;
372  // The width must be DWORD (4byte) aligned unless the bitmap is RLE
373  // compressed.
374  rowlength = width*bytesPerPixel;
375  extra = 4 - (rowlength % 4);
376  if(extra == 4) extra = 0;
377  alignedwidth = rowlength + extra;
378  //bi.biSizeImage = ((bi.biWidth * 8*bytesPerPixel +31) & ~31) /8
379  // * bi.biHeight;
380  bi.biSizeImage = alignedwidth * height;
381  bi.biSize = sizeof(bi);
382  bi.biClrUsed = 0;
383  bi.biClrImportant = 0;
384  //printf("width=%d height=%d rowlengthmod4= %d extra=%d\n",width,height,rowlength%4,extra);
385  if(0){
386  //problem 1 - 64bit compiler may pad struct to 8 bytes
387  //problem 2 - we may be writing on a big-endian machine, .bmp numbers should be little endian
388  //memcpy(&bmph.bfType,"BM",2);
389  memcpy(&bfType,"BM",2);
390  bmph.bfReserved1 = 0;
391  bmph.bfReserved2 = 0;
392  bmph.bfOffBits = sizeof(bfType) + sizeof(FWBITMAPFILEHEADER) + sizeof(FWBITMAPINFOHEADER);
393  bmph.bfSize = sizeof(bfType) + sizeof(FWBITMAPFILEHEADER) + sizeof(FWBITMAPINFOHEADER) + bi.biSizeImage;
394  fwrite(&bfType,sizeof(bfType),1,fout);
395  fwrite(&bmph,sizeof(FWBITMAPFILEHEADER),1,fout);
396  fwrite(&bi,sizeof(FWBITMAPINFO),1,fout); //this is wrong. I'm writing 4 bytes for a color map I don't need to
397  if(true) //reverse colors
398  {
399  //swap GRB TO RGB //this is wrong because I wrote out 4 extra bytes above
400  int i;
401  char c;
402  for(i=0;i<rowlength*height;i+=3)
403  {
404  c = buffer[i];
405  buffer[i] = buffer[i+1];
406  buffer[i+1] = c;
407  }
408  }
409  }
410  if(1){
411  //solution 1: write each variable separately to buffer to elliminate struct padding
412  //solution 2: convert any-endian to little-endian with byte-reordering functions
413  char buf[128];
414  fwrite("BM",2,1,fout);
415  bi.biSize = 40; //9 longs x 4byte + 2 shorts x 2byte = 36 + 4 = 40
416  bmph.bfOffBits = 2 + 12 + bi.biSize; //2 + 12 + 40 = 54
417  bmph.bfSize = bmph.bfOffBits + bi.biSizeImage;
418  bmph.bfReserved1 = 0;
419  bmph.bfReserved2 = 0;
420 
421  fromLong(bmph.bfSize, &buf[0]); //4
422  fromShort(bmph.bfReserved1, &buf[4]); //2
423  fromShort(bmph.bfReserved2, &buf[6]); //2
424  fromLong(bmph.bfOffBits, &buf[8]); //4
425  fromLong(bi.biSize, &buf[12]); //4
426 
427  fromLong(bi.biWidth, &buf[16]);//4
428  fromLong(bi.biHeight, &buf[20]);//4
429  fromShort(bi.biPlanes, &buf[24]);//2
430  fromShort(bi.biBitCount, &buf[26]);//2
431  fromLong(bi.biCompression, &buf[28]);//4
432  fromLong(bi.biSizeImage, &buf[32]);//4
433  fromLong(bi.biXPelsPerMeter, &buf[36]);//4
434  fromLong(bi.biYPelsPerMeter, &buf[40]);//4
435  fromLong(bi.biClrUsed, &buf[44]);//4
436  fromLong(bi.biClrImportant, &buf[48]);//4
437  fwrite(buf,52,1,fout);
438  if(true) //reverse order
439  {
440  //swap BGR TO RGB
441  int i;
442  char c;
443  for(i=0;i<rowlength*height;i+=3)
444  {
445  c = buffer[i];
446  buffer[i] = buffer[i+2];
447  buffer[i+2] = c;
448  }
449  }
450  }
451  //write by row - and do byte alignment 4 (assume incoming is byte aligned 1)
452  for(i=0;i<height;i++)
453  {
454  int j=i*rowlength;
455  fwrite(&buffer[j],rowlength,1,fout);
456  if(extra)
457  fwrite(filler,extra,1,fout);
458  }
459  fclose(fout);
460 }
461 #endif
462 
463 #ifdef _MSC_VER
464 int fw_mkdir(const char* path);
465 void Snapshot ()
466 {
467 /* going to try just the single snapshot for windows, to .bmp format
468  (and future: remember .avi holds a sequence of DIBs. A .bmp holds 1 DIB.
469  There is something in the 2003 platform SDK and online for AVI & RIFF/DIB/BMP
470  http://msdn.microsoft.com/en-us/library/dd145119(v=VS.85).aspx storing a bitmap
471  http://msdn.microsoft.com/en-us/library/dd183391(VS.85).aspx .bmp
472  http://msdn.microsoft.com/en-us/library/aa446563.aspx sample program
473  http://msdn.microsoft.com/en-us/library/ms706540(v=VS.85).aspx
474  http://msdn.microsoft.com/en-us/library/ms706415(v=VS.85).aspx Vfw.h, Vfw32.lib
475 */
476  char thisRawFile[2000];
477  char *mysnapb, *mytmp;
478  char *imgbuf;
479  ppSnapshot p = (ppSnapshot)gglobal()->Snapshot.prv;
480 
481  imgbuf = grabScreen(3,0,0,gglobal()->display.screenWidth,gglobal()->display.screenHeight);
482  if (p->snapsnapB == NULL)
483  mysnapb = "freewrl.snap";
484  else
485  mysnapb = p->snapsnapB;
486 
487  if (p->seqtmp == NULL) mytmp = "freewrl_tmp";
488  else mytmp = p->seqtmp;
489 
490  fw_mkdir(mytmp);
491  p->snapRawCount ++;
492  snprintf(thisRawFile, sizeof(thisRawFile), "%s/%s.%04d.bmp", mytmp, mysnapb, p->snapRawCount);
493  saveSnapshotBMP(thisRawFile, imgbuf, 3, gglobal()->display.screenWidth, gglobal()->display.screenHeight);
494  FREE(imgbuf);
495 }
496 void Snapshot1(char *fname){
497  char *imgbuf;
498  imgbuf = grabScreen(3,0,0,gglobal()->display.screenWidth,gglobal()->display.screenHeight);
499  saveSnapshotBMP(fname, imgbuf, 3, gglobal()->display.screenWidth, gglobal()->display.screenHeight);
500  FREE(imgbuf);
501 }
502 #endif /*ifdef win32*/
503 #if !(defined(_MSC_VER) || defined(IPHONE))
504 
505 void fwl_init_SnapGif()
506 {
507  //struct pSnapshot* p = (struct pSnapshot*)gglobal()->Snapshot.prv;
508  ppSnapshot p = (ppSnapshot)gglobal()->Snapshot.prv;
509  p->snapGif = TRUE;
510 }
511 
512 void fwl_init_PrintShot() {
513  //struct pSnapshot* p = (struct pSnapshot*)gglobal()->Snapshot.prv;
514  ppSnapshot p = (ppSnapshot)gglobal()->Snapshot.prv;
515  p->doPrintshot = TRUE;
516  p->savedSnapshot = p->doSnapshot;
517  p->doSnapshot = TRUE;
518  printf("setting printshot/ snapshot\n");
519 }
520 
521 /* turn snapshotting on; if sequenced; possibly turn off an convert sequence */
522 void fwl_toggleSnapshot() {
523  struct tSnapshot* t = &gglobal()->Snapshot;
524 
525 #ifdef DOSNAPSEQUENCE
526  struct pSnapshot* p = (struct pSnapshot*)t->prv;
527 
528 /* need to re-implement this for OSX generating QTVR */
529  if (!t->doSnapshot) {
530  t->doSnapshot = TRUE;
531  } else {
532  if (p->snapsequence) {
533  t->doSnapshot = FALSE;
534  saveSnapSequence();
535  }
536  }
537 #else
538  t->doSnapshot = ! t->doSnapshot;
539 #endif
540 }
541 
542 #ifdef DOSNAPSEQUENCE
543 /* need to re-implement this for OSX generating QTVR */
544 
545 /* convert a sequence of snaps into a movie */
546 void saveSnapSequence() {
547  char *mytmp, *myseqb;
548  char sysline[2000];
549  char thisRawFile[2000];
550  char thisGoodFile[2000];
551  int xx;
552  struct tSnapshot* t = (struct tSnapshot*)gglobal()->Snapshot;
553 
554  /* make up base names - these may be command line parameters */
555  if (p->snapseqB == NULL) myseqb = "freewrl.seq";
556  else myseqb = p->snapseqB;
557  if (p->seqtmp == NULL) mytmp = "freewrl_tmp";
558  else mytmp = p->seqtmp;
559 
560  t->snapGoodCount++;
561 
562  if (t->snapGif) {
563  snprintf (thisGoodFile, sizeof(thisGoodFile),"%s/%s.%04d.gif",mytmp,myseqb,t->snapGoodCount);
564  } else {
565  snprintf (thisGoodFile, sizeof(thisGoodFile),"%s/%s.%04d.mpg",mytmp,myseqb,t->snapGoodCount);
566  }
567  /* snprintf(sysline,sizeof(sysline),"%s -size %dx%d -depth 8 -flip %s/%s*rgb %s", */
568 
569  /* Dani Rozenbaum - In order to generate
570  movies (e.g. with mencoder) images have to be three-band RGB (in other
571  words 24-bits) */
572  snprintf(sysline,sizeof(sysline), "%s -size %dx%d -depth 24 -colorspace RGB +matte -flip %s/%s*rgb %s",
573  CONVERT, gglobal()->display.screenWidth, gglobal()->display.screenHeight,mytmp,myseqb,thisGoodFile);
574 
575  /* printf ("convert line %s\n",sysline); */
576 
577  if (system (sysline) != 0) {
578  printf ("Freewrl: error running convert line %s\n",sysline);
579  }
580  printf ("[1] snapshot is: %s\n",thisGoodFile);
581  /* remove temporary files */
582  for (xx=1; xx <= p->snapRawCount; xx++) {
583  snprintf (thisRawFile, sizeof(thisRawFile), "%s/%s.%04d.rgb",mytmp,myseqb,xx);
584  UNLINK (thisRawFile);
585  }
586  t->snapRawCount=0;
587 }
588 #endif
589 
590 
591 // OLD_IPHONE_AQUA #ifdef AQUA
592 // OLD_IPHONE_AQUA
593 // OLD_IPHONE_AQUA CGContextRef MyCreateBitmapContext(int pixelsWide, int pixelsHigh, unsigned char *buffer) {
594 // OLD_IPHONE_AQUA CGContextRef context=NULL;
595 // OLD_IPHONE_AQUA CGColorSpaceRef colorSpace;
596 // OLD_IPHONE_AQUA unsigned char* bitmapData;
597 // OLD_IPHONE_AQUA int bitmapByteCount;
598 // OLD_IPHONE_AQUA int bitmapBytesPerRow;
599 // OLD_IPHONE_AQUA int i;
600 // OLD_IPHONE_AQUA
601 // OLD_IPHONE_AQUA bitmapBytesPerRow =(pixelsWide*4);
602 // OLD_IPHONE_AQUA bitmapByteCount =(bitmapBytesPerRow*pixelsHigh);
603 // OLD_IPHONE_AQUA colorSpace=CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
604 // OLD_IPHONE_AQUA bitmapData=(unsigned char*) MALLOC(void *, bitmapByteCount);
605 // OLD_IPHONE_AQUA
606 // OLD_IPHONE_AQUA if(bitmapData==NULL)
607 // OLD_IPHONE_AQUA {
608 // OLD_IPHONE_AQUA fprintf(stderr,"Memorynotallocated!");
609 // OLD_IPHONE_AQUA return NULL;
610 // OLD_IPHONE_AQUA }
611 // OLD_IPHONE_AQUA
612 // OLD_IPHONE_AQUA /* copy the saved OpenGL data, but, invert it */
613 // OLD_IPHONE_AQUA for (i=0; i<pixelsHigh; i++) {
614 // OLD_IPHONE_AQUA memcpy (&bitmapData[i*bitmapBytesPerRow],
615 // OLD_IPHONE_AQUA &buffer[(pixelsHigh-i-1)*bitmapBytesPerRow],
616 // OLD_IPHONE_AQUA bitmapBytesPerRow);
617 // OLD_IPHONE_AQUA }
618 // OLD_IPHONE_AQUA
619 // OLD_IPHONE_AQUA context=CGBitmapContextCreate(bitmapData,
620 // OLD_IPHONE_AQUA pixelsWide,
621 // OLD_IPHONE_AQUA pixelsHigh,
622 // OLD_IPHONE_AQUA 8, // bits per component
623 // OLD_IPHONE_AQUA bitmapBytesPerRow,
624 // OLD_IPHONE_AQUA colorSpace,
625 // OLD_IPHONE_AQUA kCGImageAlphaPremultipliedLast);
626 // OLD_IPHONE_AQUA if (context== NULL)
627 // OLD_IPHONE_AQUA {
628 // OLD_IPHONE_AQUA FREE(bitmapData);
629 // OLD_IPHONE_AQUA fprintf (stderr, "Context not created!");
630 // OLD_IPHONE_AQUA return NULL;
631 // OLD_IPHONE_AQUA }
632 // OLD_IPHONE_AQUA CGColorSpaceRelease( colorSpace );
633 // OLD_IPHONE_AQUA return context;
634 // OLD_IPHONE_AQUA }
635 // OLD_IPHONE_AQUA #endif
636 
637 /* get 1 frame; convert if we are doing 1 image at a time */
638 void Snapshot () {
639  GLvoid *buffer;
640  DIR *mydir;
641 
642 // OLD_IPHONE_AQUA #ifndef AQUA
643  char sysline[2000];
644  FILE * tmpfile;
645  char thisRawFile[2000];
646 
647 // OLD_IPHONE_AQUA #endif
648 
649  char thisGoodFile[2000];
650  char *mytmp, *mysnapb;
651 
652 // OLD_IPHONE_AQUA #ifdef AQUA
653 // OLD_IPHONE_AQUA CFStringRef path;
654 // OLD_IPHONE_AQUA CFURLRef url;
655 // OLD_IPHONE_AQUA CGImageRef image;
656 // OLD_IPHONE_AQUA CGImageDestinationRef imageDest;
657 // OLD_IPHONE_AQUA CGRect myBoundingBox;
658 // OLD_IPHONE_AQUA CGContextRef myBitmapContext;
659 // OLD_IPHONE_AQUA #endif
660 
661  struct tSnapshot* t = &gglobal()->Snapshot;
662  struct pSnapshot* p = (struct pSnapshot*)t->prv;
663 
664 
665  printf("do Snapshot ... \n");
666  /* make up base names - these may be command line parameters */
667 
668 #ifdef DOSNAPSEQUENCE
669 /* need to re-implement this for OSX generating QTVR */
670 
671  if (p->snapsequence) {
672  if (p->snapseqB == NULL)
673  mysnapb = "freewrl.seq";
674  else
675  mysnapb = p->snapseqB;
676  } else {
677 #endif
678  if (p->snapsnapB == NULL)
679  mysnapb = "freewrl.snap";
680  else
681  mysnapb = p->snapsnapB;
682 #ifdef DOSNAPSEQUENCE
683 /* need to re-implement this for OSX generating QTVR */
684 
685  }
686 #endif
687 
688 
689  if (p->seqtmp == NULL) mytmp = "freewrl_tmp";
690  else mytmp = p->seqtmp;
691 
692  /*does the directory exist? */
693  if ((mydir = opendir(mytmp)) == NULL) {
694  mkdir (mytmp,0755);
695  if ((mydir = opendir(mytmp)) == NULL) {
696  ConsoleMessage ("error opening Snapshot directory %s\n",mytmp);
697  return;
698  }
699  }
700 
701 #ifdef DOSNAPSEQUENCE
702 /* need to re-implement this for OSX generating QTVR */
703 
704  /* are we sequencing, or just single snapping? */
705  if (!p->snapsequence) p->doSnapshot=FALSE; /* reset snapshot key */
706 #endif
707 
708 
709 // OLD_IPHONE_AQUA #ifdef AQUA
710 // OLD_IPHONE_AQUA /* OSX needs 32 bits per byte. */
711 // OLD_IPHONE_AQUA /* MALLOC 4 bytes per pixel */
712 // OLD_IPHONE_AQUA buffer = MALLOC (GLvoid *, 4*gglobal()->display.screenWidth*gglobal()->display.screenHeight*sizeof(char));
713 // OLD_IPHONE_AQUA
714 // OLD_IPHONE_AQUA /* grab the data */
715 // OLD_IPHONE_AQUA FW_GL_PIXELSTOREI (GL_UNPACK_ALIGNMENT, 1);
716 // OLD_IPHONE_AQUA FW_GL_PIXELSTOREI (GL_PACK_ALIGNMENT, 1);
717 // OLD_IPHONE_AQUA FW_GL_READPIXELS (0,0,gglobal()->display.screenWidth,gglobal()->display.screenHeight,GL_RGBA,GL_UNSIGNED_BYTE, buffer);
718 // OLD_IPHONE_AQUA #else
719 
720  /* Linux, etc, can get by with 3 bytes per pixel */
721  /* MALLOC 3 bytes per pixel */
722  buffer = MALLOC (GLvoid *, 3*gglobal()->display.screenWidth*gglobal()->display.screenHeight*sizeof(char));
723 
724  /* grab the data */
725  FW_GL_PIXELSTOREI (GL_UNPACK_ALIGNMENT, 1);
726  FW_GL_PIXELSTOREI (GL_PACK_ALIGNMENT, 1);
727  FW_GL_READPIXELS (0,0,gglobal()->display.screenWidth,gglobal()->display.screenHeight,GL_RGB,GL_UNSIGNED_BYTE, buffer);
728 // OLD_IPHONE_AQUA #endif
729 
730  /* save this snapshot */
731  p->snapRawCount ++;
732 #ifdef DOSNAPSEQUENCE
733 /* need to re-implement this for OSX generating QTVR */
734 
735  if (p->snapRawCount > maxSnapImages) {
736  FREE_IF_NZ (buffer);
737  return;
738  }
739 #endif
740 
741 // OLD_IPHONE_AQUA #ifdef AQUA
742 // OLD_IPHONE_AQUA
743 // OLD_IPHONE_AQUA myBoundingBox = CGRectMake (0, 0, gglobal()->display.screenWidth, gglobal()->display.screenHeight);
744 // OLD_IPHONE_AQUA myBitmapContext = MyCreateBitmapContext (gglobal()->display.screenWidth, gglobal()->display.screenHeight,buffer);
745 // OLD_IPHONE_AQUA
746 // OLD_IPHONE_AQUA image = CGBitmapContextCreateImage (myBitmapContext);
747 // OLD_IPHONE_AQUA CGContextDrawImage(myBitmapContext, myBoundingBox, image);
748 // OLD_IPHONE_AQUA char *bitmapData = CGBitmapContextGetData(myBitmapContext);
749 // OLD_IPHONE_AQUA
750 // OLD_IPHONE_AQUA CGContextRelease (myBitmapContext);
751 // OLD_IPHONE_AQUA if (bitmapData) FREE(bitmapData);
752 // OLD_IPHONE_AQUA
753 // OLD_IPHONE_AQUA
754 // OLD_IPHONE_AQUA p->snapGoodCount++;
755 // OLD_IPHONE_AQUA if (t->doPrintshot) {
756 // OLD_IPHONE_AQUA snprintf (thisGoodFile, sizeof(thisGoodFile), "/tmp/FW_print_snap_tmp.png");
757 // OLD_IPHONE_AQUA p->doPrintshot = FALSE;
758 // OLD_IPHONE_AQUA t->doSnapshot = p->savedSnapshot;
759 // OLD_IPHONE_AQUA path = CFStringCreateWithCString(NULL, thisGoodFile, kCFStringEncodingUTF8);
760 // OLD_IPHONE_AQUA printf("thisGoodFile is %s\n", thisGoodFile);
761 // OLD_IPHONE_AQUA url = CFURLCreateWithFileSystemPath (NULL, path, kCFURLPOSIXPathStyle, FALSE);
762 // OLD_IPHONE_AQUA } else {
763 // OLD_IPHONE_AQUA snprintf (thisGoodFile, sizeof(thisGoodFile),"%s/%s.%04d.png",mytmp,mysnapb,p->snapGoodCount);
764 // OLD_IPHONE_AQUA
765 // OLD_IPHONE_AQUA path = CFStringCreateWithCString(NULL, thisGoodFile, kCFStringEncodingUTF8);
766 // OLD_IPHONE_AQUA url = CFURLCreateWithFileSystemPath (NULL, path, kCFURLPOSIXPathStyle, FALSE);
767 // OLD_IPHONE_AQUA }
768 // OLD_IPHONE_AQUA
769 // OLD_IPHONE_AQUA imageDest = CGImageDestinationCreateWithURL(url, CFSTR("public.png"), 1, NULL);
770 // OLD_IPHONE_AQUA CFRelease(url);
771 // OLD_IPHONE_AQUA CFRelease(path);
772 // OLD_IPHONE_AQUA
773 // OLD_IPHONE_AQUA if (!imageDest) {
774 // OLD_IPHONE_AQUA ConsoleMessage("[1] Snapshot cannot be written");
775 // OLD_IPHONE_AQUA return;
776 // OLD_IPHONE_AQUA }
777 // OLD_IPHONE_AQUA
778 // OLD_IPHONE_AQUA CGImageDestinationAddImage(imageDest, image, NULL);
779 // OLD_IPHONE_AQUA if (!CGImageDestinationFinalize(imageDest)) {
780 // OLD_IPHONE_AQUA ConsoleMessage ("[2] Snapshot cannot be written");
781 // OLD_IPHONE_AQUA }
782 // OLD_IPHONE_AQUA CFRelease(imageDest);
783 // OLD_IPHONE_AQUA CGImageRelease(image);
784 // OLD_IPHONE_AQUA #else
785 
786  /* save the file */
787  if(p->modeTesting){
788  snprintf (thisRawFile, sizeof(thisRawFile),"%s/%s.%04d.bmp",mytmp,mysnapb,p->snapRawCount);
789  saveSnapshotBMP(thisRawFile,buffer,3,gglobal()->display.screenWidth, gglobal()->display.screenHeight);
790  FREE_IF_NZ (buffer);
791  }else{
792  snprintf (thisRawFile, sizeof(thisRawFile),"%s/%s.%04d.rgb",mytmp,mysnapb,p->snapRawCount);
793  tmpfile = fopen(thisRawFile,"w");
794  if (tmpfile == NULL) {
795  printf ("cannot open temp file (%s) for writing\n",thisRawFile);
796  FREE_IF_NZ (buffer);
797  return;
798  }
799 
800  if (fwrite(buffer, 1, gglobal()->display.screenHeight*gglobal()->display.screenWidth*3, tmpfile) <= 0) {
801  printf ("error writing snapshot to %s, aborting snapshot\n",thisRawFile);
802  FREE_IF_NZ (buffer);
803  return;
804  }
805  fclose (tmpfile);
806 
807  /* convert -size 450x300 -depth 8 -flip /tmp/snappedfile.rgb out.png works. */
808 
809  FREE_IF_NZ (buffer);
810 
811 #ifdef DOSNAPSEQUENCE
812 /* need to re-implement this for OSX generating QTVR */
813 
814  /* now, if we are doing only 1, convert the raw into the good.... */
815  if (!p->snapsequence) {
816 #endif
817  //if(!p->modeTesting){
818  t->snapGoodCount++;
819  snprintf (thisGoodFile, sizeof(thisGoodFile),"%s/%s.%04d.png",mytmp,mysnapb,t->snapGoodCount);
820  snprintf(sysline,sizeof(sysline),"%s -size %dx%d -depth 8 -flip %s %s",
821  IMAGECONVERT,gglobal()->display.screenWidth, gglobal()->display.screenHeight,thisRawFile,thisGoodFile);
822 
823  if (system (sysline) != 0) {
824  printf ("Freewrl: error running convert line %s\n",sysline);
825  }
826  printf ("[2] snapshot is: %s\n",thisGoodFile);
827  UNLINK (thisRawFile);
828  //}
829 #ifdef DOSNAPSEQUENCE
830 /* need to re-implement this for OSX generating QTVR */
831 
832  }
833 #endif
834 
835 // OLD_IPHONE_AQUA #endif
836  }
837 }
838 #endif /*ifdef win32*/
839 
840 #endif