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