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
28void fwl_set_modeRecord()
29{
30}
31void fwl_set_modeFixture()
32{
33}
34void 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
348void fwl_set_modeRecord()
349{
350 ppSnapshotTesting p;
351 //ttglobal tg = gglobal();
352 //p = (ppSnapshotTesting)tg->SnapshotTesting.prv;
353 p = get_ppSnapshotTesting();
354 p->modeRecord = TRUE;
355}
356void fwl_set_modeFixture()
357{
358 ppSnapshotTesting p;
359 //ttglobal tg = gglobal();
360 //p = (ppSnapshotTesting)tg->SnapshotTesting.prv;
361 p = get_ppSnapshotTesting();
362 p->modeFixture = TRUE;
363}
364void fwl_set_modePlayback()
365{
366 ppSnapshotTesting p;
367 //ttglobal tg = gglobal();
368 //p = (ppSnapshotTesting)tg->SnapshotTesting.prv;
369 p = get_ppSnapshotTesting();
370 p->modePlayback = TRUE;
371}
372void fwl_set_nameTest(char *nameTest)
373{
374 ppSnapshotTesting p;
375 //ttglobal tg = gglobal();
376 //p = (ppSnapshotTesting)tg->SnapshotTesting.prv;
377 p = get_ppSnapshotTesting();
378 p->nameTest = STRDUP(nameTest);
379}
380void fwl_set_testPath(char *testPath)
381{
382 ppSnapshotTesting p;
383 int ierr;
384 //ttglobal tg = gglobal();
385 //p = (ppSnapshotTesting)tg->SnapshotTesting.prv;
386 p = get_ppSnapshotTesting();
387 p->testPath = STRDUP(testPath);
388 ierr = chdir(p->testPath);
389 if (ierr == -1) {
390 //folder may not exist yet. Try and create it.
391 mkdir(p->testPath, 0755);
392 ierr = chdir(p->testPath);
393 }
394 if (1) {
395 //where are we?
396 char cwd[1000];
397 getcwd(cwd, 999);
398 printf("current working directory= %s\n", cwd);
399 }
400 //printf("ierr = %d", ierr);
401}
402
403char *nameLogFileFolderTESTING(char *logfilename, int size){
404 ppSnapshotTesting p;
405 ttglobal tg = gglobal();
406 //p = (ppSnapshotTesting)tg->SnapshotTesting.prv;
407 p = get_ppSnapshotTesting();
408
409 if(p->modePlayback || p->modeFixture){
410 if(p->modePlayback)
411 strcat(logfilename,"playback");
412 else
413 strcat(logfilename,"fixture");
414 fw_mkdir(logfilename);
415 strcat(logfilename,"/");
416 if(p->nameTest){
417 // /fixture/test1.log
418 strcat(logfilename,p->nameTest);
419 }else if(tg->Mainloop.scene_name){
420 // /fixture/1_wrl.log
421 strcat(logfilename,tg->Mainloop.scene_name);
422 if(tg->Mainloop.scene_suff){
423 strcat(logfilename,"_");
424 strcat(logfilename,tg->Mainloop.scene_suff);
425 }
426 }
427 }else{
428 nameLogFileFolderNORMAL(logfilename,size);
429 }
430 return logfilename;
431}
432
433
434int fw_mkdir(const char* path);
435void fwl_RenderSceneUpdateScene0(double dtime);
436void fwl_RenderSceneUpdateSceneTARGETWINDOWS();
437void fwl_RenderSceneUpdateSceneTESTING() {
438 double dtime;
439 //ttglobal tg = gglobal();
440 //ppMainloop p = (ppMainloop)tg->Mainloop.prv;
441 ppSnapshotTesting p;
442 ttglobal tg = gglobal();
443 //p = (ppSnapshotTesting)tg->SnapshotTesting.prv;
444 p = get_ppSnapshotTesting();
445
446
447 dtime = Time1970sec();
448 if((p->modeRecord || p->modeFixture || p->modePlayback)) //commandline --record/-R and --playback/-P, for automated testing
449 {
450 //functional testing support options May 2013
451 //records frame#, dtime, keyboard, mouse to an ASCII .fwplay file for playback
452 //to record, run a scene file with -R or --record option
453 //copy the .fwplay between platforms
454 //before starting refactoring, run scenes with -F or --fixture option,
455 // and hit the 'x' key to save a snapshot one or more times per fixture run
456 //after each refactoring step, run scenes with -P or --playback option,
457 // and (with perl script) do a file compare(fixture_snapshot,playback_snapshot)
458 //
459 //on the command line use:
460 //-R to just record the .fwplay file
461 //-F to play recording and save as fixture
462 //-P to play recording and save as playback
463 //-R -F to record and save as fixture in one step
464 //command line long option equivalents: -R --record, -F --fixture, -P --playback
465 int key;
466 int type;
467 int mev,ix,iy,ID;
468 unsigned int button;
469 float x,y;
470 char buff[1000], keystrokes[200], mouseStr[1000];
471 int namingMethod;
472 char *folder;
473 char sceneName[1000];
474 //naming method for related files (and folders)
475 //0=default: recording.fwplay, fixture.bmp playback.bmp - will overwrite for each scene
476 //1=folders: 1_wrl/recording.fwplay, 1_wrl/fixture/17.bmp, 1_wrl/playback/17.bmp
477 //2=flattened: 1_wrl.fwplay, 1_wrl_fixture_17.bmp, 1_wrl_playback_17.bmp (17 is frame#)
478 //3=groupfolders: /tests, /recordings/*.fwplay, /fixtures/1_wrl_17.bmp /playbacks/1_wrl_17.bmp
479 //4=groupfolders: /tests, /recordings/*.fwplay, /fixtures/1_wrl_17.bmp /playbacks/1_wrl_17.bmp
480 // - 4 same as 3, except done to harmonize with linux/aqua naming approach:
481 // - fwl_set_SnapFile(path = {"fixture" | "playback" }); to set mytmp
482 // -
483 folder = NULL;
484 namingMethod = 4;
485 //if(p->frameNum == 1){
486 if(!p->fwplayOpened){
487 char recordingName[1000];
488 int j,k;
489 p->fwplayOpened = 1;
490 recordingName[0] = '\0';
491 sceneName[0] = '\0';
492 if(tg->Mainloop.scene_name){
493 strcat(sceneName,tg->Mainloop.scene_name);
494 if(tg->Mainloop.scene_suff){
495 strcat(sceneName,".");
496 strcat(sceneName,tg->Mainloop.scene_suff);
497 }
498 }
499 if(namingMethod==3 || namingMethod==4){
500 strcpy(recordingName,"recording");
501 fw_mkdir(recordingName);
502 strcat(recordingName,"/");
503 }
504 if(namingMethod>0){
505 if(p->nameTest){
506 strcat(recordingName,p->nameTest);
507 }else{
508 strcat(recordingName,tg->Mainloop.scene_name);
509 k = strlen(recordingName);
510 if(k){
511 //1.wrl -> 1_wrl
512 j = strlen(tg->Mainloop.scene_suff);
513 if(j){
514 strcat(recordingName,"_");
515 strcat(recordingName,tg->Mainloop.scene_suff);
516 }
517 }
518 }
519 }
520 if(namingMethod==1){
521 fw_mkdir(recordingName);
522 strcat(recordingName,"/recording"); //recording.fwplay a generic name, in case there's no scene name
523 }
524 if(namingMethod==0)
525 strcat(recordingName,"recording");
526 strcat(recordingName,".fwplay"); //1_wrl.fwplay
527 p->recordingFName = STRDUP(recordingName);
528
529 if(p->modeFixture || p->modePlayback){
530 if(!p->modeRecord){
531 p->recordingFile = fopen(p->recordingFName, "r");
532 if(p->recordingFile == NULL){
533 printf("ouch recording file %s not found\n", p->recordingFName);
534 fw_exit(1);
535 }
536 if( fgets(buff, 1000, p->recordingFile) != NULL){
537 char window_widthxheight[100], equals[50];
538 int width, height;
539 //window_wxh = 600,400
540 if( sscanf(buff,"%s %s %d, %d\n",window_widthxheight,equals, &width,&height) == 4) {
541 if(width != tg->display.screenWidth || height != tg->display.screenHeight){
542 //right now all we can do is passively complain
543 printf("Ouch - the test playback window size is different than recording:\n");
544 printf("recording %d x %d playback %d x %d\n",width,height,
545 tg->display.screenWidth,tg->display.screenHeight);
546 printf("hit Enter:");
547 getchar();
548 }
549 }
550 }
551 if( fgets(buff, 1000, p->recordingFile) != NULL){
552 char scenefile[100], equals[50];
553 //scenefile = 1.wrl
554 if( sscanf(buff,"%s %s %s \n",scenefile,equals, sceneName) == 3) {
555 if(!tg->Mainloop.scene_name){
556 char* suff = NULL;
557 char* local_name = NULL;
558 char* url = NULL;
559 if(strlen(sceneName)) url = STRDUP(sceneName);
560 if(url){
561 splitpath_local_suffix(url, &local_name, &suff);
562 gglobal()->Mainloop.url = url;
563 gglobal()->Mainloop.scene_name = local_name;
564 gglobal()->Mainloop.scene_suff = suff;
565 fwl_resource_push_single_request(url);
566 }
567 }
568 }
569 }
570 }
571 }
572 }
573 int doEvents = (!fwl_isinputThreadParsing()) && (!fwl_isTextureParsing()) && fwl_isInputThreadInitialized();
574 //printf("frame %d doevents=%d\n",p->frameNum,p->doEvents);
575 if(!doEvents)
576 return; //for Record and Playback, don't start doing things until scene and textures are loaded
577 if(p->modeRecord)
578 if(dtime - tg->Mainloop.TickTime < .5) return; //slow down frame rate to 2fps to reduce empty meaningless records
579 p->frameNum++; //for record, frame relative to when scene is loaded
580
581 if(p->modeRecord){
582 int i;
583 char temp[1000];
584 if(p->frameNum == 1){
585 if(0){
586 //where are we?
587 char cwd[1000];
588 getcwd(cwd, 999);
589 printf("current working directory= %s\n", cwd);
590 }
591 p->recordingFile = fopen(p->recordingFName, "w");
592 if(p->recordingFile == NULL){
593 printf("ouch recording file %s not found\n", p->recordingFName);
594 fw_exit(1);
595 }
596 //put in a header record, passively showing window widthxheight
597 fprintf(p->recordingFile,"window_wxh = %d, %d \n",tg->display.screenWidth,tg->display.screenHeight);
598 fprintf(p->recordingFile,"scenefile = %s \n",tg->Mainloop.url); //sceneName);
599 }
600 strcpy(keystrokes,"\"");
601 while(dequeueKeyPress(p,&key,&type)){
602 sprintf(temp,"%d,%d,",key,type);
603 strcat(keystrokes,temp);
604 }
605 strcat(keystrokes,"\"");
606 strcpy(mouseStr,"\"");
607 i = 0;
608 while(dequeueMouseMulti(p,&mev, &button, &ix, &iy, &ID)){
609 sprintf(temp,"%d,%d,%d,%d,%d;",mev,button,ix,iy,ID);
610 strcat(mouseStr,temp);
611 i++;
612 }
613 strcat(mouseStr,"\"");
614 fprintf(p->recordingFile,"%d %.6lf %s %s\n",p->frameNum,dtime,keystrokes,mouseStr);
615 //in case we are -R -F together,
616 //we need to round dtime for -F like it will be coming out of .fwplay for -P
617 sprintf(temp,"%.6lf",dtime);
618 sscanf(temp,"%lf",&dtime);
619 //folder = "fixture";
620 folder = NULL;
621 }
622 if(p->modeFixture || p->modePlayback){
623 if(!p->modeRecord){
624 // playback[i] = {iframe, dtime, keystrokes or NULL, mouse (xy,button sequence) or NULL, snapshot URL or NULL, scenegraph_dump URL or NULL, ?other?}
625 if( fgets( buff, 1000, p->recordingFile ) != NULL ) {
626 if(sscanf(buff,"%d %lf %s %s\n",&p->frameNum,&dtime,keystrokes,mouseStr) == 4){ //,snapshotURL,scenegraphURL) == 6){
627 if(0) printf("%d %lf %s %s\n",p->frameNum,dtime,keystrokes,mouseStr);
628 }
629 }
630 }
631 if(p->modeFixture) folder = "fixture";
632 if(p->modePlayback) folder = "playback";
633 }
634 //for all 3 - read the keyboard string and the mouse string
635 if(p->modeRecord || p->modeFixture || p->modePlayback){
636 if(strlen(keystrokes)>2){ // "x,1," == 6
637 char *next,*curr;
638 //count the number of ','
639 //for(i=0,n=0;i<strlen(keystrokes);i++) if(keystrokes[i] == ',') n++; //(strlen(keystrokes) -2)/4;
640 //n /= 2; //each keystroke has 2 commas: (char),(type),
641 curr = &keystrokes[1]; //skip leading "
642 while(curr && strlen(curr)>1){
643 //for(i=0;i<n;i++){
644 //ii = i*4 +1;
645 //sscanf(&keystrokes[ii],"%d,%d",&key,&type);
646 sscanf(curr,"%d",&key);
647 next = strchr(curr,',');
648 curr = &next[1];
649 sscanf(curr,"%d",&type);
650 next = strchr(curr,',');
651 curr = &next[1];
652 if(p->modeFixture || p->modePlayback){
653 //we will catch the snapshot keybaord command and prepare the
654 //snapshot filename and folder/directory for fixture and playback
655 if(key == 'x'){
656 //prepare snapshot folder(scene/ + fixture ||playback)
657 // and file name(frame#)
658 char snapfile[5];
659#ifdef _MSC_VER
660 char *suff = ".bmp";
661#else
662 char *suff = ".snap";
663#endif
664 sprintf(snapfile,"%d",p->frameNum);
665 if(namingMethod == 0){
666 //default: recording.bmp, playback.bmp
667 char snappath[100];
668 strcpy(snappath,folder);
669 strcat(snappath,suff);
670 fwl_set_SnapFile(snappath);
671 }
672 if(namingMethod==1){
673 //nested folder approach
674 //1=folders: 1_wrl/recording.fwplay, 1_wrl/fixture/17.bmp, 1_wrl/playback/17.bmp
675 int k,j;
676 char snappath[100];
677 strcpy(snappath,tg->Mainloop.scene_name);
678 k = strlen(snappath);
679 if(k){
680 //1.wrl -> 1_wrl
681 j = strlen(tg->Mainloop.scene_suff);
682 if(j){
683 strcat(snappath,"_");
684 strcat(snappath,tg->Mainloop.scene_suff);
685 }
686 }
687 strcat(snappath,"/");
688 strcat(snappath,folder);
689 fw_mkdir(snappath); //1_wrl/fixture
690 //fwl_set_SnapTmp(snappath); //sets the folder for snaps
691 strcat(snappath,"/");
692 strcat(snappath,snapfile);
693 strcat(snappath,suff); //".bmp");
694 //fwl_set_SnapFile(snapfile);
695 fwl_set_SnapFile(snappath); //1_wrl/fixture/17.bmp
696 }
697 if(namingMethod == 2){
698 //flattened filename approach with '_'
699 //if snapshot 'x' is on frame 17, and fixture,
700 // then 1_wrl_fixture_17.snap or .bmp
701 char snappath[100];
702 int j, k;
703 strcpy(snappath,tg->Mainloop.scene_name);
704 k = strlen(snappath);
705 if(k){
706 j= strlen(tg->Mainloop.scene_suff);
707 if(j){
708 strcat(snappath,"_");
709 strcat(snappath,tg->Mainloop.scene_suff);
710 }
711 strcat(snappath,"_");
712 }
713 strcat(snappath,folder);
714 strcat(snappath,"_");
715 strcat(snappath,snapfile);
716 strcat(snappath,suff); //".bmp");
717 fwl_set_SnapFile(snappath);
718 }
719 if(namingMethod == 3){
720 //group folder
721 //if snapshot 'x' is on frame 17, and fixture,
722 // then fixture/1_wrl_17.snap or .bmp
723 char snappath[100];
724 int j, k;
725 strcpy(snappath,folder);
726 fw_mkdir(snappath); // /fixture
727 strcat(snappath,"/");
728 strcat(snappath,tg->Mainloop.scene_name); // /fixture/1
729 k = strlen(tg->Mainloop.scene_name);
730 if(k){
731 j= strlen(tg->Mainloop.scene_suff);
732 if(j){
733 strcat(snappath,"_");
734 strcat(snappath,tg->Mainloop.scene_suff);
735 }
736 strcat(snappath,"_");
737 }
738 strcat(snappath,snapfile);
739 strcat(snappath,suff); //".bmp");
740 fwl_set_SnapFile(snappath); // /fixture/1_wrl_17.bmp
741 }
742 if(namingMethod == 4){
743 //group folder
744 //if snapshot 'x' is the first one .0001, and fixture,
745 // then fixture/1_wrl.0001.rgb or .bmp
746 char snappath[100];
747 char *sep = "_"; // "." or "_" or "/"
748 set_snapshotModeTesting(TRUE);
749 //if(isSnapshotModeTesting())
750 // printf("testing\n");
751 //else
752 // printf("not testing\n");
753 strcpy(snappath,folder);
754 fw_mkdir(snappath); // /fixture
755 fwl_set_SnapTmp(snappath);
756
757 snappath[0] = '\0';
758 if(p->nameTest){
759 strcat(snappath,p->nameTest);
760 }else{
761 if(tg->Mainloop.scene_name){
762 strcat(snappath,tg->Mainloop.scene_name); // /fixture/1
763 if(tg->Mainloop.scene_suff)
764 {
765 strcat(snappath,sep); // "." or "_");
766 strcat(snappath,tg->Mainloop.scene_suff);
767 }
768 }
769 }
770 fwl_set_SnapFile(snappath); // /fixture/1_wrl.001.bmp
771
772 }
773 }
774 }
775 fwl_do_keyPress0(key, type);
776
777 }
778 }
779 if(strlen(mouseStr)>2){
780 int i,ii,len;
781 int mev;
782 unsigned int button;
783 float x,y;
784 len = strlen(mouseStr);
785 ii=1;
786 do{
787 for(i=ii;i<len;i++)
788 if(mouseStr[i] == ';') break;
789
790 sscanf(&mouseStr[ii],"%d,%d,%d,%d,%d;",&mev,&button,&ix,&iy,&ID);
791 //fwl_handle_aqua_multiNORMAL(mev,button,ix,iy,ID);
792 fwl_handle_mouse0(mev, button, ix, iy, ID);
793 //printf("%d,%d,%f,%f;",mev,button,x,y);
794 ii=i+1;
795 }while(ii<len-1);
796 }
797 }
798 }
799 fwl_RenderSceneUpdateSceneTARGETWINDOWS();
800 //fwl_RenderSceneUpdateScene0(dtime);
801}
802extern void (*fwl_do_rawKeyPressPTR)(int key, int type);
803extern int (*fwl_handle_mousePTR)(const int mev, const unsigned int button, int x, int y, int windex);
804extern void (*fwl_RenderSceneUpdateScenePTR)();
805extern void (*handlePTR)(const int mev, const unsigned int button, const float x, const float y);
806extern char * (*nameLogFileFolderPTR)(char *logfilename, int size);
807void SnapshotTesting_setHandlers(){
808 fwl_do_rawKeyPressPTR = fwl_do_rawKeyPressTESTING;
809 fwl_handle_mousePTR = fwl_handle_aqua_TESTING;
810 fwl_RenderSceneUpdateScenePTR = fwl_RenderSceneUpdateSceneTESTING;
811 //handlePTR = handleTESTING;
812 nameLogFileFolderPTR = nameLogFileFolderTESTING;
813}
814
815#endif //USE_SNAPSHOT_TESTING
Definition Viewer.h:139