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