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