1
/* gcompris - photohunter.c
3
* Copyright (C) 2009 Marc Le Douarain
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation; either version 3 of the License, or
8
* (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, see <http://www.gnu.org/licenses/>.
21
#include "gcompris/gcompris.h"
23
static GcomprisBoard *gcomprisBoard = NULL;
24
static GooCanvasItem *boardRootItem = NULL;
25
static gboolean board_paused = TRUE;
27
static void start_board (GcomprisBoard *agcomprisBoard);
28
static void pause_board (gboolean pause);
29
static void end_board (void);
30
static void set_level(guint level);
31
static gboolean is_our_board (GcomprisBoard *gcomprisBoard);
34
#define NBR_OF_PHOTOS_PER_SESSION 9
35
#define FRAME_OFFSET 2
36
typedef struct StructGame
43
int NbrOfPhotosAvailable;
44
int * PhotoNbrForThisLevel; // random photo to play for each level
46
typedef struct StructDiffCoor
54
GooCanvasItem *ItemPhoto[2] = {NULL, NULL };
55
GooCanvasItem *ItemFrame[2] = {NULL, NULL };
57
GArray *gDiffCoorArray = NULL; // coords list of the differences in the photos
58
GArray *gDiffFoundArray = NULL; // coords already discovered
60
int LoadNextLevelAfterEndOfBonusDisplay;
62
static void CleanLevelDatas( void );
63
static gchar * ScanAndPickRandomFile( int * pNbrOfFiles, int RandomSelection );
64
static void StartLevel( );
65
static gint MouseClick(GooCanvasItem *item, GdkEvent *event, gpointer data);
66
static void LoadCsvDiffFile( char * pFilename );
69
/* Description of this plugin */
70
static BoardPlugin menu_bp =
75
"Find differences between two photos",
76
"Marc Le Douarain (http://membres.lycos.fr/mavati)",
94
/* =====================================================================
95
* IMPORTANT, REQUIRED TO "SEE" THE PLUGIN BOARD !
96
* =====================================================================*/
97
GET_BPLUGIN_INFO(photohunter)
99
/* =====================================================================
100
* (ALSO CALLED AFTER END OF BONUS DISPLAY WHEN A LEVEL IS COMPLETED)
101
* =====================================================================*/
102
static void pause_board (gboolean pause)
104
if(gcomprisBoard==NULL)
106
printf("pause_board() called with value=%d\n",pause);
107
if ( LoadNextLevelAfterEndOfBonusDisplay==TRUE && pause==FALSE )
109
LoadNextLevelAfterEndOfBonusDisplay = FALSE;
110
gcomprisBoard->level++;
111
if ( gcomprisBoard->level>gcomprisBoard->maxlevel )
112
gcomprisBoard->level = 1;
116
board_paused = pause;
119
/* =====================================================================
121
* =====================================================================*/
122
static void start_board (GcomprisBoard *agcomprisBoard)
124
if(agcomprisBoard!=NULL)
126
char * PhotoSelectedMark;
129
gcomprisBoard = agcomprisBoard;
131
gc_set_default_background(goo_canvas_get_root_item(gcomprisBoard->canvas));
133
// get nbr of photos available, and init as none found for now
134
ScanAndPickRandomFile( &Game.NbrOfPhotosAvailable, -1 );
135
if ( Game.NbrOfPhotosAvailable==0 )
136
gc_dialog(_("Error: Absolutely no photo found in the data directory"), gc_board_stop);
138
gcomprisBoard->level = 1;
139
// limit to "N" photos to play per game session (in case of more photos in the directory...)
140
gcomprisBoard->maxlevel=Game.NbrOfPhotosAvailable>NBR_OF_PHOTOS_PER_SESSION?NBR_OF_PHOTOS_PER_SESSION:Game.NbrOfPhotosAvailable;
141
gcomprisBoard->sublevel = 0;
142
gcomprisBoard->number_of_sublevel = 0;
144
gc_bar_set(GC_BAR_LEVEL);
146
Game.PhotoNbrForThisLevel = malloc( (gcomprisBoard->maxlevel+1)*sizeof(int) );
147
PhotoSelectedMark = malloc( Game.NbrOfPhotosAvailable*sizeof(char) );
148
if ( Game.PhotoNbrForThisLevel && PhotoSelectedMark )
150
// precalc a list of photos to play for each level
151
for( InitScan=0; InitScan<Game.NbrOfPhotosAvailable ; InitScan++ )
152
PhotoSelectedMark[ InitScan ] = FALSE;
153
for( StorePhotoLevel=1; StorePhotoLevel<=gcomprisBoard->maxlevel; StorePhotoLevel++ )
156
// we never give the same photo...
159
RandVal = (int)g_random_int_range( 0, Game.NbrOfPhotosAvailable );
161
while( PhotoSelectedMark[ RandVal ]!=FALSE );
162
PhotoSelectedMark[ RandVal ] = TRUE;
163
Game.PhotoNbrForThisLevel[ StorePhotoLevel ] = RandVal;
165
free( PhotoSelectedMark );
167
boardRootItem = goo_canvas_group_new (goo_canvas_get_root_item(gcomprisBoard->canvas), NULL);
168
gtk_signal_connect(GTK_OBJECT(gcomprisBoard->canvas), "event", (GtkSignalFunc) MouseClick, NULL);
170
gDiffCoorArray = g_array_new( FALSE, FALSE, sizeof(StructDiffCoor) );
171
gDiffFoundArray = g_array_new( FALSE, FALSE, sizeof(StructDiffCoor) );
172
LoadNextLevelAfterEndOfBonusDisplay = FALSE;
179
/* =====================================================================
181
* =====================================================================*/
182
static void end_board ()
184
printf("End Board!\n");
185
if(gcomprisBoard!=NULL)
191
gcomprisBoard = NULL;
192
if(boardRootItem!=NULL)
193
goo_canvas_item_remove( boardRootItem );
194
if ( Game.PhotoNbrForThisLevel!=NULL )
195
free( Game.PhotoNbrForThisLevel );
196
if ( gDiffCoorArray!=NULL )
197
g_array_free( gDiffCoorArray, TRUE );
198
if ( gDiffFoundArray!=NULL )
199
g_array_free( gDiffFoundArray, TRUE );
202
/* =====================================================================
204
* =====================================================================*/
205
static void set_level(guint level)
207
if(gcomprisBoard!=NULL)
209
gcomprisBoard->level = level;
210
if ( gcomprisBoard->level>gcomprisBoard->maxlevel )
211
gcomprisBoard->level = 1;
216
/* =====================================================================
218
* =====================================================================*/
219
static gboolean is_our_board (GcomprisBoard *gcomprisBoard)
223
if(g_strcasecmp(gcomprisBoard->type, "photohunter")==0)
225
/* Set the plugin entry */
226
gcomprisBoard->plugin=&menu_bp;
233
static void CleanLevelDatas( void )
236
printf("CleaningUp\n");
237
if ( gDiffCoorArray!=NULL )
239
if ( gDiffCoorArray->len>0 )
240
g_array_remove_range( gDiffCoorArray, 0, gDiffCoorArray->len );
242
if ( gDiffFoundArray!=NULL )
244
if ( gDiffFoundArray->len>0 )
245
g_array_remove_range( gDiffFoundArray, 0, gDiffFoundArray->len );
247
for( ScanPhoto=0; ScanPhoto<2; ScanPhoto++ )
249
if ( ItemPhoto[ ScanPhoto ]!=NULL )
251
goo_canvas_item_remove( ItemPhoto[ ScanPhoto ] );
252
ItemPhoto[ ScanPhoto ] = NULL;
254
if ( ItemFrame[ ScanPhoto ]!=NULL )
256
goo_canvas_item_remove( ItemFrame[ ScanPhoto ] );
257
ItemFrame[ ScanPhoto ] = NULL;
260
printf("EndOfClean\n");
263
static GooCanvasItem * LoadPhoto( char * file, int PhotoNbr )
265
GooCanvasItem * item = NULL;
266
GdkPixbuf * pixmap = gc_pixmap_load(file);
272
Game.PhotoWidth = gdk_pixbuf_get_width( pixmap );
273
Game.PhotoHeight = gdk_pixbuf_get_height( pixmap );
274
Game.SpaceX = (BOARDWIDTH-2*Game.PhotoWidth)/3;
275
Game.SpaceY = (BOARDHEIGHT-Game.PhotoHeight)/2;
281
PosiX = 2*Game.SpaceX+Game.PhotoWidth;
284
item = goo_canvas_image_new (boardRootItem,
289
gdk_pixbuf_unref(pixmap);
294
static void DrawCircle( int x1, int y1, int x2, int y2, char * color )
298
goo_canvas_ellipse_new (boardRootItem,
303
"stroke-color", color,
304
"line-width", (double)1,
307
static GooCanvasItem * DrawPhotoFrame( int PhotoNbr, char * color )
310
GooCanvasItem * item = NULL;
313
x1 = Game.SpaceX-FRAME_OFFSET;
314
y1 = Game.SpaceY-FRAME_OFFSET;
318
x1 = 2*Game.SpaceX+Game.PhotoWidth-FRAME_OFFSET;
319
y1 = Game.SpaceY-FRAME_OFFSET;
321
item = goo_canvas_rect_new( boardRootItem,
323
Game.PhotoWidth+FRAME_OFFSET +2, Game.PhotoHeight+FRAME_OFFSET +2,
324
/*"fill_color"*/"stroke_color", color,
329
static void StartLevel( )
334
int RandVal = Game.PhotoNbrForThisLevel[ gcomprisBoard->level ];
335
printf("Random nbr = %d (for level=%d)\n", RandVal, gcomprisBoard->level);
339
// get base filename datas to play
340
gchar * RandomFileToLoad = ScanAndPickRandomFile( NULL, RandVal );
341
printf("Random file choosed = %s\n", RandomFileToLoad );
342
for( ScanPhoto=0; ScanPhoto<2; ScanPhoto++ )
344
str = g_strdup_printf("%s/%s%c.jpg", gcomprisBoard->boarddir, RandomFileToLoad, ScanPhoto==0?'a':'b' );
345
ItemPhoto[ ScanPhoto ] = LoadPhoto( str, ScanPhoto );
347
ItemFrame[ ScanPhoto ] = DrawPhotoFrame( ScanPhoto, "black" );
349
str = gc_file_find_absolute("%s/%s.csv", gcomprisBoard->boarddir, RandomFileToLoad);
350
LoadCsvDiffFile( str );
352
g_free(RandomFileToLoad);
356
for( scanposi=0; scanposi<gDiffCoorArray->len; scanposi++)
358
StructDiffCoor * pDiff = &g_array_index (gDiffCoorArray, StructDiffCoor, scanposi);
359
DrawCircle( Game.SpaceX+pDiff->x1, Game.SpaceY+pDiff->y1, Game.SpaceX+pDiff->x2, Game.SpaceY+pDiff->y2, "green" );
360
DrawCircle( (2*Game.SpaceX+Game.PhotoWidth)+pDiff->x1, Game.SpaceY+pDiff->y1, (2*Game.SpaceX+Game.PhotoWidth)+pDiff->x2, Game.SpaceY+pDiff->y2, "green" );
364
gcomprisBoard->sublevel = 0;
365
gcomprisBoard->number_of_sublevel = gDiffCoorArray->len;
366
gc_score_start(SCORESTYLE_NOTE,
369
gcomprisBoard->number_of_sublevel);
370
gc_score_set(gcomprisBoard->sublevel);
371
gc_bar_set_level(gcomprisBoard);
372
printf("Start level=%d, total=%d\n", gcomprisBoard->level, gcomprisBoard->maxlevel );
376
static int TestIfClickedOnDiff( int ClickX, int ClickY )
379
int ScanPosi,ScanPhoto;
380
for( ScanPhoto=0; ScanPhoto<2; ScanPhoto++ )
382
for( ScanPosi=0; ScanPosi<gDiffCoorArray->len; ScanPosi++)
384
int OffsetX = (ScanPhoto==0)?Game.SpaceX:(Game.SpaceX*2+Game.PhotoWidth);
385
int OffsetY = Game.SpaceY;
386
StructDiffCoor * pDiff = &g_array_index (gDiffCoorArray, StructDiffCoor, ScanPosi);
387
if ( OffsetX+pDiff->x1 <= ClickX && ClickX<= OffsetX+pDiff->x2
388
&& OffsetY+pDiff->y1 <= ClickY && ClickY<= OffsetY+pDiff->y2 )
391
printf("CLICKED ON DIFF%d: coords x1=%d, y1=%d, x2=%d, y2=%d\n", ScanPosi, pDiff->x1, pDiff->y1, pDiff->x2, pDiff->y2 );
397
static void TestClick( int ClickX, int ClickY )
399
int DiffFound = TestIfClickedOnDiff( ClickX, ClickY );
403
StructDiffCoor * pClickedDiffFound = &g_array_index (gDiffCoorArray, StructDiffCoor, DiffFound);
404
// not already found ?
405
if ( gDiffFoundArray->len>0 )
407
int ScanAlreadyFound;
408
for( ScanAlreadyFound=0; ScanAlreadyFound<gDiffFoundArray->len; ScanAlreadyFound++)
410
StructDiffCoor * pScanDiffFound = &g_array_index (gDiffFoundArray, StructDiffCoor, ScanAlreadyFound);
411
if ( pScanDiffFound->x1==pClickedDiffFound->x1 && pScanDiffFound->y1==pClickedDiffFound->y1
412
&& pScanDiffFound->x2==pClickedDiffFound->x2 && pScanDiffFound->y2==pClickedDiffFound->y2 )
415
printf("THIS DIFF IS ALREADY FOUND!\n");
421
g_array_append_val( gDiffFoundArray, *pClickedDiffFound );
422
// draw the found difference on the photos
423
DrawCircle( Game.SpaceX+pClickedDiffFound->x1, Game.SpaceY+pClickedDiffFound->y1, Game.SpaceX+pClickedDiffFound->x2, Game.SpaceY+pClickedDiffFound->y2, "yellow" );
424
DrawCircle( (2*Game.SpaceX+Game.PhotoWidth)+pClickedDiffFound->x1, Game.SpaceY+pClickedDiffFound->y1, (2*Game.SpaceX+Game.PhotoWidth)+pClickedDiffFound->x2, Game.SpaceY+pClickedDiffFound->y2, "yellow" );
425
gcomprisBoard->sublevel++;
426
gc_score_set(gcomprisBoard->sublevel);
428
if ( gDiffFoundArray->len==gDiffCoorArray->len )
430
printf("END OF LEVEL!!!!!!!!!\n");
431
gc_bonus_display( GC_BOARD_WIN, GC_BONUS_SMILEY );
432
LoadNextLevelAfterEndOfBonusDisplay = TRUE;
437
static gint MouseClick(GooCanvasItem *item, GdkEvent *event, gpointer data)
441
if (!gcomprisBoard || board_paused)
448
case GDK_BUTTON_PRESS:
449
// goo_canvas_c2w (gcomprisBoard->canvas, x, y, &x, &y);
450
TestClick( (int)x, (int)y );
459
// Two call methods, firstly to know how many files are available (with RandomSelection to -1),
460
// secondly to return the random file selected.
461
gchar * ScanAndPickRandomFile( int * pNbrOfFiles, int RandomSelection )
463
int NbrOfFilesFound = 0;
464
char SelectionFound = FALSE;
465
gchar * FileChoosen = NULL;
466
char * str = gc_file_find_absolute("%s", gcomprisBoard->boarddir );
467
printf("opening dir : %s\n", str);
468
GDir * FilesDir = g_dir_open( str, 0, NULL );
474
File = g_dir_read_name( FilesDir );
477
if ( g_str_has_suffix(File, ".csv") )
479
printf("filtered file found : %s (select=%d, scan=%d)\n", File, RandomSelection, NbrOfFilesFound );
480
if ( RandomSelection==NbrOfFilesFound )
482
FileChoosen = g_strdup( File );
483
FileChoosen[ strlen(FileChoosen)-4 ] = '\0';
484
printf("filtered file found, after cleanup : %s\n", FileChoosen );
485
SelectionFound = TRUE;
491
while( File!=NULL && !SelectionFound );
492
g_dir_close( FilesDir );
495
if ( pNbrOfFiles!=NULL )
496
*pNbrOfFiles = NbrOfFilesFound;
499
// return nbr of fields found
500
int SplitCommasFieldsInPointersArray( char * LineDatas, char * PtrFieldsDatasFound[], int NbrMaxFields )
503
for( ScanField=0; ScanField<NbrMaxFields; ScanField++ )
504
PtrFieldsDatasFound[ ScanField ] = NULL;
506
PtrFieldsDatasFound[ ScanField++ ] = LineDatas;
512
if ( *LineDatas==',' && *(LineDatas+1)!='\0' )
514
// test if not an empty field...
515
if ( *(LineDatas+1)!=',' )
517
PtrFieldsDatasFound[ ScanField ] = LineDatas+1;
524
while( ScanField<NbrMaxFields-1 && *LineDatas!='\0' );
526
while( ScanField<NbrMaxFields-1 && *LineDatas!='\0' );
529
void ConvertCsvLine( char * FileLineDatas )
531
char * PtrArraysCsv[20];
532
int NbrInfos = SplitCommasFieldsInPointersArray( FileLineDatas, PtrArraysCsv, 20 );
536
Diff.x1 = atoi( PtrArraysCsv[ 0 ] );
537
Diff.y1 = atoi( PtrArraysCsv[ 1 ] );
538
Diff.x2 = atoi( PtrArraysCsv[ 2 ] );
539
Diff.y2 = atoi( PtrArraysCsv[ 3 ] );
540
printf("fields size = %d - diff coords x1=%d, y1=%d, x2=%d, y2=%d\n", NbrInfos, Diff.x1, Diff.y1, Diff.x2, Diff.y2 );
541
g_array_append_val( gDiffCoorArray, Diff );
544
void LoadCsvDiffFile( char * pFilename )
547
printf("opening csv file %s...\n", pFilename);
548
FILE * pFileDiffDesc = fopen( pFilename, "rt" );
551
while( !feof( pFileDiffDesc ) )
553
if ( fgets( LineBuff, 50, pFileDiffDesc )!=NULL )
555
//printf("fgets %s\n", LineBuff );
556
if ( strlen( LineBuff )>=7 )
557
ConvertCsvLine( LineBuff );
560
fclose( pFileDiffDesc );
564
gc_dialog(_("Error: Abnormally failed to load a data file"), gc_board_stop);