]> git.sesse.net Git - vlc/blob - modules/visualization/galaktos/preset.c
Test pointers against NULL instead of 0.
[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_common.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
389     /* Initialize idle preset struct */
390   if ((preset = (preset_t*)malloc(sizeof(preset_t))) == NULL)
391     return FAILURE;
392
393   
394   strncpy(preset->name, "idlepreset", strlen("idlepreset"));
395
396   /* Initialize equation trees */
397   preset->init_cond_tree = create_splaytree(compare_string, copy_string, free_string);
398   preset->user_param_tree = create_splaytree(compare_string, copy_string, free_string);
399   preset->per_frame_eqn_tree = create_splaytree(compare_int, copy_int, free_int);
400   preset->per_pixel_eqn_tree = create_splaytree(compare_int, copy_int, free_int);
401   preset->per_frame_init_eqn_tree = create_splaytree(compare_string, copy_string, free_string);
402   preset->custom_wave_tree = create_splaytree(compare_int, copy_int, free_int);
403   preset->custom_shape_tree = create_splaytree(compare_int, copy_int, free_int);
404  
405   /* Set file path to dummy name */  
406   strncpy(preset->file_path, "IDLE PRESET", MAX_PATH_SIZE-1);
407   
408   /* Set initial index values */
409   preset->per_pixel_eqn_string_index = 0;
410   preset->per_frame_eqn_string_index = 0;
411   preset->per_frame_init_eqn_string_index = 0;
412   memset(preset->per_pixel_flag, 0, sizeof(int)*NUM_OPS);
413   
414   /* Clear string buffers */
415   memset(preset->per_pixel_eqn_string_buffer, 0, STRING_BUFFER_SIZE);
416   memset(preset->per_frame_eqn_string_buffer, 0, STRING_BUFFER_SIZE);
417   memset(preset->per_frame_init_eqn_string_buffer, 0, STRING_BUFFER_SIZE);
418
419   idle_preset = preset;
420   
421   return SUCCESS;
422 }
423
424 int destroy_idle_preset() {
425
426   return close_preset(idle_preset);
427   
428 }
429
430 /* initPresetLoader: initializes the preset
431    loading library. this should be done before
432    any parsing */
433 int initPresetLoader() {
434
435   /* Initializes the builtin parameter database */
436   init_builtin_param_db();
437
438   /* Initializes the builtin function database */
439   init_builtin_func_db();
440         
441   /* Initializes all infix operators */
442   init_infix_ops();
443
444   /* Set the seed to the current time in seconds */
445   srand(time(NULL));
446
447   /* Initialize the 'idle' preset */
448   init_idle_preset();
449
450  
451
452   reset_engine_vars();
453
454   active_preset = idle_preset;
455   load_init_conditions();
456
457   /* Done */
458   if (PRESET_DEBUG) printf("initPresetLoader: finished\n");
459   return SUCCESS;
460 }
461
462 /* Sort of experimental code here. This switches
463    to a hard coded preset. Useful if preset directory
464    was not properly loaded, or a preset fails to parse */
465
466 void switchToIdlePreset() {
467
468
469   /* Idle Preset already activated */
470   if (active_preset == idle_preset)
471     return;
472
473
474   /* Close active preset */
475   if (active_preset != NULL)
476     close_preset(active_preset);
477
478   /* Sets global active_preset pointer */
479   active_preset = idle_preset;
480
481   /* Reinitialize the engine variables to sane defaults */
482   reset_engine_vars();
483
484   /* Add any missing initial conditions */
485   load_init_conditions();
486
487   /* Need to evaluate the initial conditions once */
488   evalInitConditions();
489
490 }
491
492 /* destroyPresetLoader: closes the preset
493    loading library. This should be done when 
494    projectM does cleanup */
495
496 int destroyPresetLoader() {
497   
498   if ((active_preset != NULL) && (active_preset != idle_preset)) {      
499         close_preset(active_preset);      
500   }     
501
502   active_preset = NULL;
503   
504   destroy_idle_preset();
505   destroy_builtin_param_db();
506   destroy_builtin_func_db();
507   destroy_infix_ops();
508
509   return SUCCESS;
510
511 }
512
513 /* load_preset_file: private function that loads a specific preset denoted
514    by the given pathname */
515 int load_preset_file(char * pathname, preset_t * preset) { 
516   FILE * fs;
517   int retval;
518
519   if (pathname == NULL)
520           return FAILURE;
521   if (preset == NULL)
522           return FAILURE;
523   
524   /* Open the file corresponding to pathname */
525   if ((fs = utf8_fopen(pathname, "r")) == NULL) {
526     if (PRESET_DEBUG) printf("load_preset_file: loading of file %s failed!\n", pathname);
527     return ERROR;       
528   }
529
530   if (PRESET_DEBUG) printf("load_preset_file: file stream \"%s\" opened successfully\n", pathname);
531
532   /* Parse any comments */
533   if (parse_top_comment(fs) < 0) {
534     if (PRESET_DEBUG) printf("load_preset_file: no left bracket found...\n");
535     fclose(fs);
536     return FAILURE;
537   }
538   
539   /* Parse the preset name and a left bracket */
540   if (parse_preset_name(fs, preset->name) < 0) {
541     if (PRESET_DEBUG) printf("load_preset_file: loading of preset name in file \"%s\" failed\n", pathname);
542     fclose(fs);
543     return ERROR;
544   }
545   
546   if (PRESET_DEBUG) printf("load_preset_file: preset \"%s\" parsed\n", preset->name);
547
548   /* Parse each line until end of file */
549   if (PRESET_DEBUG) printf("load_preset_file: beginning line parsing...\n");
550   while ((retval = parse_line(fs, preset)) != EOF) {
551     if (retval == PARSE_ERROR) {
552       if (PRESET_DEBUG > 1) printf("load_preset_file: parse error in file \"%s\"\n", pathname);
553     }
554   }
555   
556   if (PRESET_DEBUG) printf("load_preset_file: finished line parsing successfully\n"); 
557
558   /* Now the preset has been loaded.
559      Evaluation calls can be made at appropiate
560      times in the frame loop */
561   
562   fclose(fs);
563    
564   if (PRESET_DEBUG) printf("load_preset_file: file \"%s\" closed, preset ready\n", pathname);
565   return SUCCESS;
566   
567 }
568
569 void evalInitConditions() {
570   splay_traverse(eval_init_cond, active_preset->init_cond_tree);
571   splay_traverse(eval_init_cond, active_preset->per_frame_init_eqn_tree);
572 }
573
574 void evalPerFrameEquations() {
575   splay_traverse(eval_per_frame_eqn, active_preset->per_frame_eqn_tree);
576 }
577
578 void evalPerFrameInitEquations() {
579   //printf("evalPerFrameInitEquations: per frame init unimplemented!\n");
580   //  splay_traverse(eval_per_frame_eqn, active_preset->per_frame_init_eqn_tree);
581 }       
582
583 /* Returns nonzero if string 'name' contains .milk or
584    (the better) .prjm extension. Not a very strong function currently */
585 int is_valid_extension(char * name) {
586
587         if (PRESET_DEBUG > 1) {
588                 printf("is_valid_extension: scanning string \"%s\"...", name);
589                 fflush(stdout);
590         }
591
592         if (strstr(name, MILKDROP_FILE_EXTENSION)) {
593                         if (PRESET_DEBUG > 1) printf("\".milk\" extension found in string [true]\n");
594                         return TRUE;
595         }       
596         
597         if (strstr(name, PROJECTM_FILE_EXTENSION)) {
598                     if (PRESET_DEBUG > 1) printf("\".prjm\" extension found in string [true]\n");
599                         return TRUE;
600         }
601          
602         if (PRESET_DEBUG > 1) printf("no valid extension found [false]\n");
603         return FALSE;
604 }
605
606 /* Private function to close a preset file */
607 int close_preset(preset_t * preset) {
608
609   if (preset == NULL)
610     return FAILURE;
611
612
613   splay_traverse(free_init_cond, preset->init_cond_tree);
614   destroy_splaytree(preset->init_cond_tree);
615   
616   splay_traverse(free_init_cond, preset->per_frame_init_eqn_tree);
617   destroy_splaytree(preset->per_frame_init_eqn_tree);
618   
619   splay_traverse(free_per_pixel_eqn, preset->per_pixel_eqn_tree);
620   destroy_splaytree(preset->per_pixel_eqn_tree);
621   
622   splay_traverse(free_per_frame_eqn, preset->per_frame_eqn_tree);
623   destroy_splaytree(preset->per_frame_eqn_tree);
624   
625   splay_traverse(free_param, preset->user_param_tree);
626   destroy_splaytree(preset->user_param_tree);
627   
628   splay_traverse(free_custom_wave, preset->custom_wave_tree);
629   destroy_splaytree(preset->custom_wave_tree);
630
631   splay_traverse(free_custom_shape, preset->custom_shape_tree);
632   destroy_splaytree(preset->custom_shape_tree);
633
634   free(preset); 
635   
636   return SUCCESS;
637
638 }
639
640 void reloadPerPixel(char *s, preset_t * preset) {
641   
642   FILE * fs;
643   int slen;
644   char c;
645   int i;
646
647   if (s == NULL)
648     return;
649
650   if (preset == NULL)
651     return;
652
653   /* Clear previous per pixel equations */
654   splay_traverse(free_per_pixel_eqn, preset->per_pixel_eqn_tree);
655   destroy_splaytree(preset->per_pixel_eqn_tree);
656   preset->per_pixel_eqn_tree = create_splaytree(compare_int, copy_int, free_int);
657
658   /* Convert string to a stream */
659   fs = fmemopen (s, strlen(s), "r");
660
661   while ((c = fgetc(fs)) != EOF) {
662     ungetc(c, fs);
663     parse_per_pixel_eqn(fs, preset);
664   }
665
666   fclose(fs);
667
668   /* Clear string space */
669   memset(preset->per_pixel_eqn_string_buffer, 0, STRING_BUFFER_SIZE);
670
671   /* Compute length of string */
672   slen = strlen(s);
673
674   /* Copy new string into buffer */
675   strncpy(preset->per_pixel_eqn_string_buffer, s, slen);
676
677   /* Yet again no bounds checking */
678   preset->per_pixel_eqn_string_index = slen;
679
680   /* Finished */
681  
682   return;
683 }
684
685 /* Obviously unwritten */
686 void reloadPerFrameInit(char *s, preset_t * preset) {
687
688 }
689
690 void reloadPerFrame(char * s, preset_t * preset) {
691
692   FILE * fs;
693   int slen;
694   char c;
695   int eqn_count = 1;
696   per_frame_eqn_t * per_frame;
697
698   if (s == NULL)
699     return;
700
701   if (preset == NULL)
702     return;
703
704   /* Clear previous per frame equations */
705   splay_traverse(free_per_frame_eqn, preset->per_frame_eqn_tree);
706   destroy_splaytree(preset->per_frame_eqn_tree);
707   preset->per_frame_eqn_tree = create_splaytree(compare_int, copy_int, free_int);
708
709   /* Convert string to a stream */
710   fs = fmemopen (s, strlen(s), "r");
711
712   while ((c = fgetc(fs)) != EOF) {
713     ungetc(c, fs);
714     if ((per_frame = parse_per_frame_eqn(fs, eqn_count, preset)) != NULL) {
715       splay_insert(per_frame, &eqn_count, preset->per_frame_eqn_tree);
716       eqn_count++;
717     }
718   }
719
720   fclose(fs);
721
722   /* Clear string space */
723   memset(preset->per_frame_eqn_string_buffer, 0, STRING_BUFFER_SIZE);
724
725   /* Compute length of string */
726   slen = strlen(s);
727
728   /* Copy new string into buffer */
729   strncpy(preset->per_frame_eqn_string_buffer, s, slen);
730
731   /* Yet again no bounds checking */
732   preset->per_frame_eqn_string_index = slen;
733
734   /* Finished */
735   printf("reloadPerFrame: %d eqns parsed succesfully\n", eqn_count-1);
736   return;
737
738 }
739
740 preset_t * load_preset(char * pathname) {
741
742   preset_t * preset;
743
744   /* Initialize preset struct */
745   if ((preset = (preset_t*)malloc(sizeof(preset_t))) == NULL)
746     return NULL;
747    
748   /* Initialize equation trees */
749   preset->init_cond_tree = create_splaytree(compare_string, copy_string, free_string);
750   preset->user_param_tree = create_splaytree(compare_string, copy_string, free_string);
751   preset->per_frame_eqn_tree = create_splaytree(compare_int, copy_int, free_int);
752   preset->per_pixel_eqn_tree = create_splaytree(compare_int, copy_int, free_int);
753   preset->per_frame_init_eqn_tree = create_splaytree(compare_string, copy_string, free_string);
754   preset->custom_wave_tree = create_splaytree(compare_int, copy_int, free_int);
755   preset->custom_shape_tree = create_splaytree(compare_int, copy_int, free_int);
756
757   memset(preset->per_pixel_flag, 0, sizeof(int)*NUM_OPS);
758
759   /* Copy file path */  
760   strncpy(preset->file_path, pathname, MAX_PATH_SIZE-1);
761   
762   /* Set initial index values */
763   preset->per_pixel_eqn_string_index = 0;
764   preset->per_frame_eqn_string_index = 0;
765   preset->per_frame_init_eqn_string_index = 0;
766   
767   
768   /* Clear string buffers */
769   memset(preset->per_pixel_eqn_string_buffer, 0, STRING_BUFFER_SIZE);
770   memset(preset->per_frame_eqn_string_buffer, 0, STRING_BUFFER_SIZE);
771   memset(preset->per_frame_init_eqn_string_buffer, 0, STRING_BUFFER_SIZE);
772   
773   
774   if (load_preset_file(pathname, preset) < 0) {
775         if (PRESET_DEBUG) printf("load_preset: failed to load file \"%s\"\n", pathname);
776         close_preset(preset);
777         return NULL;
778   }
779
780   /* It's kind of ugly to reset these values here. Should definitely be placed in the parser somewhere */
781   per_frame_eqn_count = 0;
782   per_frame_init_eqn_count = 0;
783
784   /* Finished, return new preset */
785   return preset;
786 }
787
788 void savePreset(char * filename) {
789
790   FILE * fs;
791
792   if (filename == NULL)
793     return;
794   
795   /* Open the file corresponding to pathname */
796   if ((fs = utf8_fopen(filename, "w+")) == NULL) {
797     if (PRESET_DEBUG) printf("savePreset: failed to create filename \"%s\"!\n", filename);
798     return;     
799   }
800
801   write_stream = fs;
802
803   if (write_preset_name(fs) < 0) {
804     write_stream = NULL;
805     fclose(fs);
806     return;
807   }
808
809   if (write_init_conditions(fs) < 0) {
810     write_stream = NULL;
811     fclose(fs);
812     return;
813   }
814
815   if (write_per_frame_init_equations(fs) < 0) {
816     write_stream = NULL;
817     fclose(fs);
818     return;
819   }
820
821   if (write_per_frame_equations(fs) < 0) {
822     write_stream = NULL;
823     fclose(fs);
824     return;
825   }
826
827   if (write_per_pixel_equations(fs) < 0) {
828     write_stream = NULL;
829     fclose(fs);
830     return;
831   }
832  
833   write_stream = NULL;
834   fclose(fs);
835
836 }
837
838 int write_preset_name(FILE * fs) {
839
840   char s[256];
841   int len;
842
843   memset(s, 0, 256);
844
845   if (fs == NULL)
846     return FAILURE;
847
848   /* Format the preset name in a string */
849   sprintf(s, "[%s]\n", active_preset->name);
850
851   len = strlen(s);
852
853   /* Write preset name to file stream */
854   if (fwrite(s, 1, len, fs) != len)
855     return FAILURE;
856
857   return SUCCESS;
858
859 }
860
861 int write_init_conditions(FILE * fs) {
862
863   if (fs == NULL)
864     return FAILURE;
865   if (active_preset == NULL)
866     return FAILURE;
867
868
869   splay_traverse(write_init, active_preset->init_cond_tree);
870   
871   return SUCCESS;
872 }
873
874 void write_init(init_cond_t * init_cond) {
875
876   char s[512];
877   int len;
878
879   if (write_stream == NULL)
880     return;
881
882   memset(s, 0, 512);
883
884   if (init_cond->param->type == P_TYPE_BOOL)
885     sprintf(s, "%s=%d\n", init_cond->param->name, init_cond->init_val.bool_val);
886
887   else if (init_cond->param->type == P_TYPE_INT)    
888     sprintf(s, "%s=%d\n", init_cond->param->name, init_cond->init_val.int_val);
889
890   else if (init_cond->param->type == P_TYPE_DOUBLE)
891   {
892     lldiv_t div = lldiv( init_cond->init_val.double_val * 1000000,1000000 );
893     sprintf(s, "%s=%"PRId64".%06u\n", init_cond->param->name, div.quot,
894                     (unsigned int) div.rem );
895   }
896
897   else { printf("write_init: unknown parameter type!\n"); return; }
898
899   len = strlen(s);
900
901   if ((fwrite(s, 1, len, write_stream)) != len)
902     printf("write_init: failed writing to file stream! Out of disk space?\n");
903
904 }
905
906
907 int write_per_frame_init_equations(FILE * fs) {
908
909   int len;
910
911   if (fs == NULL)
912     return FAILURE;
913   if (active_preset == NULL)
914     return FAILURE;
915   
916   len = strlen(active_preset->per_frame_init_eqn_string_buffer);
917
918   if (fwrite(active_preset->per_frame_init_eqn_string_buffer, 1, len, fs) != len)
919     return FAILURE;
920
921   return SUCCESS;
922 }
923
924
925 int write_per_frame_equations(FILE * fs) {
926
927   int len;
928
929   if (fs == NULL)
930     return FAILURE;
931   if (active_preset == NULL)
932     return FAILURE;
933
934   len = strlen(active_preset->per_frame_eqn_string_buffer);
935
936   if (fwrite(active_preset->per_frame_eqn_string_buffer, 1, len, fs) != len)
937     return FAILURE;
938
939   return SUCCESS;
940 }
941
942
943 int write_per_pixel_equations(FILE * fs) {
944
945   int len;
946
947   if (fs == NULL)
948     return FAILURE;
949   if (active_preset == NULL)
950     return FAILURE;
951
952   len = strlen(active_preset->per_pixel_eqn_string_buffer);
953
954   if (fwrite(active_preset->per_pixel_eqn_string_buffer, 1, len, fs) != len)
955     return FAILURE;
956
957   return SUCCESS;
958 }
959
960
961 void load_init_conditions() {
962
963   splay_traverse(load_init_cond, builtin_param_tree);
964
965  
966 }
967
968 void load_init_cond(param_t * param) {
969
970   init_cond_t * init_cond;
971   value_t init_val;
972
973   /* Don't count read only parameters as initial conditions */
974   if (param->flags & P_FLAG_READONLY)
975     return;
976
977   /* If initial condition was not defined by the preset file, force a default one
978      with the following code */
979   if ((init_cond = splay_find(param->name, active_preset->init_cond_tree)) == NULL) {
980     
981     /* Make sure initial condition does not exist in the set of per frame initial equations */
982     if ((init_cond = splay_find(param->name, active_preset->per_frame_init_eqn_tree)) != NULL)
983       return;
984     
985     if (param->type == P_TYPE_BOOL)
986       init_val.bool_val = 0;
987     
988     else if (param->type == P_TYPE_INT)
989       init_val.int_val = *(int*)param->engine_val;
990
991     else if (param->type == P_TYPE_DOUBLE)
992       init_val.double_val = *(double*)param->engine_val;
993
994     //printf("%s\n", param->name);
995     /* Create new initial condition */
996     if ((init_cond = new_init_cond(param, init_val)) == NULL)
997       return;
998     
999     /* Insert the initial condition into this presets tree */
1000     if (splay_insert(init_cond, init_cond->param->name, active_preset->init_cond_tree) < 0) {
1001       free_init_cond(init_cond);
1002       return;
1003     }
1004     
1005   }
1006  
1007 }
1008
1009 void load_custom_wave_init_conditions() {
1010
1011   splay_traverse(load_custom_wave_init, active_preset->custom_wave_tree);
1012
1013 }
1014
1015 void load_custom_wave_init(custom_wave_t * custom_wave) {
1016
1017   load_unspecified_init_conds(custom_wave);
1018
1019 }
1020
1021
1022 void load_custom_shape_init_conditions() {
1023
1024   splay_traverse(load_custom_shape_init, active_preset->custom_shape_tree);
1025
1026 }
1027
1028 void load_custom_shape_init(custom_shape_t * custom_shape) {
1029  
1030   load_unspecified_init_conds_shape(custom_shape);
1031  
1032 }