FreeWRL / FreeX3D 4.3.0
SnapshotTesting.c
1/****************************************************************************
2 This file is part of the FreeWRL/FreeX3D Distribution.
3
4 Copyright 2009 CRC Canada. (http://www.crc.gc.ca)
5
6 FreeWRL/FreeX3D is free software: you can redistribute it and/or modify
7 it under the terms of the GNU Lesser Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 FreeWRL/FreeX3D is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with FreeWRL/FreeX3D. If not, see <http://www.gnu.org/licenses/>.
18****************************************************************************/
19
20#include <internal.h>
21#include "MainLoop.h"
22#include "../main.h"
23#include "../scenegraph/Viewer.h"
24
25//#define USE_SNAPSHOT_TESTING 1
26#ifndef USE_SNAPSHOT_TESTING
27//stubs for options
28//void fwl_set_modeRecord()
29//{
30//}
31void fwl_set_modeFixture()
32{
33}
34//void fwl_set_modePlayback()
35//{
36//}
37void fwl_set_nameTest(char *nameTest)
38{
39}
40void fwl_set_testPath(char *testPath)
41{
42}
43#endif //ifndef USE_SNAPSHOT_TESTING
44
45
46#ifdef USE_SNAPSHOT_TESTING
47
48/* SnapshotTesting
49- a process to do regression testing
50- implemented as an insertible 'layer' in freewrl
51
52http://freewrl.sourceforge.net/use.html
53Commmand Line Options - Testing
54
55Developers working on desktop configurations of freewrl can automate testing by comparing
56before- and after- snapshot images and log files.
57
58There are 3 steps to the testing process:
59A) generate test playback files:
60 freewrl 1.wrl -R -N t1
61 generates /recording/t1.fwplay
62 In order to generate test fixtures, you need to take a snapshot of the graphics window
63 using the 'x' key, and/or for non-visual tests, log something to the log file by toggling
64 logging on with the "`" key, doing some functions that write to the console such as "/" command,
65 toggle logging off with "`", and press 'q' to exit gracefully.
66 (some temporary files will appear in /freewrl_tmp but are not needed).
67 During this sesssion the frame rate is slowed -to minimize the size of the .fwplay file
68 and speed up test playback- and your mouse and keyboard actions are recorded on each frame,
69 to the .fwplay file.
70B) before making a change to the code, run the playback files to generate test fixtures:
71 freewrl -F -N t1
72 generates /fixture/t1.0001.bmp test fixture, assuming you hit the 'x' snapshot during the recording step,
73 and /fixture/t1.log if you toggled logging on during recording
74C) after making each small code change:
75 i) re-run the playback files
76 freewrl -P -N t1
77 generates /playback/t1.0001.bmp and/or /playback/t1.log
78 ii) compare /playback/testname.* to the /fixture/testname.* files
79 For this you'll need a perl script doing a file compare between the /fixture and /playback versions.
80 If any tests break by not comparing identically playback to fixture,
81 that means you changed the functionality of the code.
82 Sometimes that's what you want. In that case check which tests failed to see if
83 there are unintended side-effects. If all OK, then generate new fixtures.
84 Sometimes you want to refactor code: change its structure without changing its functionality.
85 In this case if you break any test, roll back your last code change.
86
87Summary of testing command line options:
88
89-N or --nametest testname
90 Sets the .fwplay, snapshot image and logfile prefix to testname.
91 During recording /recording/testname.fwplay test playback file is generated,
92 and during fixture it's read, and /fixture/testname.0001.bmp (or .png) and/or /fixture/testname.log
93 is generated, depending on what actions you took during recording.
94 If you don't set this option, testname defaults to your scene basename,
95 except with the .suffix changed to _suffix. Example 1.wrl defaults to 1_wrl.fwplay.
96-R or --record
97 Generates /recording/testname.fwplay test playback file.
98-F or --fixture
99 Generates /fixture/testname.0001.bmp or .png, and/or /fixture/testname.log depending
100 on whether you did a snapshot and/or log command during recording.
101-P or --playback
102 Identical to option -F or --fixture except puts test fixtures into /playback folder.
103-Y or --testpath <path to top test folder>
104
105*/
106
107
108
109
110#include <stdio.h>
111#include <iglobal.h>
112#include <internal.h>
113void set_snapshotModeTesting(int value); //snapshot.c
114int isSnapshotModeTesting(); //snapshot.c
115
116
117#define FALSE 0
118#define TRUE 1
119
120struct keypressTuple{
121 int key;
122 int type;
123};
124struct mouseTuple{
125 int mev;
126 unsigned int button;
127 float x;
128 float y;
129 int ix;
130 int iy;
131 int ID;
132};
133struct playbackRecord {
134 int frame;
135 double dtime;
136 //should we use more general Touch instead of mouse-specific?
137 int *mousetuples; //x,y,button chord
138 int mouseCount; //# mouse tuples
139 char *keystrokes;
140 int keyCount;
141};
142
143typedef struct tSnapshotTesting{
144 void *prv;
145 } tSnapshotTesting;
146static tSnapshotTesting SnapshotTesting;
147
148
149typedef struct pSnapshotTesting{
150 FILE* recordingFile;
151 char* recordingFName;
152 int modeRecord;
153 int modeFixture;
154 int modePlayback;
155 int fwplayOpened;
156 char *nameTest;
157 char *testPath;
158 int frameNum; //for Record, Playback - frame# =0 after scene loaded
159 struct playbackRecord* playback;
160 int playbackCount;
161
162 struct keypressTuple keypressQueue[50]; //for Record,Playback where keypresses are applied just once per frame for consistency
163 int keypressQueueCount;
164 struct mouseTuple mouseQueue[50];
165 int mouseQueueCount;
166
167}* ppSnapshotTesting;
168void *SnapshotTesting_constructor(){
169 void *v = MALLOCV(sizeof(struct pSnapshotTesting));
170 memset(v,0,sizeof(struct pSnapshotTesting));
171 return v;
172}
173void SnapshotTesting_init(struct tSnapshotTesting *t){
174 //public
175 //private
176 t->prv = SnapshotTesting_constructor();
177 {
178 ppSnapshotTesting p = (ppSnapshotTesting)t->prv;
179 p->recordingFile = NULL;
180 p->recordingFName = NULL;
181 p->modeRecord = FALSE;
182 p->modeFixture = FALSE;
183 p->modePlayback = FALSE;
184 p->nameTest = NULL;
185 p->testPath = NULL;
186 p->frameNum = 0;
187 p->playbackCount = 0;
188 p->playback = NULL;
189 p->fwplayOpened = 0;
190
191 p->keypressQueueCount=0;
192 p->mouseQueueCount=0;
193 }
194}
195void SnapshotTesting_setHandlers();
196
197static int rtestinit = 0;
198static ppSnapshotTesting get_ppSnapshotTesting(){
199 if(!rtestinit){
200 SnapshotTesting_init(&SnapshotTesting);
201 rtestinit = 1;
202 ppSnapshotTesting p = (ppSnapshotTesting)SnapshotTesting.prv;
203 SnapshotTesting_setHandlers();
204 }
205 return (ppSnapshotTesting)SnapshotTesting.prv;
206}
207
208/*
209When playing back, you don't have key and mouse events to trigger dequeueing
210- so during record, you enqueue mouse and key from their message threads
211- and dequeue to use them in the scene, during rendersceneupdatescene, giving the frame's timestamp to all mouse and key dequeued
212- then during Fixture and Playback, we dequeue again in the rendersceneupdatescene on the timestamped frame
213- and forward them to the key and mouse message queuus
214*/
215
216
217int dequeueKeyPress(ppSnapshotTesting p,int *key, int *type){
218 if(p->keypressQueueCount > 0){
219 int i;
220 p->keypressQueueCount--;
221 *key = p->keypressQueue[0].key;
222 *type = p->keypressQueue[0].type;
223 for(i=0;i<p->keypressQueueCount;i++){
224 p->keypressQueue[i].key = p->keypressQueue[i+1].key;
225 p->keypressQueue[i].type = p->keypressQueue[i+1].type;
226 }
227 return 1;
228 }
229 return 0;
230}
231
232void queueKeyPress(ppSnapshotTesting p, int key, int type){
233 if(p->keypressQueueCount < 50){
234 p->keypressQueue[p->keypressQueueCount].key = key;
235 p->keypressQueue[p->keypressQueueCount].type = type;
236 p->keypressQueueCount++;
237 }
238}
239
240int dequeueMouse(ppSnapshotTesting p, int *mev, unsigned int *button, float *x, float *y){
241 if(p->mouseQueueCount > 0){
242 int i;
243 p->mouseQueueCount--;
244 *mev = p->mouseQueue[0].mev;
245 *button = p->mouseQueue[0].button;
246 *x = p->mouseQueue[0].x;
247 *y = p->mouseQueue[0].y;
248 for(i=0;i<p->mouseQueueCount;i++){
249 p->mouseQueue[i].mev = p->mouseQueue[i+1].mev;
250 p->mouseQueue[i].button = p->mouseQueue[i+1].button;
251 p->mouseQueue[i].x = p->mouseQueue[i+1].x;
252 p->mouseQueue[i].y = p->mouseQueue[i+1].y;
253 }
254 return 1;
255 }
256 return 0;
257}
258int dequeueMouseMulti(ppSnapshotTesting p, int *mev, unsigned int *button, int *ix, int *iy, int *ID){
259 if(p->mouseQueueCount > 0){
260 int i;
261 p->mouseQueueCount--;
262 *mev = p->mouseQueue[0].mev;
263 *button = p->mouseQueue[0].button;
264 *ix = p->mouseQueue[0].ix;
265 *iy = p->mouseQueue[0].iy;
266 *ID = p->mouseQueue[0].ID;
267 for(i=0;i<p->mouseQueueCount;i++){
268 p->mouseQueue[i].mev = p->mouseQueue[i+1].mev;
269 p->mouseQueue[i].button = p->mouseQueue[i+1].button;
270 p->mouseQueue[i].ix = p->mouseQueue[i+1].ix;
271 p->mouseQueue[i].iy = p->mouseQueue[i+1].iy;
272 p->mouseQueue[i].ID = p->mouseQueue[i+1].ID;
273 }
274 return 1;
275 }
276 return 0;
277}
278
279void queueMouseMulti(ppSnapshotTesting p, const int mev, const unsigned int button, const int ix, const int iy, int ID){
280 if(p->mouseQueueCount < 50){
281 p->mouseQueue[p->mouseQueueCount].mev = mev;
282 p->mouseQueue[p->mouseQueueCount].button = button;
283 p->mouseQueue[p->mouseQueueCount].ix = ix;
284 p->mouseQueue[p->mouseQueueCount].iy = iy;
285 p->mouseQueue[p->mouseQueueCount].ID = ID;
286 p->mouseQueueCount++;
287 }
288}
289void queueMouse(ppSnapshotTesting p, const int mev, const unsigned int button, const float x, const float y){
290 if(p->mouseQueueCount < 50){
291 p->mouseQueue[p->mouseQueueCount].mev = mev;
292 p->mouseQueue[p->mouseQueueCount].button = button;
293 p->mouseQueue[p->mouseQueueCount].x = x;
294 p->mouseQueue[p->mouseQueueCount].y = y;
295 p->mouseQueueCount++;
296 }
297}
298
299
300void handleTESTING(const int mev, const unsigned int button, const float x, const float y)
301{
302 ppSnapshotTesting p;
303 //ttglobal tg = gglobal();
304 //p = (ppSnapshotTesting)tg->SnapshotTesting.prv;
305 p = get_ppSnapshotTesting();
306
307 //if(0)
308 if(p->modeRecord || p->modeFixture || p->modePlayback){
309 if(p->modeRecord){
310 queueMouse(p,mev,button,x,y);
311 }
312 //else ignor so test isn't ruined by random mouse movement during playback
313 return;
314 }
315 handle0(mev, button, x, y);
316}
317void fwl_do_keyPress0(int key, int type);
318void fwl_do_rawKeyPressTESTING(int key, int type) {
319 ppSnapshotTesting p;
320 //ttglobal tg = gglobal();
321 //p = (ppSnapshotTesting)tg->SnapshotTesting.prv;
322 p = get_ppSnapshotTesting();
323
324 if(p->modeRecord){
325 queueKeyPress(p,key,type);
326 }else{
327 fwl_do_keyPress0(key,type);
328 }
329}
330int fwl_handle_mouse0(const int mev, const unsigned int button, int x, int y, int windex);
331int fwl_handle_aqua_TESTING(const int mev, const unsigned int button, int x, int y, int windex)
332{
333 ppSnapshotTesting p;
334 //ttglobal tg = gglobal();
335 //p = (ppSnapshotTesting)tg->SnapshotTesting.prv;
336 p = get_ppSnapshotTesting();
337
338 if(p->modeRecord || p->modeFixture || p->modePlayback){
339 if(p->modeRecord){
340 queueMouseMulti(p,mev,button,x,y,windex);
341 }
342 //else ignor so test isn't ruined by random mouse movement during playback
343 return 0;
344 }
345 return fwl_handle_mouse0(mev, button, x, y, windex);
346}
347
348/*
349void fwl_set_modeRecord()
350{
351 ppSnapshotTesting p;
352 //ttglobal tg = gglobal();
353 //p = (ppSnapshotTesting)tg->SnapshotTesting.prv;
354 p = get_ppSnapshotTesting();
355 p->modeRecord = TRUE;
356}
357*/
358void fwl_set_modeFixture()
359{
360 ppSnapshotTesting p;
361 //ttglobal tg = gglobal();
362 //p = (ppSnapshotTesting)tg->SnapshotTesting.prv;
363 p = get_ppSnapshotTesting();
364 p->modeFixture = TRUE;
365}
366/*
367void fwl_set_modePlayback()
368{
369 ppSnapshotTesting p;
370 //ttglobal tg = gglobal();
371 //p = (ppSnapshotTesting)tg->SnapshotTesting.prv;
372 p = get_ppSnapshotTesting();
373 p->modePlayback = TRUE;
374}
375*/
376void fwl_set_nameTest(char *nameTest)
377{
378 ppSnapshotTesting p;
379 //ttglobal tg = gglobal();
380 //p = (ppSnapshotTesting)tg->SnapshotTesting.prv;
381 p = get_ppSnapshotTesting();
382 p->nameTest = STRDUP(nameTest);
383}
384void fwl_set_testPath(char *testPath)
385{
386 ppSnapshotTesting p;
387 int ierr;
388 //ttglobal tg = gglobal();
389 //p = (ppSnapshotTesting)tg->SnapshotTesting.prv;
390 p = get_ppSnapshotTesting();
391 p->testPath = STRDUP(testPath);
392 ierr = chdir(p->testPath);
393 if (ierr == -1) {
394 //folder may not exist yet. Try and create it.
395 mkdir(p->testPath, 0755);
396 ierr = chdir(p->testPath);
397 }
398 if (1) {
399 //where are we?
400 char cwd[1000];
401 getcwd(cwd, 999);
402 printf("current working directory= %s\n", cwd);
403 }
404 //printf("ierr = %d", ierr);
405}
406
407char *nameLogFileFolderTESTING(char *logfilename, int size){
408 ppSnapshotTesting p;
409 ttglobal tg = gglobal();
410 //p = (ppSnapshotTesting)tg->SnapshotTesting.prv;
411 p = get_ppSnapshotTesting();
412
413 if(p->modePlayback || p->modeFixture){
414 if(p->modePlayback)
415 strcat(logfilename,"playback");
416 else
417 strcat(logfilename,"fixture");
418 fw_mkdir(logfilename);
419 strcat(logfilename,"/");
420 if(p->nameTest){
421 // /fixture/test1.log
422 strcat(logfilename,p->nameTest);
423 }else if(tg->Mainloop.scene_name){
424 // /fixture/1_wrl.log
425 strcat(logfilename,tg->Mainloop.scene_name);
426 if(tg->Mainloop.scene_suff){
427 strcat(logfilename,"_");
428 strcat(logfilename,tg->Mainloop.scene_suff);
429 }
430 }
431 }else{
432 nameLogFileFolderNORMAL(logfilename,size);
433 }
434 return logfilename;
435}
436
437
438int fw_mkdir(const char* path);
439void fwl_RenderSceneUpdateScene0(double dtime);
440void fwl_RenderSceneUpdateSceneTARGETWINDOWS();
441void fwl_RenderSceneUpdateSceneTESTING() {
442 double dtime;
443 //ttglobal tg = gglobal();
444 //ppMainloop p = (ppMainloop)tg->Mainloop.prv;
445 ppSnapshotTesting p;
446 ttglobal tg = gglobal();
447 //p = (ppSnapshotTesting)tg->SnapshotTesting.prv;
448 p = get_ppSnapshotTesting();
449
450
451 dtime = Time1970sec();
452 if((p->modeRecord || p->modeFixture || p->modePlayback)) //commandline --record/-R and --playback/-P, for automated testing
453 {
454 //functional testing support options May 2013
455 //records frame#, dtime, keyboard, mouse to an ASCII .fwplay file for playback
456 //to record, run a scene file with -R or --record option
457 //copy the .fwplay between platforms
458 //before starting refactoring, run scenes with -F or --fixture option,
459 // and hit the 'x' key to save a snapshot one or more times per fixture run
460 //after each refactoring step, run scenes with -P or --playback option,
461 // and (with perl script) do a file compare(fixture_snapshot,playback_snapshot)
462 //
463 //on the command line use:
464 //-R to just record the .fwplay file
465 //-F to play recording and save as fixture
466 //-P to play recording and save as playback
467 //-R -F to record and save as fixture in one step
468 //command line long option equivalents: -R --record, -F --fixture, -P --playback
469 int key;
470 int type;
471 int mev,ix,iy,ID;
472 unsigned int button;
473 float x,y;
474 char buff[1000], keystrokes[200], mouseStr[1000];
475 int namingMethod;
476 char *folder;
477 char sceneName[1000];
478 //naming method for related files (and folders)
479 //0=default: recording.fwplay, fixture.bmp playback.bmp - will overwrite for each scene
480 //1=folders: 1_wrl/recording.fwplay, 1_wrl/fixture/17.bmp, 1_wrl/playback/17.bmp
481 //2=flattened: 1_wrl.fwplay, 1_wrl_fixture_17.bmp, 1_wrl_playback_17.bmp (17 is frame#)
482 //3=groupfolders: /tests, /recordings/*.fwplay, /fixtures/1_wrl_17.bmp /playbacks/1_wrl_17.bmp
483 //4=groupfolders: /tests, /recordings/*.fwplay, /fixtures/1_wrl_17.bmp /playbacks/1_wrl_17.bmp
484 // - 4 same as 3, except done to harmonize with linux/aqua naming approach:
485 // - fwl_set_SnapFile(path = {"fixture" | "playback" }); to set mytmp
486 // -
487 folder = NULL;
488 namingMethod = 4;
489 //if(p->frameNum == 1){
490 if(!p->fwplayOpened){
491 char recordingName[1000];
492 int j,k;
493 p->fwplayOpened = 1;
494 recordingName[0] = '\0';
495 sceneName[0] = '\0';
496 if(tg->Mainloop.scene_name){
497 strcat(sceneName,tg->Mainloop.scene_name);
498 if(tg->Mainloop.scene_suff){
499 strcat(sceneName,".");
500 strcat(sceneName,tg->Mainloop.scene_suff);
501 }
502 }
503 if(namingMethod==3 || namingMethod==4){
504 strcpy(recordingName,"recording");
505 fw_mkdir(recordingName);
506 strcat(recordingName,"/");
507 }
508 if(namingMethod>0){
509 if(p->nameTest){
510 strcat(recordingName,p->nameTest);
511 }else{
512 strcat(recordingName,tg->Mainloop.scene_name);
513 k = strlen(recordingName);
514 if(k){
515 //1.wrl -> 1_wrl
516 j = strlen(tg->Mainloop.scene_suff);
517 if(j){
518 strcat(recordingName,"_");
519 strcat(recordingName,tg->Mainloop.scene_suff);
520 }
521 }
522 }
523 }
524 if(namingMethod==1){
525 fw_mkdir(recordingName);
526 strcat(recordingName,"/recording"); //recording.fwplay a generic name, in case there's no scene name
527 }
528 if(namingMethod==0)
529 strcat(recordingName,"recording");
530 strcat(recordingName,".fwplay"); //1_wrl.fwplay
531 p->recordingFName = STRDUP(recordingName);
532
533 if(p->modeFixture || p->modePlayback){
534 if(!p->modeRecord){
535 p->recordingFile = fopen(p->recordingFName, "r");
536 if(p->recordingFile == NULL){
537 printf("ouch recording file %s not found\n", p->recordingFName);
538 fw_exit(1);
539 }
540 if( fgets(buff, 1000, p->recordingFile) != NULL){
541 char window_widthxheight[100], equals[50];
542 int width, height;
543 //window_wxh = 600,400
544 if( sscanf(buff,"%s %s %d, %d\n",window_widthxheight,equals, &width,&height) == 4) {
545 if(width != tg->display.screenWidth || height != tg->display.screenHeight){
546 //right now all we can do is passively complain
547 printf("Ouch - the test playback window size is different than recording:\n");
548 printf("recording %d x %d playback %d x %d\n",width,height,
549 tg->display.screenWidth,tg->display.screenHeight);
550 printf("hit Enter:");
551 getchar();
552 }
553 }
554 }
555 if( fgets(buff, 1000, p->recordingFile) != NULL){
556 char scenefile[100], equals[50];
557 //scenefile = 1.wrl
558 if( sscanf(buff,"%s %s %s \n",scenefile,equals, sceneName) == 3) {
559 if(!tg->Mainloop.scene_name){
560 char* suff = NULL;
561 char* local_name = NULL;
562 char* url = NULL;
563 if(strlen(sceneName)) url = STRDUP(sceneName);
564 if(url){
565 splitpath_local_suffix(url, &local_name, &suff);
566 gglobal()->Mainloop.url = url;
567 gglobal()->Mainloop.scene_name = local_name;
568 gglobal()->Mainloop.scene_suff = suff;
569 fwl_resource_push_single_request(url);
570 }
571 }
572 }
573 }
574 }
575 }
576 }
577 int doEvents = (!fwl_isinputThreadParsing()) && (!fwl_isTextureParsing()) && fwl_isInputThreadInitialized();
578 //printf("frame %d doevents=%d\n",p->frameNum,p->doEvents);
579 if(!doEvents)
580 return; //for Record and Playback, don't start doing things until scene and textures are loaded
581 if(p->modeRecord)
582 if(dtime - tg->Mainloop.TickTime < .5) return; //slow down frame rate to 2fps to reduce empty meaningless records
583 p->frameNum++; //for record, frame relative to when scene is loaded
584
585 if(p->modeRecord){
586 int i;
587 char temp[1000];
588 if(p->frameNum == 1){
589 if(0){
590 //where are we?
591 char cwd[1000];
592 getcwd(cwd, 999);
593 printf("current working directory= %s\n", cwd);
594 }
595 p->recordingFile = fopen(p->recordingFName, "w");
596 if(p->recordingFile == NULL){
597 printf("ouch recording file %s not found\n", p->recordingFName);
598 fw_exit(1);
599 }
600 //put in a header record, passively showing window widthxheight
601 fprintf(p->recordingFile,"window_wxh = %d, %d \n",tg->display.screenWidth,tg->display.screenHeight);
602 fprintf(p->recordingFile,"scenefile = %s \n",tg->Mainloop.url); //sceneName);
603 }
604 strcpy(keystrokes,"\"");
605 while(dequeueKeyPress(p,&key,&type)){
606 sprintf(temp,"%d,%d,",key,type);
607 strcat(keystrokes,temp);
608 }
609 strcat(keystrokes,"\"");
610 strcpy(mouseStr,"\"");
611 i = 0;
612 while(dequeueMouseMulti(p,&mev, &button, &ix, &iy, &ID)){
613 sprintf(temp,"%d,%d,%d,%d,%d;",mev,button,ix,iy,ID);
614 strcat(mouseStr,temp);
615 i++;
616 }
617 strcat(mouseStr,"\"");
618 fprintf(p->recordingFile,"%d %.6lf %s %s\n",p->frameNum,dtime,keystrokes,mouseStr);
619 //in case we are -R -F together,
620 //we need to round dtime for -F like it will be coming out of .fwplay for -P
621 sprintf(temp,"%.6lf",dtime);
622 sscanf(temp,"%lf",&dtime);
623 //folder = "fixture";
624 folder = NULL;
625 }
626 if(p->modeFixture || p->modePlayback){
627 if(!p->modeRecord){
628 // playback[i] = {iframe, dtime, keystrokes or NULL, mouse (xy,button sequence) or NULL, snapshot URL or NULL, scenegraph_dump URL or NULL, ?other?}
629 if( fgets( buff, 1000, p->recordingFile ) != NULL ) {
630 if(sscanf(buff,"%d %lf %s %s\n",&p->frameNum,&dtime,keystrokes,mouseStr) == 4){ //,snapshotURL,scenegraphURL) == 6){
631 if(0) printf("%d %lf %s %s\n",p->frameNum,dtime,keystrokes,mouseStr);
632 }
633 }
634 }
635 if(p->modeFixture) folder = "fixture";
636 if(p->modePlayback) folder = "playback";
637 }
638 //for all 3 - read the keyboard string and the mouse string
639 if(p->modeRecord || p->modeFixture || p->modePlayback){
640 if(strlen(keystrokes)>2){ // "x,1," == 6
641 char *next,*curr;
642 //count the number of ','
643 //for(i=0,n=0;i<strlen(keystrokes);i++) if(keystrokes[i] == ',') n++; //(strlen(keystrokes) -2)/4;
644 //n /= 2; //each keystroke has 2 commas: (char),(type),
645 curr = &keystrokes[1]; //skip leading "
646 while(curr && strlen(curr)>1){
647 //for(i=0;i<n;i++){
648 //ii = i*4 +1;
649 //sscanf(&keystrokes[ii],"%d,%d",&key,&type);
650 sscanf(curr,"%d",&key);
651 next = strchr(curr,',');
652 curr = &next[1];
653 sscanf(curr,"%d",&type);
654 next = strchr(curr,',');
655 curr = &next[1];
656 if(p->modeFixture || p->modePlayback){
657 //we will catch the snapshot keybaord command and prepare the
658 //snapshot filename and folder/directory for fixture and playback
659 if(key == 'x'){
660 //prepare snapshot folder(scene/ + fixture ||playback)
661 // and file name(frame#)
662 char snapfile[5];
663#ifdef _MSC_VER
664 char *suff = ".bmp";
665#else
666 char *suff = ".snap";
667#endif
668 sprintf(snapfile,"%d",p->frameNum);
669 if(namingMethod == 0){
670 //default: recording.bmp, playback.bmp
671 char snappath[100];
672 strcpy(snappath,folder);
673 strcat(snappath,suff);
674 fwl_set_SnapFile(snappath);
675 }
676 if(namingMethod==1){
677 //nested folder approach
678 //1=folders: 1_wrl/recording.fwplay, 1_wrl/fixture/17.bmp, 1_wrl/playback/17.bmp
679 int k,j;
680 char snappath[100];
681 strcpy(snappath,tg->Mainloop.scene_name);
682 k = strlen(snappath);
683 if(k){
684 //1.wrl -> 1_wrl
685 j = strlen(tg->Mainloop.scene_suff);
686 if(j){
687 strcat(snappath,"_");
688 strcat(snappath,tg->Mainloop.scene_suff);
689 }
690 }
691 strcat(snappath,"/");
692 strcat(snappath,folder);
693 fw_mkdir(snappath); //1_wrl/fixture
694 //fwl_set_SnapTmp(snappath); //sets the folder for snaps
695 strcat(snappath,"/");
696 strcat(snappath,snapfile);
697 strcat(snappath,suff); //".bmp");
698 //fwl_set_SnapFile(snapfile);
699 fwl_set_SnapFile(snappath); //1_wrl/fixture/17.bmp
700 }
701 if(namingMethod == 2){
702 //flattened filename approach with '_'
703 //if snapshot 'x' is on frame 17, and fixture,
704 // then 1_wrl_fixture_17.snap or .bmp
705 char snappath[100];
706 int j, k;
707 strcpy(snappath,tg->Mainloop.scene_name);
708 k = strlen(snappath);
709 if(k){
710 j= strlen(tg->Mainloop.scene_suff);
711 if(j){
712 strcat(snappath,"_");
713 strcat(snappath,tg->Mainloop.scene_suff);
714 }
715 strcat(snappath,"_");
716 }
717 strcat(snappath,folder);
718 strcat(snappath,"_");
719 strcat(snappath,snapfile);
720 strcat(snappath,suff); //".bmp");
721 fwl_set_SnapFile(snappath);
722 }
723 if(namingMethod == 3){
724 //group folder
725 //if snapshot 'x' is on frame 17, and fixture,
726 // then fixture/1_wrl_17.snap or .bmp
727 char snappath[100];
728 int j, k;
729 strcpy(snappath,folder);
730 fw_mkdir(snappath); // /fixture
731 strcat(snappath,"/");
732 strcat(snappath,tg->Mainloop.scene_name); // /fixture/1
733 k = strlen(tg->Mainloop.scene_name);
734 if(k){
735 j= strlen(tg->Mainloop.scene_suff);
736 if(j){
737 strcat(snappath,"_");
738 strcat(snappath,tg->Mainloop.scene_suff);
739 }
740 strcat(snappath,"_");
741 }
742 strcat(snappath,snapfile);
743 strcat(snappath,suff); //".bmp");
744 fwl_set_SnapFile(snappath); // /fixture/1_wrl_17.bmp
745 }
746 if(namingMethod == 4){
747 //group folder
748 //if snapshot 'x' is the first one .0001, and fixture,
749 // then fixture/1_wrl.0001.rgb or .bmp
750 char snappath[100];
751 char *sep = "_"; // "." or "_" or "/"
752 set_snapshotModeTesting(TRUE);
753 //if(isSnapshotModeTesting())
754 // printf("testing\n");
755 //else
756 // printf("not testing\n");
757 strcpy(snappath,folder);
758 fw_mkdir(snappath); // /fixture
759 fwl_set_SnapTmp(snappath);
760
761 snappath[0] = '\0';
762 if(p->nameTest){
763 strcat(snappath,p->nameTest);
764 }else{
765 if(tg->Mainloop.scene_name){
766 strcat(snappath,tg->Mainloop.scene_name); // /fixture/1
767 if(tg->Mainloop.scene_suff)
768 {
769 strcat(snappath,sep); // "." or "_");
770 strcat(snappath,tg->Mainloop.scene_suff);
771 }
772 }
773 }
774 fwl_set_SnapFile(snappath); // /fixture/1_wrl.001.bmp
775
776 }
777 }
778 }
779 fwl_do_keyPress0(key, type);
780
781 }
782 }
783 if(strlen(mouseStr)>2){
784 int i,ii,len;
785 int mev;
786 unsigned int button;
787 float x,y;
788 len = strlen(mouseStr);
789 ii=1;
790 do{
791 for(i=ii;i<len;i++)
792 if(mouseStr[i] == ';') break;
793
794 sscanf(&mouseStr[ii],"%d,%d,%d,%d,%d;",&mev,&button,&ix,&iy,&ID);
795 //fwl_handle_aqua_multiNORMAL(mev,button,ix,iy,ID);
796 fwl_handle_mouse0(mev, button, ix, iy, ID);
797 //printf("%d,%d,%f,%f;",mev,button,x,y);
798 ii=i+1;
799 }while(ii<len-1);
800 }
801 }
802 }
803 fwl_RenderSceneUpdateSceneTARGETWINDOWS();
804 //fwl_RenderSceneUpdateScene0(dtime);
805}
806extern void (*fwl_do_rawKeyPressPTR)(int key, int type);
807extern int (*fwl_handle_mousePTR)(const int mev, const unsigned int button, int x, int y, int windex);
808extern void (*fwl_RenderSceneUpdateScenePTR)();
809extern void (*handlePTR)(const int mev, const unsigned int button, const float x, const float y);
810extern char * (*nameLogFileFolderPTR)(char *logfilename, int size);
811void SnapshotTesting_setHandlers(){
812 fwl_do_rawKeyPressPTR = fwl_do_rawKeyPressTESTING;
813 fwl_handle_mousePTR = fwl_handle_aqua_TESTING;
814 fwl_RenderSceneUpdateScenePTR = fwl_RenderSceneUpdateSceneTESTING;
815 //handlePTR = handleTESTING;
816 nameLogFileFolderPTR = nameLogFileFolderTESTING;
817}
818
819#endif //USE_SNAPSHOT_TESTING
Definition Viewer.h:141