Remove stdio while we're at it.
[vlc.git] / modules / visualization / galaktos / preset.c
1 /*****************************************************************************
2  * preset.c:
3  *****************************************************************************
4  * Copyright (C) 2004 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Cyril Deguet <asmax@videolan.org>
8  *          code from projectM http://xmms-projectm.sourceforge.net
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 #include <vlc/vlc.h>
26
27
28 #include <dirent.h>
29 #include <time.h>
30 #include "common.h"
31 #include "fatal.h"
32
33 #include "preset_types.h"
34 #include "preset.h"
35
36 #include "parser.h"
37
38 #include "expr_types.h"
39 #include "eval.h"
40
41 #include "splaytree_types.h"
42 #include "splaytree.h"
43 #include "tree_types.h"
44
45 #include "per_frame_eqn_types.h"
46 #include "per_frame_eqn.h"
47
48 #include "per_pixel_eqn_types.h"
49 #include "per_pixel_eqn.h"
50
51 #include "init_cond_types.h"
52 #include "init_cond.h"
53
54 #include "param_types.h"
55 #include "param.h"
56
57 #include "func_types.h"
58 #include "func.h"
59
60 #include "custom_wave_types.h"
61 #include "custom_wave.h"
62
63 #include "custom_shape_types.h"
64 #include "custom_shape.h"
65
66 #include "idle_preset.h"
67
68 /* The maximum number of preset names loaded into buffer */
69 #define MAX_PRESETS_IN_DIR 50000
70 extern int per_frame_eqn_count;
71 extern int per_frame_init_eqn_count;
72 //extern int custom_per_frame_eqn_count;
73
74 extern splaytree_t * builtin_param_tree;
75
76 preset_t * active_preset = NULL;
77 preset_t * idle_preset = NULL;
78 FILE * write_stream = NULL;
79
80
81 int preset_index = -1;
82 int preset_name_buffer_size = 0;
83 splaytree_t * chrono_order_preset_name_tree = NULL;
84 int get_preset_path(char ** preset_path_ptr, char * filepath, char * filename);
85 preset_t * load_preset(char * pathname);
86 int is_valid_extension(char * name);    
87 int load_preset_file(char * pathname, preset_t * preset);
88 int close_preset(preset_t * preset);
89
90 int write_preset_name(FILE * fs);
91 int write_per_pixel_equations(FILE * fs);
92 int write_per_frame_equations(FILE * fs);
93 int write_per_frame_init_equations(FILE * fs);
94 int write_init_conditions(FILE * fs);
95 void load_init_cond(param_t * param);
96 void load_init_conditions();
97 void write_init(init_cond_t * init_cond);
98 int init_idle_preset();
99 int destroy_idle_preset();
100 void load_custom_wave_init_conditions();
101 void load_custom_wave_init(custom_wave_t * custom_wave);
102
103 void load_custom_shape_init_conditions();
104 void load_custom_shape_init(custom_shape_t * custom_shape);
105
106 /* loadPresetDir: opens the directory buffer
107    denoted by 'dir' to load presets */
108    
109 int loadPresetDir(char * dir) {
110
111   struct dirent ** name_list;
112   char * preset_name;
113   int i, j, dir_size;
114   
115   if (dir == NULL)
116         return ERROR;
117  
118   if (chrono_order_preset_name_tree != NULL) {
119         if (PRESET_DEBUG) printf("loadPresetDir: previous directory doesn't appear to be closed!\n");
120         /* Let this slide for now */
121   }     
122   
123   /* Scan the entire directory, storing each entry in a dirent struct array that needs 
124      to be freed later. For more information, consult scandir(3) in the man pages */
125   if ((dir_size = scandir(dir, &name_list, 0, alphasort)) < 0) {
126         if (PRESET_DEBUG) printf("loadPresetDir: failed to open directory \"%s\"\n", dir);
127         return ERROR;
128   }
129   
130   chrono_order_preset_name_tree = create_splaytree(compare_int, copy_int, free_int);
131   
132   /* Iterate through entire dirent name list, adding to the preset name list if it
133      is valid */  
134   for (i = 0; ((i < dir_size) && (i < MAX_PRESETS_IN_DIR));i++) {
135
136         /* Only perform the next set of operations if the preset name 
137            contains a valid extension */
138         if (is_valid_extension(name_list[i]->d_name)) {
139                 
140                 /* Handle the out of memory case. My guess is xmms would
141                    crash before this program would, but whatever...*/
142                 if ((preset_name = (char*)malloc(MAX_PATH_SIZE)) == NULL) {
143                         if (PRESET_DEBUG) printf("loadPresetDir: out of memory! \n");
144                         
145                         /* Free the rest of the dirent name list */
146                         for (j = i; j < dir_size; j++) 
147                                 free(name_list[j]);
148                         destroy_splaytree(chrono_order_preset_name_tree);
149                         return OUTOFMEM_ERROR;
150                 }
151                                 
152                 /* Now create the full path */
153             if (get_preset_path(&preset_name, dir, name_list[i]->d_name) < 0) {
154                         if (PRESET_DEBUG) printf("loadPresetDir: failed to generate full preset path name!\n");
155                         
156                         /* Free the rest of the dirent name list */
157                         for (j = i; j < dir_size; j++) 
158                                 free(name_list[j]);
159                         destroy_splaytree(chrono_order_preset_name_tree);
160                         return OUTOFMEM_ERROR;
161                         
162                 }
163                 
164                 /* Insert the character string into the splay tree, with the key being its sequence number */
165                 splay_insert(preset_name, &preset_name_buffer_size, chrono_order_preset_name_tree);
166                 preset_name_buffer_size++;
167         }
168         
169         /* Free the dirent struct */
170         free(name_list[i]);
171         
172   }     
173   
174   free(name_list);
175   
176   /* No valid files in directory! */
177   if (chrono_order_preset_name_tree->root == NULL) {
178         if (PRESET_DEBUG) printf("loadPresetDir: no valid files in directory \"%s\"\n", dir);
179         destroy_splaytree(chrono_order_preset_name_tree);
180         chrono_order_preset_name_tree = NULL;
181         return FAILURE;   
182   }     
183           
184   /* Start the prefix index right before the first entry, so next preset
185      starts at the top of the list */
186   preset_index = -1;
187   
188   /* Start the first preset */
189
190   switchPreset(ALPHA_NEXT, HARD_CUT);
191   
192   return SUCCESS;
193 }
194
195 /* closePresetDir: closes the current
196    preset directory buffer */
197
198 int closePresetDir() {
199
200   /* No preset director appears to be loaded */ 
201   if (chrono_order_preset_name_tree == NULL) 
202     return SUCCESS;
203   
204   if (PRESET_DEBUG) {
205          printf("closePresetDir: freeing directory buffer...");
206          fflush(stdout);
207   }  
208   
209   /* Free each entry in the directory preset name tree */
210   splay_traverse(free_int, chrono_order_preset_name_tree);
211   
212   /* Destroy the chronological order splay tree */
213   destroy_splaytree(chrono_order_preset_name_tree);
214   chrono_order_preset_name_tree = NULL;
215   preset_name_buffer_size = 0;
216   if (PRESET_DEBUG) printf("finished\n");
217   
218   return SUCCESS;
219 }
220
221
222
223 /* Converts a preset file name to a full path */ 
224 int get_preset_path(char ** preset_path_ptr, char * filepath, char * filename) {
225
226   char * preset_path;
227         
228   /* An insanely paranoid sequence of argument checks */
229   if (preset_path_ptr == NULL)
230         return ERROR;
231   if (*preset_path_ptr == NULL)
232     return ERROR;
233   if (filename == NULL)
234         return ERROR;
235   if (filepath == NULL)
236         return ERROR;
237   
238   /* Mostly here for looks */
239   preset_path = *preset_path_ptr;
240
241   /* Clear the name space first */
242   memset(preset_path, 0, MAX_PATH_SIZE);
243   
244   /* Now create the string "PATH/FILENAME", where path is either absolute or relative location
245      of the .milk file, and filename is the name of the preset file itself */
246   strcat(
247         strcat(
248                 strncpy(
249                         preset_path, 
250                     filepath, 
251             MAX_PATH_SIZE-1),   
252         "/"), 
253     filename);  
254
255   return SUCCESS;
256 }       
257
258 /* switchPreset: loads the next preset from the directory stream.
259    loadPresetDir() must be called first. This is a
260    sequential load function */
261
262 int switchPreset(switch_mode_t switch_mode, int cut_type) {
263
264   preset_t * new_preset;
265         
266   int switch_index;
267         
268   /* Make sure a preset directory list is in the buffer */
269   if (chrono_order_preset_name_tree == NULL) {
270     if (PRESET_DEBUG) printf("switchPreset: it helps if you open a directory first with a loadPresetDir() call\n");
271     return ERROR;
272   }
273   
274   
275   switch (switch_mode) {
276           
277   case ALPHA_NEXT:
278   /* An index variable that iterates through the directory
279      buffer, doing wrap around when it reaches the end of
280          the buffer */
281   
282   if (preset_index == (preset_name_buffer_size - 1))
283                 switch_index = preset_index = 0;
284   else  
285                 switch_index = ++preset_index;
286   break;
287
288   case ALPHA_PREVIOUS:
289           
290   if (preset_index == 0)
291                 switch_index = preset_index = preset_name_buffer_size - 1;
292   else  
293                 switch_index = --preset_index;
294   break;
295   
296   case RANDOM_NEXT:
297         switch_index = (int) (preset_name_buffer_size*(rand()/(RAND_MAX+1.0)));
298         break;
299   case RESTART_ACTIVE:
300         switch_index = preset_index;
301         break;
302   default:
303         return FAILURE;
304   }
305   
306     
307   /* Finally, load the preset using its actual path */
308   if ((new_preset = load_preset((char*)splay_find(&switch_index, chrono_order_preset_name_tree))) == NULL) {
309         if (PRESET_DEBUG) printf("switchPreset: failed to load preset\n");
310         return ERROR;
311   }
312
313   /* Closes a preset currently loaded, if any */
314   if ((active_preset != NULL) && (active_preset != idle_preset))
315     close_preset(active_preset);
316
317   /* Sets global active_preset pointer */
318   active_preset = new_preset;
319
320  
321   /* Reinitialize the engine variables to sane defaults */
322   reset_engine_vars();
323
324   /* Add any missing initial conditions */
325   load_init_conditions();
326
327   /* Add any missing initial conditions for each wave */
328   load_custom_wave_init_conditions();
329
330 /* Add any missing initial conditions for each shape */
331   load_custom_shape_init_conditions();
332
333   /* Need to evaluate the initial conditions once */
334   evalInitConditions();
335
336  
337   //  evalInitPerFrameEquations();
338   return SUCCESS;
339 }
340
341 /* Loads a specific preset by absolute path */
342 int loadPresetByFile(char * filename) {
343
344   preset_t * new_preset;
345  
346   /* Finally, load the preset using its actual path */
347   if ((new_preset = load_preset(filename)) == NULL) {
348         if (PRESET_DEBUG) printf("loadPresetByFile: failed to load preset!\n");
349         return ERROR;     
350   }
351
352   /* Closes a preset currently loaded, if any */
353   if ((active_preset != NULL) && (active_preset != idle_preset))
354     close_preset(active_preset); 
355
356   /* Sets active preset global pointer */
357   active_preset = new_preset;
358
359   /* Reinitialize engine variables */
360   reset_engine_vars();
361
362  
363   /* Add any missing initial conditions for each wave */
364   load_custom_wave_init_conditions();
365
366  /* Add any missing initial conditions for each wave */
367   load_custom_shape_init_conditions();
368
369   /* Add any missing initial conditions */
370   load_init_conditions();
371   
372   /* Need to do this once for menu */
373   evalInitConditions();
374   //  evalPerFrameInitEquations();
375   return SUCCESS;
376
377 }
378
379 int init_idle_preset() {
380
381   preset_t * preset;
382   int i;
383
384     /* Initialize idle preset struct */
385   if ((preset = (preset_t*)malloc(sizeof(preset_t))) == NULL)
386     return FAILURE;
387
388   
389   strncpy(preset->name, "idlepreset", strlen("idlepreset"));
390
391   /* Initialize equation trees */
392   preset->init_cond_tree = create_splaytree(compare_string, copy_string, free_string);
393   preset->user_param_tree = create_splaytree(compare_string, copy_string, free_string);
394   preset->per_frame_eqn_tree = create_splaytree(compare_int, copy_int, free_int);
395   preset->per_pixel_eqn_tree = create_splaytree(compare_int, copy_int, free_int);
396   preset->per_frame_init_eqn_tree = create_splaytree(compare_string, copy_string, free_string);
397   preset->custom_wave_tree = create_splaytree(compare_int, copy_int, free_int);
398   preset->custom_shape_tree = create_splaytree(compare_int, copy_int, free_int);
399  
400   /* Set file path to dummy name */  
401   strncpy(preset->file_path, "IDLE PRESET", MAX_PATH_SIZE-1);
402   
403   /* Set initial index values */
404   preset->per_pixel_eqn_string_index = 0;
405   preset->per_frame_eqn_string_index = 0;
406   preset->per_frame_init_eqn_string_index = 0;
407   memset(preset->per_pixel_flag, 0, sizeof(int)*NUM_OPS);
408   
409   /* Clear string buffers */
410   memset(preset->per_pixel_eqn_string_buffer, 0, STRING_BUFFER_SIZE);
411   memset(preset->per_frame_eqn_string_buffer, 0, STRING_BUFFER_SIZE);
412   memset(preset->per_frame_init_eqn_string_buffer, 0, STRING_BUFFER_SIZE);
413
414   idle_preset = preset;
415   
416   return SUCCESS;
417 }
418
419 int destroy_idle_preset() {
420
421   return close_preset(idle_preset);
422   
423 }
424
425 /* initPresetLoader: initializes the preset
426    loading library. this should be done before
427    any parsing */
428 int initPresetLoader() {
429
430   /* Initializes the builtin parameter database */
431   init_builtin_param_db();
432
433   /* Initializes the builtin function database */
434   init_builtin_func_db();
435         
436   /* Initializes all infix operators */
437   init_infix_ops();
438
439   /* Set the seed to the current time in seconds */
440   srand(time(NULL));
441
442   /* Initialize the 'idle' preset */
443   init_idle_preset();
444
445  
446
447   reset_engine_vars();
448
449   active_preset = idle_preset;
450   load_init_conditions();
451
452   /* Done */
453   if (PRESET_DEBUG) printf("initPresetLoader: finished\n");
454   return SUCCESS;
455 }
456
457 /* Sort of experimental code here. This switches
458    to a hard coded preset. Useful if preset directory
459    was not properly loaded, or a preset fails to parse */
460
461 void switchToIdlePreset() {
462
463
464   /* Idle Preset already activated */
465   if (active_preset == idle_preset)
466     return;
467
468
469   /* Close active preset */
470   if (active_preset != NULL)
471     close_preset(active_preset);
472
473   /* Sets global active_preset pointer */
474   active_preset = idle_preset;
475
476   /* Reinitialize the engine variables to sane defaults */
477   reset_engine_vars();
478
479   /* Add any missing initial conditions */
480   load_init_conditions();
481
482   /* Need to evaluate the initial conditions once */
483   evalInitConditions();
484
485 }
486
487 /* destroyPresetLoader: closes the preset
488    loading library. This should be done when 
489    projectM does cleanup */
490
491 int destroyPresetLoader() {
492   
493   if ((active_preset != NULL) && (active_preset != idle_preset)) {      
494         close_preset(active_preset);      
495   }     
496
497   active_preset = NULL;
498   
499   destroy_idle_preset();
500   destroy_builtin_param_db();
501   destroy_builtin_func_db();
502   destroy_infix_ops();
503
504   return SUCCESS;
505
506 }
507
508 /* load_preset_file: private function that loads a specific preset denoted
509    by the given pathname */
510 int load_preset_file(char * pathname, preset_t * preset) { 
511   FILE * fs;
512   int retval;
513
514   if (pathname == NULL)
515           return FAILURE;
516   if (preset == NULL)
517           return FAILURE;
518   
519   /* Open the file corresponding to pathname */
520   if ((fs = utf8_fopen(pathname, "r")) == 0) {
521     if (PRESET_DEBUG) printf("load_preset_file: loading of file %s failed!\n", pathname);
522     return ERROR;       
523   }
524
525   if (PRESET_DEBUG) printf("load_preset_file: file stream \"%s\" opened successfully\n", pathname);
526
527   /* Parse any comments */
528   if (parse_top_comment(fs) < 0) {
529     if (PRESET_DEBUG) printf("load_preset_file: no left bracket found...\n");
530     fclose(fs);
531     return FAILURE;
532   }
533   
534   /* Parse the preset name and a left bracket */
535   if (parse_preset_name(fs, preset->name) < 0) {
536     if (PRESET_DEBUG) printf("load_preset_file: loading of preset name in file \"%s\" failed\n", pathname);
537     fclose(fs);
538     return ERROR;
539   }
540   
541   if (PRESET_DEBUG) printf("load_preset_file: preset \"%s\" parsed\n", preset->name);
542
543   /* Parse each line until end of file */
544   if (PRESET_DEBUG) printf("load_preset_file: beginning line parsing...\n");
545   while ((retval = parse_line(fs, preset)) != EOF) {
546     if (retval == PARSE_ERROR) {
547       if (PRESET_DEBUG > 1) printf("load_preset_file: parse error in file \"%s\"\n", pathname);
548     }
549   }
550   
551   if (PRESET_DEBUG) printf("load_preset_file: finished line parsing successfully\n"); 
552
553   /* Now the preset has been loaded.
554      Evaluation calls can be made at appropiate
555      times in the frame loop */
556   
557   fclose(fs);
558    
559   if (PRESET_DEBUG) printf("load_preset_file: file \"%s\" closed, preset ready\n", pathname);
560   return SUCCESS;
561   
562 }
563
564 void evalInitConditions() {
565   splay_traverse(eval_init_cond, active_preset->init_cond_tree);
566   splay_traverse(eval_init_cond, active_preset->per_frame_init_eqn_tree);
567 }
568
569 void evalPerFrameEquations() {
570   splay_traverse(eval_per_frame_eqn, active_preset->per_frame_eqn_tree);
571 }
572
573 void evalPerFrameInitEquations() {
574   //printf("evalPerFrameInitEquations: per frame init unimplemented!\n");
575   //  splay_traverse(eval_per_frame_eqn, active_preset->per_frame_init_eqn_tree);
576 }       
577
578 /* Returns nonzero if string 'name' contains .milk or
579    (the better) .prjm extension. Not a very strong function currently */
580 int is_valid_extension(char * name) {
581
582         if (PRESET_DEBUG > 1) {
583                 printf("is_valid_extension: scanning string \"%s\"...", name);
584                 fflush(stdout);
585         }
586
587         if (strstr(name, MILKDROP_FILE_EXTENSION)) {
588                         if (PRESET_DEBUG > 1) printf("\".milk\" extension found in string [true]\n");
589                         return TRUE;
590         }       
591         
592         if (strstr(name, PROJECTM_FILE_EXTENSION)) {
593                     if (PRESET_DEBUG > 1) printf("\".prjm\" extension found in string [true]\n");
594                         return TRUE;
595         }
596          
597         if (PRESET_DEBUG > 1) printf("no valid extension found [false]\n");
598         return FALSE;
599 }
600
601 /* Private function to close a preset file */
602 int close_preset(preset_t * preset) {
603
604   if (preset == NULL)
605     return FAILURE;
606
607
608   splay_traverse(free_init_cond, preset->init_cond_tree);
609   destroy_splaytree(preset->init_cond_tree);
610   
611   splay_traverse(free_init_cond, preset->per_frame_init_eqn_tree);
612   destroy_splaytree(preset->per_frame_init_eqn_tree);
613   
614   splay_traverse(free_per_pixel_eqn, preset->per_pixel_eqn_tree);
615   destroy_splaytree(preset->per_pixel_eqn_tree);
616   
617   splay_traverse(free_per_frame_eqn, preset->per_frame_eqn_tree);
618   destroy_splaytree(preset->per_frame_eqn_tree);
619   
620   splay_traverse(free_param, preset->user_param_tree);
621   destroy_splaytree(preset->user_param_tree);
622   
623   splay_traverse(free_custom_wave, preset->custom_wave_tree);
624   destroy_splaytree(preset->custom_wave_tree);
625
626   splay_traverse(free_custom_shape, preset->custom_shape_tree);
627   destroy_splaytree(preset->custom_shape_tree);
628
629   free(preset); 
630   
631   return SUCCESS;
632
633 }
634
635 void reloadPerPixel(char *s, preset_t * preset) {
636   
637   FILE * fs;
638   int slen;
639   char c;
640   int i;
641
642   if (s == NULL)
643     return;
644
645   if (preset == NULL)
646     return;
647
648   /* Clear previous per pixel equations */
649   splay_traverse(free_per_pixel_eqn, preset->per_pixel_eqn_tree);
650   destroy_splaytree(preset->per_pixel_eqn_tree);
651   preset->per_pixel_eqn_tree = create_splaytree(compare_int, copy_int, free_int);
652
653   /* Convert string to a stream */
654   fs = fmemopen (s, strlen(s), "r");
655
656   while ((c = fgetc(fs)) != EOF) {
657     ungetc(c, fs);
658     parse_per_pixel_eqn(fs, preset);
659   }
660
661   fclose(fs);
662
663   /* Clear string space */
664   memset(preset->per_pixel_eqn_string_buffer, 0, STRING_BUFFER_SIZE);
665
666   /* Compute length of string */
667   slen = strlen(s);
668
669   /* Copy new string into buffer */
670   strncpy(preset->per_pixel_eqn_string_buffer, s, slen);
671
672   /* Yet again no bounds checking */
673   preset->per_pixel_eqn_string_index = slen;
674
675   /* Finished */
676  
677   return;
678 }
679
680 /* Obviously unwritten */
681 void reloadPerFrameInit(char *s, preset_t * preset) {
682
683 }
684
685 void reloadPerFrame(char * s, preset_t * preset) {
686
687   FILE * fs;
688   int slen;
689   char c;
690   int eqn_count = 1;
691   per_frame_eqn_t * per_frame;
692
693   if (s == NULL)
694     return;
695
696   if (preset == NULL)
697     return;
698
699   /* Clear previous per frame equations */
700   splay_traverse(free_per_frame_eqn, preset->per_frame_eqn_tree);
701   destroy_splaytree(preset->per_frame_eqn_tree);
702   preset->per_frame_eqn_tree = create_splaytree(compare_int, copy_int, free_int);
703
704   /* Convert string to a stream */
705   fs = fmemopen (s, strlen(s), "r");
706
707   while ((c = fgetc(fs)) != EOF) {
708     ungetc(c, fs);
709     if ((per_frame = parse_per_frame_eqn(fs, eqn_count, preset)) != NULL) {
710       splay_insert(per_frame, &eqn_count, preset->per_frame_eqn_tree);
711       eqn_count++;
712     }
713   }
714
715   fclose(fs);
716
717   /* Clear string space */
718   memset(preset->per_frame_eqn_string_buffer, 0, STRING_BUFFER_SIZE);
719
720   /* Compute length of string */
721   slen = strlen(s);
722
723   /* Copy new string into buffer */
724   strncpy(preset->per_frame_eqn_string_buffer, s, slen);
725
726   /* Yet again no bounds checking */
727   preset->per_frame_eqn_string_index = slen;
728
729   /* Finished */
730   printf("reloadPerFrame: %d eqns parsed succesfully\n", eqn_count-1);
731   return;
732
733 }
734
735 preset_t * load_preset(char * pathname) {
736
737   preset_t * preset;
738   int i;
739
740   /* Initialize preset struct */
741   if ((preset = (preset_t*)malloc(sizeof(preset_t))) == NULL)
742     return NULL;
743    
744   /* Initialize equation trees */
745   preset->init_cond_tree = create_splaytree(compare_string, copy_string, free_string);
746   preset->user_param_tree = create_splaytree(compare_string, copy_string, free_string);
747   preset->per_frame_eqn_tree = create_splaytree(compare_int, copy_int, free_int);
748   preset->per_pixel_eqn_tree = create_splaytree(compare_int, copy_int, free_int);
749   preset->per_frame_init_eqn_tree = create_splaytree(compare_string, copy_string, free_string);
750   preset->custom_wave_tree = create_splaytree(compare_int, copy_int, free_int);
751   preset->custom_shape_tree = create_splaytree(compare_int, copy_int, free_int);
752
753   memset(preset->per_pixel_flag, 0, sizeof(int)*NUM_OPS);
754
755   /* Copy file path */  
756   strncpy(preset->file_path, pathname, MAX_PATH_SIZE-1);
757   
758   /* Set initial index values */
759   preset->per_pixel_eqn_string_index = 0;
760   preset->per_frame_eqn_string_index = 0;
761   preset->per_frame_init_eqn_string_index = 0;
762   
763   
764   /* Clear string buffers */
765   memset(preset->per_pixel_eqn_string_buffer, 0, STRING_BUFFER_SIZE);
766   memset(preset->per_frame_eqn_string_buffer, 0, STRING_BUFFER_SIZE);
767   memset(preset->per_frame_init_eqn_string_buffer, 0, STRING_BUFFER_SIZE);
768   
769   
770   if (load_preset_file(pathname, preset) < 0) {
771         if (PRESET_DEBUG) printf("load_preset: failed to load file \"%s\"\n", pathname);
772         close_preset(preset);
773         return NULL;
774   }
775
776   /* It's kind of ugly to reset these values here. Should definitely be placed in the parser somewhere */
777   per_frame_eqn_count = 0;
778   per_frame_init_eqn_count = 0;
779
780   /* Finished, return new preset */
781   return preset;
782 }
783
784 void savePreset(char * filename) {
785
786   FILE * fs;
787
788   if (filename == NULL)
789     return;
790   
791   /* Open the file corresponding to pathname */
792   if ((fs = utf8_fopen(filename, "w+")) == 0) {
793     if (PRESET_DEBUG) printf("savePreset: failed to create filename \"%s\"!\n", filename);
794     return;     
795   }
796
797   write_stream = fs;
798
799   if (write_preset_name(fs) < 0) {
800     write_stream = NULL;
801     fclose(fs);
802     return;
803   }
804
805   if (write_init_conditions(fs) < 0) {
806     write_stream = NULL;
807     fclose(fs);
808     return;
809   }
810
811   if (write_per_frame_init_equations(fs) < 0) {
812     write_stream = NULL;
813     fclose(fs);
814     return;
815   }
816
817   if (write_per_frame_equations(fs) < 0) {
818     write_stream = NULL;
819     fclose(fs);
820     return;
821   }
822
823   if (write_per_pixel_equations(fs) < 0) {
824     write_stream = NULL;
825     fclose(fs);
826     return;
827   }
828  
829   write_stream = NULL;
830   fclose(fs);
831
832 }
833
834 int write_preset_name(FILE * fs) {
835
836   char s[256];
837   int len;
838
839   memset(s, 0, 256);
840
841   if (fs == NULL)
842     return FAILURE;
843
844   /* Format the preset name in a string */
845   sprintf(s, "[%s]\n", active_preset->name);
846
847   len = strlen(s);
848
849   /* Write preset name to file stream */
850   if (fwrite(s, 1, len, fs) != len)
851     return FAILURE;
852
853   return SUCCESS;
854
855 }
856
857 int write_init_conditions(FILE * fs) {
858
859   if (fs == NULL)
860     return FAILURE;
861   if (active_preset == NULL)
862     return FAILURE;
863
864
865   splay_traverse(write_init, active_preset->init_cond_tree);
866   
867   return SUCCESS;
868 }
869
870 void write_init(init_cond_t * init_cond) {
871
872   char s[512];
873   int len;
874
875   if (write_stream == NULL)
876     return;
877
878   memset(s, 0, 512);
879
880   if (init_cond->param->type == P_TYPE_BOOL)
881     sprintf(s, "%s=%d\n", init_cond->param->name, init_cond->init_val.bool_val);
882
883   else if (init_cond->param->type == P_TYPE_INT)    
884     sprintf(s, "%s=%d\n", init_cond->param->name, init_cond->init_val.int_val);
885
886   else if (init_cond->param->type == P_TYPE_DOUBLE)
887   {
888     lldiv_t div = lldiv( init_cond->init_val.double_val * 1000000,1000000 );
889     sprintf(s, "%s="I64Fd".%06u\n", init_cond->param->name, div.quot,
890                     (unsigned int) div.rem );
891   }
892
893   else { printf("write_init: unknown parameter type!\n"); return; }
894
895   len = strlen(s);
896
897   if ((fwrite(s, 1, len, write_stream)) != len)
898     printf("write_init: failed writing to file stream! Out of disk space?\n");
899
900 }
901
902
903 int write_per_frame_init_equations(FILE * fs) {
904
905   int len;
906
907   if (fs == NULL)
908     return FAILURE;
909   if (active_preset == NULL)
910     return FAILURE;
911   
912   len = strlen(active_preset->per_frame_init_eqn_string_buffer);
913
914   if (fwrite(active_preset->per_frame_init_eqn_string_buffer, 1, len, fs) != len)
915     return FAILURE;
916
917   return SUCCESS;
918 }
919
920
921 int write_per_frame_equations(FILE * fs) {
922
923   int len;
924
925   if (fs == NULL)
926     return FAILURE;
927   if (active_preset == NULL)
928     return FAILURE;
929
930   len = strlen(active_preset->per_frame_eqn_string_buffer);
931
932   if (fwrite(active_preset->per_frame_eqn_string_buffer, 1, len, fs) != len)
933     return FAILURE;
934
935   return SUCCESS;
936 }
937
938
939 int write_per_pixel_equations(FILE * fs) {
940
941   int len;
942
943   if (fs == NULL)
944     return FAILURE;
945   if (active_preset == NULL)
946     return FAILURE;
947
948   len = strlen(active_preset->per_pixel_eqn_string_buffer);
949
950   if (fwrite(active_preset->per_pixel_eqn_string_buffer, 1, len, fs) != len)
951     return FAILURE;
952
953   return SUCCESS;
954 }
955
956
957 void load_init_conditions() {
958
959   splay_traverse(load_init_cond, builtin_param_tree);
960
961  
962 }
963
964 void load_init_cond(param_t * param) {
965
966   init_cond_t * init_cond;
967   value_t init_val;
968
969   /* Don't count read only parameters as initial conditions */
970   if (param->flags & P_FLAG_READONLY)
971     return;
972
973   /* If initial condition was not defined by the preset file, force a default one
974      with the following code */
975   if ((init_cond = splay_find(param->name, active_preset->init_cond_tree)) == NULL) {
976     
977     /* Make sure initial condition does not exist in the set of per frame initial equations */
978     if ((init_cond = splay_find(param->name, active_preset->per_frame_init_eqn_tree)) != NULL)
979       return;
980     
981     if (param->type == P_TYPE_BOOL)
982       init_val.bool_val = 0;
983     
984     else if (param->type == P_TYPE_INT)
985       init_val.int_val = *(int*)param->engine_val;
986
987     else if (param->type == P_TYPE_DOUBLE)
988       init_val.double_val = *(double*)param->engine_val;
989
990     //printf("%s\n", param->name);
991     /* Create new initial condition */
992     if ((init_cond = new_init_cond(param, init_val)) == NULL)
993       return;
994     
995     /* Insert the initial condition into this presets tree */
996     if (splay_insert(init_cond, init_cond->param->name, active_preset->init_cond_tree) < 0) {
997       free_init_cond(init_cond);
998       return;
999     }
1000     
1001   }
1002  
1003 }
1004
1005 void load_custom_wave_init_conditions() {
1006
1007   splay_traverse(load_custom_wave_init, active_preset->custom_wave_tree);
1008
1009 }
1010
1011 void load_custom_wave_init(custom_wave_t * custom_wave) {
1012
1013   load_unspecified_init_conds(custom_wave);
1014
1015 }
1016
1017
1018 void load_custom_shape_init_conditions() {
1019
1020   splay_traverse(load_custom_shape_init, active_preset->custom_shape_tree);
1021
1022 }
1023
1024 void load_custom_shape_init(custom_shape_t * custom_shape) {
1025  
1026   load_unspecified_init_conds_shape(custom_shape);
1027  
1028 }