]> git.sesse.net Git - vlc/commitdiff
* all: first implementation of a MilkDrop-compatible visualization plugin,
authorCyril Deguet <asmax@videolan.org>
Sat, 17 Jul 2004 13:55:48 +0000 (13:55 +0000)
committerCyril Deguet <asmax@videolan.org>
Sat, 17 Jul 2004 13:55:48 +0000 (13:55 +0000)
    based on ProjectM (xmms-projectm.sourceforge.net), without the
    dependency on SDL 1.3. At the moment it only works on X11 with GLX 1.3,
    I didn't manage to have it working with the 1.2 API :(
    SGI Pbuffers are not used yet, I didn't manage to have them working
    well either :(
    Milkdrop presets are searched in /etc/projectM/presets (guess why ;)
    With projectM presets, colours look a bit "flashy", I wonder if it
    is normal...
    To compile the plugin, add --enable-galaktos in configure. The only
    dependencies are on X11 and OpenGL libs.
    Enjoy !

58 files changed:
modules/visualization/galaktos/Modules.am
modules/visualization/galaktos/PCM.c [new file with mode: 0644]
modules/visualization/galaktos/PCM.h [new file with mode: 0644]
modules/visualization/galaktos/beat_detect.c [new file with mode: 0644]
modules/visualization/galaktos/beat_detect.h [new file with mode: 0644]
modules/visualization/galaktos/builtin_funcs.c [new file with mode: 0644]
modules/visualization/galaktos/builtin_funcs.h [new file with mode: 0644]
modules/visualization/galaktos/common.h [new file with mode: 0644]
modules/visualization/galaktos/compare.h [new file with mode: 0644]
modules/visualization/galaktos/custom_shape.c [new file with mode: 0644]
modules/visualization/galaktos/custom_shape.h [new file with mode: 0644]
modules/visualization/galaktos/custom_shape_types.h [new file with mode: 0644]
modules/visualization/galaktos/custom_wave.c [new file with mode: 0644]
modules/visualization/galaktos/custom_wave.h [new file with mode: 0644]
modules/visualization/galaktos/custom_wave_types.h [new file with mode: 0644]
modules/visualization/galaktos/engine_vars.c [new file with mode: 0644]
modules/visualization/galaktos/engine_vars.h [new file with mode: 0644]
modules/visualization/galaktos/eval.c [new file with mode: 0644]
modules/visualization/galaktos/eval.h [new file with mode: 0644]
modules/visualization/galaktos/expr_types.h [new file with mode: 0644]
modules/visualization/galaktos/fatal.h [new file with mode: 0644]
modules/visualization/galaktos/fftsg.c [new file with mode: 0644]
modules/visualization/galaktos/func.c [new file with mode: 0644]
modules/visualization/galaktos/func.h [new file with mode: 0644]
modules/visualization/galaktos/func_types.h [new file with mode: 0644]
modules/visualization/galaktos/glx.c
modules/visualization/galaktos/glx.h
modules/visualization/galaktos/idle_preset.h [new file with mode: 0644]
modules/visualization/galaktos/init_cond.c [new file with mode: 0644]
modules/visualization/galaktos/init_cond.h [new file with mode: 0644]
modules/visualization/galaktos/init_cond_types.h [new file with mode: 0644]
modules/visualization/galaktos/interface_types.h [new file with mode: 0644]
modules/visualization/galaktos/main.c
modules/visualization/galaktos/main.h
modules/visualization/galaktos/param.c [new file with mode: 0644]
modules/visualization/galaktos/param.h [new file with mode: 0644]
modules/visualization/galaktos/param_types.h [new file with mode: 0644]
modules/visualization/galaktos/parser.c [new file with mode: 0644]
modules/visualization/galaktos/parser.h [new file with mode: 0644]
modules/visualization/galaktos/per_frame_eqn.c [new file with mode: 0644]
modules/visualization/galaktos/per_frame_eqn.h [new file with mode: 0644]
modules/visualization/galaktos/per_frame_eqn_types.h [new file with mode: 0644]
modules/visualization/galaktos/per_pixel_eqn.c [new file with mode: 0644]
modules/visualization/galaktos/per_pixel_eqn.h [new file with mode: 0644]
modules/visualization/galaktos/per_pixel_eqn_types.h [new file with mode: 0644]
modules/visualization/galaktos/per_point_types.h [new file with mode: 0644]
modules/visualization/galaktos/plugin.c
modules/visualization/galaktos/plugin.h
modules/visualization/galaktos/preset.c [new file with mode: 0644]
modules/visualization/galaktos/preset.h [new file with mode: 0644]
modules/visualization/galaktos/preset_types.h [new file with mode: 0644]
modules/visualization/galaktos/splaytree.c [new file with mode: 0644]
modules/visualization/galaktos/splaytree.h [new file with mode: 0644]
modules/visualization/galaktos/splaytree_types.h [new file with mode: 0644]
modules/visualization/galaktos/tree_types.c [new file with mode: 0644]
modules/visualization/galaktos/tree_types.h [new file with mode: 0644]
modules/visualization/galaktos/video_init.c [new file with mode: 0644]
modules/visualization/galaktos/video_init.h [new file with mode: 0644]

index 906e2a1784bb7cc05d537b79425b52ed308660c8..937e7df72530b9876a9f9589fea8c80498d1d8af 100644 (file)
@@ -3,4 +3,23 @@ SOURCES_galaktos = plugin.c \
                    glx.c \
                    glx.h \
                    main.c \
-                   main.h
+                   main.h \
+                   preset.c \
+                   preset.h \
+                   beat_detect.c \
+                   param.c \
+                   engine_vars.c \
+                   parser.c \
+                   builtin_funcs.c \
+                   eval.c \
+                   init_cond.c \
+                   PCM.c \
+                   fftsg.c \
+                   per_frame_eqn.c \
+                   splaytree.c \
+                   custom_shape.c \
+                   func.c \
+                   per_pixel_eqn.c \
+                   tree_types.c \
+                   custom_wave.c \
+                   video_init.c
diff --git a/modules/visualization/galaktos/PCM.c b/modules/visualization/galaktos/PCM.c
new file mode 100644 (file)
index 0000000..14e8be4
--- /dev/null
@@ -0,0 +1,199 @@
+/*****************************************************************************
+ * PCM.c:
+ *****************************************************************************
+ * Copyright (C) 2004 VideoLAN
+ * $Id$
+ *
+ * Authors: Cyril Deguet <asmax@videolan.org>
+ *          code from projectM http://xmms-projectm.sourceforge.net
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ *****************************************************************************/
+
+
+//PCM.c - Sound data handler
+//
+//by Peter Sperl
+//
+//Takes sound data from wherever and hands it back out.
+//Returns PCM Data or spectrum data, or the derivative of the PCM data
+
+#include <stdlib.h>
+#include <stdio.h>
+
+double **PCMd;    //data structure to store PCM data  PCM[channels][maxsamples]
+int maxsamples;   //size of PCM buffer
+int start;        //where to add data next
+
+int *ip;          //working space for FFT routines
+double *w;        //lookup table for FFT routines
+int new;          //how many new samples
+
+
+//initPCM(int samples)
+//
+//Initializes the PCM buffer to
+// number of samples specified.
+
+void initPCM(int samples)
+{
+  int i; 
+
+  //Allocate memory for PCM data buffer
+  PCMd = (double **)malloc(2 * sizeof(double *));
+  PCMd[0] = (double *)malloc(samples * sizeof(double));
+  PCMd[1] = (double *)malloc(samples * sizeof(double));
+  
+  maxsamples=samples;
+  new=0;
+
+  //Initialize buffers to 0
+  for (i=0;i<samples;i++)
+    {
+      PCMd[0][i]=0;
+      PCMd[1][i]=0;
+    }
+
+  start=0;
+
+  //Allocate FFT workspace
+  w=  (double *)malloc(maxsamples*sizeof(double));
+  ip= (int *)malloc(maxsamples*sizeof(int));
+  ip[0]=0;
+}
+
+//The only current addPCM function, can support more
+//
+//Takes in a 2x512 array of PCM samples
+//and stores them
+
+void addPCM(int16_t PCMdata[2][512])
+{
+  int i,j;
+  int samples=512;
+
+        for(i=0;i<samples;i++)
+          {
+            j=i+start;
+            PCMd[0][j%maxsamples]=(PCMdata[0][i]/16384.0);
+            PCMd[1][j%maxsamples]=(PCMdata[1][i]/16384.0);  
+          }
+       
+        // printf("Added %d samples %d %d %f\n",samples,start,(start+samples)%maxsamples,PCM[0][start+10]); 
+
+ start+=samples;
+ start=start%maxsamples;
+
+ new+=samples;
+ if (new>maxsamples) new=maxsamples;
+}
+
+
+//puts sound data requested at provided pointer
+//
+//samples is number of PCM samples to return
+//freq = 0 gives PCM data
+//freq = 1 gives FFT data
+//smoothing is the smoothing coefficient
+
+//returned values are normalized from -1 to 1
+
+void getPCM(double *PCMdata, int samples, int channel, int freq, double smoothing, int derive)
+{
+   int i,index;
+   
+   index=start-1;
+
+   if (index<0) index=maxsamples+index;
+
+   PCMdata[0]=PCMd[channel][index];
+   
+   for(i=1;i<samples;i++)
+     {
+       index=start-1-i;
+       if (index<0) index=maxsamples+index;
+       
+       PCMdata[i]=(1-smoothing)*PCMd[channel][index]+smoothing*PCMdata[i-1];
+     }
+   
+   //return derivative of PCM data
+   if(derive)
+     {
+       for(i=0;i<samples-1;i++)
+        {         
+          PCMdata[i]=PCMdata[i]-PCMdata[i+1];
+        }
+       PCMdata[samples-1]=0;
+     }
+
+   //return frequency data instead of PCM (perform FFT)
+   if (freq) rdft(samples, 1, PCMdata, ip, w);
+
+
+     
+}
+
+//getPCMnew
+//
+//Like getPCM except it returns all new samples in the buffer
+//the actual return value is the number of samples, up to maxsamples.
+//the passed pointer, PCMData, must bee able to hold up to maxsamples
+
+int getPCMnew(double *PCMdata, int channel, int freq, double smoothing, int derive, int reset)
+{
+   int i,index;
+   
+   index=start-1;
+
+   if (index<0) index=maxsamples+index;
+
+   PCMdata[0]=PCMd[channel][index];
+   
+   for(i=1;i<new;i++)
+     {
+       index=start-1-i;
+       if (index<0) index=maxsamples+index;
+       
+       PCMdata[i]=(1-smoothing)*PCMd[channel][index]+smoothing*PCMdata[i-1];
+     }
+   
+   //return derivative of PCM data
+   if(derive)
+     {
+       for(i=0;i<new-1;i++)
+        {         
+          PCMdata[i]=PCMdata[i]-PCMdata[i+1];
+        }
+       PCMdata[new-1]=0;
+     }
+
+   //return frequency data instead of PCM (perform FFT)
+   //   if (freq) rdft(samples, 1, PCMdata, ip, w);
+   i=new;
+   if (reset)  new=0;
+
+   return i;
+}
+
+//Free stuff
+void freePCM()
+{
+  free(PCMd[0]);
+  free(PCMd[1]);
+  free(PCMd);
+  free(ip);
+  free(w);
+}
diff --git a/modules/visualization/galaktos/PCM.h b/modules/visualization/galaktos/PCM.h
new file mode 100644 (file)
index 0000000..9b3607b
--- /dev/null
@@ -0,0 +1,6 @@
+
+void initPCM(int maxsamples);
+void addPCM(int16_t [2][512]);
+void getPCM(double *data, int samples, int channel, int freq, double smoothing, int derive);
+void freePCM();
+int getPCMnew(double *PCMdata, int channel, int freq, double smoothing, int derive,int reset);
diff --git a/modules/visualization/galaktos/beat_detect.c b/modules/visualization/galaktos/beat_detect.c
new file mode 100644 (file)
index 0000000..03f2258
--- /dev/null
@@ -0,0 +1,148 @@
+/*****************************************************************************
+ * beat_detect.c: basic beat detection algorithm
+ *****************************************************************************
+ * Copyright (C) 2004 VideoLAN
+ * $Id$
+ *
+ * Authors: Cyril Deguet <asmax@videolan.org>
+ *          code from projectM http://xmms-projectm.sourceforge.net
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ *****************************************************************************/
+
+//
+//by Peter Sperl
+//
+//Takes sound data from wherever and returns beat detection values
+//Uses statistical Energy-Based methods. Very simple
+//
+//Some stuff was taken from Frederic Patin's beat-detection article, you'll find it online
+
+#include <stdlib.h>
+#include <stdio.h>
+#include "engine_vars.h"
+
+double beat_buffer[32][80],beat_instant[32],beat_history[32];
+double *beat_val,*beat_att,*beat_variance;
+int beat_buffer_pos;
+
+double vol_buffer[80],vol_instant,vol_history;
+
+void initBeatDetect()
+{
+
+  int x,y; 
+
+  vol_instant=0;
+  vol_history=0;
+
+  for (y=0;y<80;y++)
+    {
+      vol_buffer[y]=0;
+    }
+
+  beat_buffer_pos=0;
+
+  beat_val=(double *)malloc(32*sizeof(double));
+  beat_att=(double *)malloc(32*sizeof(double));
+  beat_variance=(double *)malloc(32*sizeof(double));
+
+  for (x=0;x<32;x++)
+    {
+      beat_instant[x]=0;
+      beat_history[x]=0;
+      beat_val[x]=1.0;
+      beat_att[x]=1.0;
+      beat_variance[x]=0;
+      for (y=0;y<80;y++)
+       {
+         beat_buffer[x][y]=0;
+       }
+    }
+
+} 
+
+void getBeatVals(double *vdataL,double *vdataR, double *vol)
+{
+  int linear=0;
+  int x,y;
+
+  vol_instant=0;
+
+      for ( x=0;x<16;x++)
+       {
+         
+         beat_instant[x]=0;
+         for ( y=linear*2;y<(linear+8+x)*2;y++)
+           {
+             beat_instant[x]+=((vdataL[y]*vdataL[y])+(vdataR[y]*vdataR[y]))*(1.0/(8+x)); 
+             vol_instant+=((vdataL[y]*vdataL[y])+(vdataR[y]*vdataR[y]))*(1.0/512.0);
+
+           }
+         
+         linear=y/2;
+         beat_history[x]-=(beat_buffer[x][beat_buffer_pos])*.0125;
+         beat_buffer[x][beat_buffer_pos]=beat_instant[x];
+         beat_history[x]+=(beat_instant[x])*.0125;
+         
+         beat_val[x]=(beat_instant[x])/(beat_history[x]);
+         
+         beat_att[x]+=(beat_instant[x])/(beat_history[x]);
+
+
+         
+       }
+      
+      vol_history-=(vol_buffer[beat_buffer_pos])*.0125;
+      vol_buffer[beat_buffer_pos]=vol_instant;
+      vol_history+=(vol_instant)*.0125;
+
+      double temp2=0;
+      mid=0;
+      for(x=1;x<10;x++)
+       {
+        mid+=(beat_instant[x]);
+         temp2+=(beat_history[x]);
+        
+       }
+       
+        mid=mid/(1.5*temp2);
+        temp2=0;
+        treb=0;
+         for(x=10;x<16;x++)
+           { 
+             treb+=(beat_instant[x]);
+             temp2+=(beat_history[x]);
+           }
+         treb=treb/(1.5*temp2);
+         *vol=vol_instant/(1.5*vol_history);
+  
+         bass=(beat_instant[0])/(1.5*beat_history[0]);
+
+         treb_att=.6 * treb_att + .4 * treb;
+         mid_att=.6 * mid_att + .4 * mid;
+         bass_att=.6 * bass_att + .4 * bass;
+         //printf("%f %f %f %f\n",bass,mid,treb,*vol);
+          // *vol=(beat_instant[3])/(beat_history[3]);
+         beat_buffer_pos++;
+         if( beat_buffer_pos>79)beat_buffer_pos=0;
+       
+}
+void freeBeatDetect()
+{
+  free(beat_att);
+  free(beat_val);
+  free(beat_variance);
+}
diff --git a/modules/visualization/galaktos/beat_detect.h b/modules/visualization/galaktos/beat_detect.h
new file mode 100644 (file)
index 0000000..c673cc1
--- /dev/null
@@ -0,0 +1,5 @@
+
+
+void initBeatDetect();
+void getBeatVals(double *vdataL,double *vdataR,double *vol);
+void freeBeatDetect();
diff --git a/modules/visualization/galaktos/builtin_funcs.c b/modules/visualization/galaktos/builtin_funcs.c
new file mode 100644 (file)
index 0000000..16086d3
--- /dev/null
@@ -0,0 +1,206 @@
+/*****************************************************************************
+ * builtin_funcs.c:
+ *****************************************************************************
+ * Copyright (C) 2004 VideoLAN
+ * $Id$
+ *
+ * Authors: Cyril Deguet <asmax@videolan.org>
+ *          code from projectM http://xmms-projectm.sourceforge.net
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ *****************************************************************************/
+
+
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+/* Values to optimize the sigmoid function */
+#define R  32767   
+#define RR 65534   
+inline double int_wrapper(double * arg_list) {
+
+  return floor(arg_list[0]);
+
+}
+
+
+inline double sqr_wrapper(double * arg_list) {
+       
+       return pow(2, arg_list[0]);
+}      
+       
+       
+inline double sign_wrapper(double * arg_list) {        
+       
+       return -arg_list[0];    
+}      
+
+inline double min_wrapper(double * arg_list) {
+       
+       if (arg_list[0] > arg_list[1])
+               return arg_list[1];
+       
+       return arg_list[0];
+}              
+
+inline double max_wrapper(double * arg_list) {
+
+       if (arg_list[0] > arg_list[1])
+         return arg_list[0];
+
+       return arg_list[1];
+}
+
+/* consult your AI book */
+inline double sigmoid_wrapper(double * arg_list) {
+  return (RR / (1 + exp( -(((double)(arg_list[0])) * arg_list[1]) / R) - R));
+}
+       
+       
+inline double bor_wrapper(double * arg_list) {
+
+       return (double)((int)arg_list[0] || (int)arg_list[1]);
+}      
+       
+inline double band_wrapper(double * arg_list) {
+       return (double)((int)arg_list[0] && (int)arg_list[1]);
+}      
+
+inline double bnot_wrapper(double * arg_list) {
+       return (double)(!(int)arg_list[0]);
+}              
+
+inline double if_wrapper(double * arg_list) {
+
+               if ((int)arg_list[0] == 0)
+                       return arg_list[2];
+               return arg_list[1];
+}              
+
+
+inline double rand_wrapper(double * arg_list) {
+  double l;
+
+  //  printf("RAND ARG:(%d)\n", (int)arg_list[0]);
+  l = (double)((rand()) % ((int)arg_list[0]));
+  //printf("VAL: %f\n", l);
+  return l;
+}      
+
+inline double equal_wrapper(double * arg_list) {
+
+       return (arg_list[0] == arg_list[1]);
+}      
+
+
+inline double above_wrapper(double * arg_list) {
+
+       return (arg_list[0] > arg_list[1]);
+}      
+
+
+inline double below_wrapper(double * arg_list) {
+
+       return (arg_list[0] < arg_list[1]);
+}
+
+inline double sin_wrapper(double * arg_list) {
+       return (sin (arg_list[0]));     
+}
+
+
+inline double cos_wrapper(double * arg_list) {
+       return (cos (arg_list[0]));
+}
+
+inline double tan_wrapper(double * arg_list) {
+       return (tan(arg_list[0]));
+}
+
+inline double asin_wrapper(double * arg_list) {
+       return (asin (arg_list[0]));
+}
+
+inline double acos_wrapper(double * arg_list) {
+       return (acos (arg_list[0]));
+}
+
+inline double atan_wrapper(double * arg_list) {
+       return (atan (arg_list[0]));
+}
+
+inline double atan2_wrapper(double * arg_list) {
+  return (atan2 (arg_list[0], arg_list[1]));
+}
+
+inline double pow_wrapper(double * arg_list) {
+  return (pow (arg_list[0], arg_list[1]));
+}
+
+inline double exp_wrapper(double * arg_list) {
+  return (exp(arg_list[0]));
+}
+
+inline double abs_wrapper(double * arg_list) {
+  return (fabs(arg_list[0]));
+}
+
+inline double log_wrapper(double *arg_list) {
+  return (log (arg_list[0]));
+}
+
+inline double log10_wrapper(double * arg_list) {
+  return (log10 (arg_list[0]));
+}
+
+inline double sqrt_wrapper(double * arg_list) {
+  return (sqrt (arg_list[0]));
+}
+
+
+inline double nchoosek_wrapper(double * arg_list) {
+      unsigned long cnm = 1UL;
+      int i, f;
+      int n, m;
+
+      n = (int)arg_list[0];
+      m = (int)arg_list[1];
+
+      if (m*2 >n) m = n-m;
+      for (i=1 ; i <= m; n--, i++)
+      {
+            if ((f=n) % i == 0)
+                  f   /= i;
+            else  cnm /= i;
+            cnm *= f;
+      }
+      return (double)cnm;
+}
+
+
+inline double fact_wrapper(double * arg_list) {
+
+
+  int result = 1;
+  
+  int n = (int)arg_list[0];
+  
+  while (n > 1) {
+    result = result * n;
+    n--;
+  }
+  return (double)result;
+}
diff --git a/modules/visualization/galaktos/builtin_funcs.h b/modules/visualization/galaktos/builtin_funcs.h
new file mode 100644 (file)
index 0000000..a181684
--- /dev/null
@@ -0,0 +1,35 @@
+/* Wrappers for all the builtin functions 
+   The arg_list pointer is a list of doubles. Its
+   size is equal to the number of arguments the parameter
+   takes */
+inline double below_wrapper(double * arg_list);
+inline double above_wrapper(double * arg_list);
+inline double equal_wrapper(double * arg_list);
+inline double if_wrapper(double * arg_list);
+inline double bnot_wrapper(double * arg_list);
+inline double rand_wrapper(double * arg_list);
+inline double bor_wrapper(double * arg_list);
+inline double band_wrapper(double * arg_list);
+inline double sigmoid_wrapper(double * arg_list);
+inline double max_wrapper(double * arg_list);
+inline double min_wrapper(double * arg_list);
+inline double sign_wrapper(double * arg_list);
+inline double sqr_wrapper(double * arg_list);
+inline double int_wrapper(double * arg_list);
+inline double nchoosek_wrapper(double * arg_list);
+inline double sin_wrapper(double * arg_list);
+inline double cos_wrapper(double * arg_list);
+inline double tan_wrapper(double * arg_list);
+inline double fact_wrapper(double * arg_list);
+inline double asin_wrapper(double * arg_list);
+inline double acos_wrapper(double * arg_list);
+inline double atan_wrapper(double * arg_list);
+inline double atan2_wrapper(double * arg_list);
+
+inline double pow_wrapper(double * arg_list);
+inline double exp_wrapper(double * arg_list);
+inline double abs_wrapper(double * arg_list);
+inline double log_wrapper(double *arg_list);
+inline double log10_wrapper(double * arg_list);
+inline double sqrt_wrapper(double * arg_list);
diff --git a/modules/visualization/galaktos/common.h b/modules/visualization/galaktos/common.h
new file mode 100644 (file)
index 0000000..560a6cc
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef COMMON_H
+#define COMMON_H
+
+#define DEFAULT_FONT_PATH "/home/carm/fonts/courier1.glf"
+#define MAX_TOKEN_SIZE 512
+#define MAX_PATH_SIZE 4096
+
+#define STRING_BUFFER_SIZE 1024*150
+#define STRING_LINE_SIZE 1024
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif 
+
+#define PROJECTM_FILE_EXTENSION ".prjm"
+#define MILKDROP_FILE_EXTENSION ".milk"
+
+#define MAX_DOUBLE_SIZE  10000000.0
+#define MIN_DOUBLE_SIZE -10000000.0
+
+#define MAX_INT_SIZE  10000000
+#define MIN_INT_SIZE -10000000
+
+#define DEFAULT_DOUBLE_IV 0.0 /* default double initial value */
+#define DEFAULT_DOUBLE_LB MIN_DOUBLE_SIZE /* default double lower bound */
+#define DEFAULT_DOUBLE_UB MAX_DOUBLE_SIZE /* default double upper bound */
+
+#endif
diff --git a/modules/visualization/galaktos/compare.h b/modules/visualization/galaktos/compare.h
new file mode 100644 (file)
index 0000000..851aad3
--- /dev/null
@@ -0,0 +1,3 @@
+
+int compare_int(int * num1, int * num2);
+int compare_string(char * string1, char * string2);
diff --git a/modules/visualization/galaktos/custom_shape.c b/modules/visualization/galaktos/custom_shape.c
new file mode 100644 (file)
index 0000000..d85dfa7
--- /dev/null
@@ -0,0 +1,607 @@
+/*****************************************************************************
+ * custom_shape.c:
+ *****************************************************************************
+ * Copyright (C) 2004 VideoLAN
+ * $Id$
+ *
+ * Authors: Cyril Deguet <asmax@videolan.org>
+ *          code from projectM http://xmms-projectm.sourceforge.net
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ *****************************************************************************/
+
+//
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "common.h"
+#include "fatal.h"
+
+#include "param_types.h"
+#include "param.h"
+
+#include "expr_types.h"
+#include "eval.h"
+
+#include "splaytree_types.h"
+#include "splaytree.h"
+#include "tree_types.h"
+
+#include "per_frame_eqn_types.h"
+#include "per_frame_eqn.h"
+
+#include "init_cond_types.h"
+#include "init_cond.h"
+
+#include "preset_types.h"
+
+#include "custom_shape_types.h"
+#include "custom_shape.h"
+
+#include "init_cond_types.h"
+#include "init_cond.h"
+
+custom_shape_t * interface_shape = NULL;
+int cwave_interface_id = 0;
+extern preset_t * active_preset;
+inline void eval_custom_shape_init_conds(custom_shape_t * custom_shape);
+void load_unspec_init_cond_shape(param_t * param);
+
+void destroy_param_db_tree_shape(splaytree_t * tree);
+void destroy_per_frame_eqn_tree_shape(splaytree_t * tree);
+void destroy_per_frame_init_eqn_tree_shape(splaytree_t * tree);
+void destroy_init_cond_tree_shape(splaytree_t * tree);
+
+custom_shape_t * new_custom_shape(int id) {
+
+  custom_shape_t * custom_shape;
+  param_t * param;
+
+  if ((custom_shape = (custom_shape_t*)malloc(sizeof(custom_shape_t))) == NULL)
+    return NULL;
+
+  custom_shape->id = id;
+  custom_shape->per_frame_count = 0;
+  custom_shape->per_frame_eqn_string_index = 0;
+  custom_shape->per_frame_init_eqn_string_index = 0;
+
+  /* Initialize tree data structures */
+
+  if ((custom_shape->param_tree = 
+       create_splaytree(compare_string, copy_string, free_string)) == NULL) {
+    free_custom_shape(custom_shape);
+    return NULL;
+  }
+
+  if ((custom_shape->per_frame_eqn_tree = 
+       create_splaytree(compare_int, copy_int, free_int)) == NULL) {
+    free_custom_shape(custom_shape);
+    return NULL;
+  }
+
+  if ((custom_shape->init_cond_tree = 
+       create_splaytree(compare_string, copy_string, free_string)) == NULL) {
+    free_custom_shape(custom_shape);
+    return NULL;
+  }
+  
+  if ((custom_shape->per_frame_init_eqn_tree = 
+       create_splaytree(compare_string, copy_string, free_string)) == NULL) {
+    free_custom_shape(custom_shape);
+    return NULL;
+  }
+
+  /* Start: Load custom shape parameters */
+
+  if ((param = new_param_double("r", P_FLAG_NONE, &custom_shape->r, NULL, 1.0, 0.0, .5)) == NULL) {
+    free_custom_shape(custom_shape);
+    return NULL;
+  }
+
+  if (insert_param(param, custom_shape->param_tree) < 0) {
+    free_custom_shape(custom_shape);
+    return NULL;
+  }
+  if ((param = new_param_double("g", P_FLAG_NONE, &custom_shape->g, NULL, 1.0, 0.0, .5)) == NULL){
+    free_custom_shape(custom_shape);
+    return NULL;
+  }
+
+  if (insert_param(param, custom_shape->param_tree) < 0) {
+    free_custom_shape(custom_shape);
+    return NULL;
+  }
+
+  if ((param = new_param_double("b", P_FLAG_NONE, &custom_shape->b, NULL, 1.0, 0.0, .5)) == NULL){
+    free_custom_shape(custom_shape);
+    return NULL;                                      
+  }
+
+  if (insert_param(param, custom_shape->param_tree) < 0) {
+    free_custom_shape(custom_shape);
+    return NULL;
+  }
+
+  if ((param = new_param_double("a", P_FLAG_NONE, &custom_shape->a, NULL, 1.0, 0.0, .5)) == NULL){
+    free_custom_shape(custom_shape);
+    return NULL;
+  }
+
+  if (insert_param(param, custom_shape->param_tree) < 0) {
+    free_custom_shape(custom_shape);
+    return NULL;
+  }
+
+  if ((param = new_param_double("border_r", P_FLAG_NONE, &custom_shape->border_r, NULL, 1.0, 0.0, .5)) == NULL) {
+    free_custom_shape(custom_shape);
+    return NULL;
+  }
+
+  if (insert_param(param, custom_shape->param_tree) < 0) {
+    free_custom_shape(custom_shape);
+    return NULL;
+  }
+  if ((param = new_param_double("border_g", P_FLAG_NONE, &custom_shape->border_g, NULL, 1.0, 0.0, .5)) == NULL){
+    free_custom_shape(custom_shape);
+    return NULL;
+  }
+
+  if (insert_param(param, custom_shape->param_tree) < 0) {
+    free_custom_shape(custom_shape);
+    return NULL;
+  }
+
+  if ((param = new_param_double("border_b", P_FLAG_NONE, &custom_shape->border_b, NULL, 1.0, 0.0, .5)) == NULL){
+    free_custom_shape(custom_shape);
+    return NULL;                                      
+  }
+
+  if (insert_param(param, custom_shape->param_tree) < 0) {
+    free_custom_shape(custom_shape);
+    return NULL;
+  }
+
+  if ((param = new_param_double("border_a", P_FLAG_NONE, &custom_shape->border_a, NULL, 1.0, 0.0, .5)) == NULL){
+    free_custom_shape(custom_shape);
+    return NULL;
+  }
+
+  if (insert_param(param, custom_shape->param_tree) < 0) {
+    free_custom_shape(custom_shape);
+    return NULL;
+  }
+
+  if ((param = new_param_double("r2", P_FLAG_NONE, &custom_shape->r2, NULL, 1.0, 0.0, .5)) == NULL) {
+    free_custom_shape(custom_shape);
+    return NULL;
+  }
+
+  if (insert_param(param, custom_shape->param_tree) < 0) {
+    free_custom_shape(custom_shape);
+    return NULL;
+  }
+  if ((param = new_param_double("g2", P_FLAG_NONE, &custom_shape->g2, NULL, 1.0, 0.0, .5)) == NULL){
+    free_custom_shape(custom_shape);
+    return NULL;
+  }
+
+  if (insert_param(param, custom_shape->param_tree) < 0) {
+    free_custom_shape(custom_shape);
+    return NULL;
+  }
+
+  if ((param = new_param_double("b2", P_FLAG_NONE, &custom_shape->b2, NULL, 1.0, 0.0, .5)) == NULL){
+    free_custom_shape(custom_shape);
+    return NULL;                                      
+  }
+
+  if (insert_param(param, custom_shape->param_tree) < 0) {
+    free_custom_shape(custom_shape);
+    return NULL;
+  }
+
+  if ((param = new_param_double("a2", P_FLAG_NONE, &custom_shape->a2, NULL, 1.0, 0.0, .5)) == NULL){
+    free_custom_shape(custom_shape);
+    return NULL;
+  }
+  
+  if (insert_param(param, custom_shape->param_tree) < 0) {
+    free_custom_shape(custom_shape);
+    return NULL;
+  }
+
+  if ((param = new_param_double("x", P_FLAG_NONE, &custom_shape->x, NULL, 1.0, 0.0, .5)) == NULL) {
+    free_custom_shape(custom_shape);
+    return NULL;
+  }
+
+  if (insert_param(param, custom_shape->param_tree) < 0) {
+    free_custom_shape(custom_shape);
+    return NULL;
+  }
+
+  if ((param = new_param_double("y", P_FLAG_NONE, &custom_shape->y, NULL, 1.0, 0.0, .5)) == NULL) {
+    free_custom_shape(custom_shape);
+    return NULL;
+  }
+
+  if (insert_param(param, custom_shape->param_tree) < 0) {
+    free_custom_shape(custom_shape);
+    return NULL;
+  }
+
+  if ((param = new_param_bool("thickOutline", P_FLAG_NONE, &custom_shape->thickOutline, 1, 0, 0)) == NULL) {
+    free_custom_shape(custom_shape);
+    return NULL;
+  }
+
+  if (insert_param(param, custom_shape->param_tree) < 0) {
+    free_custom_shape(custom_shape);
+    return NULL;
+  }
+
+  if ((param = new_param_bool("enabled", P_FLAG_NONE, &custom_shape->enabled, 1, 0, 0)) == NULL) {
+    free_custom_shape(custom_shape);
+    return NULL;
+  }
+
+  if (insert_param(param, custom_shape->param_tree) < 0) {
+    free_custom_shape(custom_shape);
+    return NULL;
+  }
+
+  if ((param = new_param_int("sides", P_FLAG_NONE, &custom_shape->sides, 100, 3, 3)) == NULL) {
+    free_custom_shape(custom_shape);
+    return NULL;
+  }
+
+  if (insert_param(param, custom_shape->param_tree) < 0) {
+    free_custom_shape(custom_shape);
+    return NULL;
+  }
+
+  if ((param = new_param_bool("additive", P_FLAG_NONE, &custom_shape->additive, 1, 0, 0)) == NULL) {
+    free_custom_shape(custom_shape);
+    return NULL;
+  }
+
+  if (insert_param(param, custom_shape->param_tree) < 0) {
+    free_custom_shape(custom_shape);
+    return NULL;
+  }
+
+  if ((param = new_param_bool("textured", P_FLAG_NONE, &custom_shape->textured, 1, 0, 0)) == NULL) {
+    free_custom_shape(custom_shape);
+    return NULL;
+  }
+
+  if (insert_param(param, custom_shape->param_tree) < 0) {
+    free_custom_shape(custom_shape);
+    return NULL;
+  }
+
+   if ((param = new_param_double("rad", P_FLAG_NONE, &custom_shape->rad, NULL, MAX_DOUBLE_SIZE, 0, 0.0)) == NULL) {
+    free_custom_shape(custom_shape);
+    return NULL;
+  }
+
+   if (insert_param(param, custom_shape->param_tree) < 0) {
+    free_custom_shape(custom_shape);
+    return NULL;
+  }
+
+   if ((param = new_param_double("ang", P_FLAG_NONE, &custom_shape->ang, NULL, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0)) == NULL) {
+    free_custom_shape(custom_shape);
+    return NULL;
+  }
+
+   if (insert_param(param, custom_shape->param_tree) < 0) {
+    free_custom_shape(custom_shape);
+    return NULL;
+  }
+
+   if ((param = new_param_double("tex_zoom", P_FLAG_NONE, &custom_shape->tex_zoom, NULL, MAX_DOUBLE_SIZE, .00000000001, 0.0)) == NULL) {
+    free_custom_shape(custom_shape);
+    return NULL;
+  }
+
+   if (insert_param(param, custom_shape->param_tree) < 0) {
+    free_custom_shape(custom_shape);
+    return NULL;
+  }
+   
+   if ((param = new_param_double("tex_ang", P_FLAG_NONE, &custom_shape->tex_ang, NULL, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0)) == NULL) {
+    free_custom_shape(custom_shape);
+    return NULL;
+  }
+
+   if (insert_param(param, custom_shape->param_tree) < 0) {
+    free_custom_shape(custom_shape);
+    return NULL;
+  }
+   if ((param = new_param_double("t1", P_FLAG_TVAR, &custom_shape->t1, NULL, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0)) == NULL) {
+    free_custom_shape(custom_shape);
+    return NULL;
+  }
+
+  if (insert_param(param, custom_shape->param_tree) < 0) {
+    free_custom_shape(custom_shape);
+    return NULL;
+  }
+
+  if ((param = new_param_double("t2", P_FLAG_TVAR, &custom_shape->t2, NULL, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0)) == NULL) {
+    free_custom_shape(custom_shape);
+    return NULL;
+  }
+
+  if (insert_param(param, custom_shape->param_tree) < 0) {
+    free_custom_shape(custom_shape);
+    return NULL;
+  }
+
+  if ((param = new_param_double("t3", P_FLAG_TVAR, &custom_shape->t3, NULL, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0)) == NULL) {
+    free_custom_shape(custom_shape);
+    return NULL;
+  }
+
+  if (insert_param(param, custom_shape->param_tree) < 0) {
+    free_custom_shape(custom_shape);
+    return NULL;
+  }
+  if ((param = new_param_double("t4", P_FLAG_TVAR, &custom_shape->t4, NULL, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0)) == NULL) {
+    free_custom_shape(custom_shape);
+    return NULL;
+  }
+
+  if (insert_param(param, custom_shape->param_tree) < 0) {
+    free_custom_shape(custom_shape);
+    return NULL;
+  }
+  if ((param = new_param_double("t5", P_FLAG_TVAR, &custom_shape->t5, NULL, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0)) == NULL) {
+    free_custom_shape(custom_shape);
+    return NULL;
+  }
+  if (insert_param(param, custom_shape->param_tree) < 0) {
+    free_custom_shape(custom_shape);
+    return NULL;
+  }
+  if ((param = new_param_double("t6", P_FLAG_TVAR, &custom_shape->t6, NULL, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0)) == NULL) {
+    free_custom_shape(custom_shape);
+    return NULL;
+  }
+
+  if (insert_param(param, custom_shape->param_tree) < 0) {
+    free_custom_shape(custom_shape);
+    return NULL;
+  }
+  if ((param = new_param_double("t7", P_FLAG_TVAR, &custom_shape->t7, NULL, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0)) == NULL) {
+    free_custom_shape(custom_shape);
+    return NULL;
+  }
+
+  if (insert_param(param, custom_shape->param_tree) < 0) {
+    free_custom_shape(custom_shape);
+    return NULL;
+  }
+
+  if ((param = new_param_double("t8", P_FLAG_TVAR, &custom_shape->t8, NULL, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0)) == NULL) {
+    free_custom_shape(custom_shape);
+    return NULL;
+  }
+
+  if (insert_param(param, custom_shape->param_tree) < 0) {
+    free_custom_shape(custom_shape);
+    return NULL;
+  }
+  /* End of parameter loading. Note that the read only parameters associated
+     with custom shapes (ie, sample) are global variables, and not specific to 
+     the custom shape datastructure. */
+
+
+
+  return custom_shape;
+
+}
+
+void destroy_per_frame_init_eqn_tree_shape(splaytree_t * tree) {
+
+  if (!tree)
+    return;
+
+  splay_traverse(free_init_cond, tree);
+  destroy_splaytree(tree);
+
+}
+
+
+
+void destroy_init_cond_tree_shape(splaytree_t * tree) {
+
+  if (!tree)
+    return;
+
+  splay_traverse(free_init_cond, tree);
+  destroy_splaytree(tree);
+
+}
+
+void destroy_per_frame_eqn_tree_shape(splaytree_t * tree) {
+
+
+  if (!tree)
+    return;
+
+  splay_traverse(free_per_frame_eqn, tree);
+  destroy_splaytree(tree);
+
+}
+
+
+void destroy_param_db_tree_shape(splaytree_t * tree) {
+
+  if (!tree)
+    return;
+
+  splay_traverse(free_param, tree);
+  destroy_splaytree(tree);
+
+}
+
+/* Frees a custom shape form object */
+void free_custom_shape(custom_shape_t * custom_shape) {
+
+  if (custom_shape == NULL)
+    return;
+
+  if (custom_shape->param_tree == NULL)
+    return;
+
+  destroy_per_frame_eqn_tree_shape(custom_shape->per_frame_eqn_tree);
+  destroy_init_cond_tree_shape(custom_shape->init_cond_tree);
+  destroy_param_db_tree_shape(custom_shape->param_tree);
+  destroy_per_frame_init_eqn_tree_shape(custom_shape->per_frame_init_eqn_tree);
+  
+  free(custom_shape);
+
+  return;
+
+}
+
+
+custom_shape_t * find_custom_shape(int id, preset_t * preset, int create_flag) {
+
+  custom_shape_t * custom_shape = NULL;
+
+  if (preset == NULL)
+    return NULL;
+  
+  if ((custom_shape = splay_find(&id, preset->custom_shape_tree)) == NULL) {
+    
+    if (CUSTOM_SHAPE_DEBUG) { printf("find_custom_shape: creating custom shape (id = %d)...", id);fflush(stdout);}
+    
+    if (create_flag == FALSE) {
+      if (CUSTOM_SHAPE_DEBUG) printf("you specified not to (create flag = false), returning null\n");
+      return NULL;
+    }
+    
+    if ((custom_shape = new_custom_shape(id)) == NULL) {
+      if (CUSTOM_SHAPE_DEBUG) printf("failed...out of memory?\n");
+      return NULL;
+    }
+    
+    if (CUSTOM_SHAPE_DEBUG) { printf("success.Inserting..."); fflush(stdout);}
+    
+    if (splay_insert(custom_shape, &custom_shape->id, preset->custom_shape_tree) < 0) {
+      if (CUSTOM_SHAPE_DEBUG) printf("failed, probably a duplicated!!\n");
+      free_custom_shape(custom_shape);
+      return NULL;
+    }
+    
+    if (CUSTOM_SHAPE_DEBUG) printf("done.\n");
+  }
+  
+  return custom_shape;
+}
+
+inline void evalCustomShapeInitConditions() {
+  splay_traverse(eval_custom_shape_init_conds, active_preset->custom_shape_tree);
+
+}
+
+inline void eval_custom_shape_init_conds(custom_shape_t * custom_shape) {
+  splay_traverse(eval_init_cond, custom_shape->init_cond_tree);
+  splay_traverse(eval_init_cond, custom_shape->per_frame_init_eqn_tree);
+}
+
+
+void load_unspecified_init_conds_shape(custom_shape_t * custom_shape) {
+
+  interface_shape = custom_shape;
+  splay_traverse(load_unspec_init_cond_shape, interface_shape->param_tree);
+  interface_shape = NULL;
+}
+
+void load_unspec_init_cond_shape(param_t * param) {
+
+  init_cond_t * init_cond;
+  value_t init_val;
+
+  /* Don't count read only parameters as initial conditions */
+  if (param->flags & P_FLAG_READONLY)
+    return;
+ if (param->flags & P_FLAG_QVAR)
+    return;
+ if (param->flags & P_FLAG_TVAR)
+    return;
+ if (param->flags & P_FLAG_USERDEF)
+    return;
+
+  /* If initial condition was not defined by the preset file, force a default one
+     with the following code */
+  if ((init_cond = splay_find(param->name, interface_shape->init_cond_tree)) == NULL) {
+    
+    /* Make sure initial condition does not exist in the set of per frame initial equations */
+    if ((init_cond = splay_find(param->name, interface_shape->per_frame_init_eqn_tree)) != NULL)
+      return;
+    
+    if (param->type == P_TYPE_BOOL)
+      init_val.bool_val = 0;
+    
+    else if (param->type == P_TYPE_INT)
+      init_val.int_val = *(int*)param->engine_val;
+
+    else if (param->type == P_TYPE_DOUBLE)
+      init_val.double_val = *(double*)param->engine_val;
+
+    //printf("%s\n", param->name);
+    /* Create new initial condition */
+    if ((init_cond = new_init_cond(param, init_val)) == NULL)
+      return;
+    
+    /* Insert the initial condition into this presets tree */
+    if (splay_insert(init_cond, init_cond->param->name, interface_shape->init_cond_tree) < 0) {
+      free_init_cond(init_cond);
+      return;
+    }
+    
+  }
+}
+
+
+/* Interface function. Makes another custom shape the current
+   concern for per frame / point equations */
+inline custom_shape_t * nextCustomShape() {
+
+  if ((interface_shape = splay_find(&cwave_interface_id, active_preset->custom_shape_tree)) == NULL) {
+    cwave_interface_id = 0;
+    return NULL;
+  }
+
+  cwave_interface_id++;
+
+  /* Evaluate all per frame equations associated with this shape */
+  splay_traverse(eval_per_frame_eqn, interface_shape->per_frame_eqn_tree);
+  return interface_shape;
+}
diff --git a/modules/visualization/galaktos/custom_shape.h b/modules/visualization/galaktos/custom_shape.h
new file mode 100644 (file)
index 0000000..4e4d8a8
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef CUSTOM_SHAPE_H
+#define CUSTOM_SHAPE_H
+#define CUSTOM_SHAPE_DEBUG 0
+#include "expr_types.h"
+#include "custom_shape_types.h"
+#include "preset_types.h"
+
+void free_custom_shape(custom_shape_t * custom_shape);
+custom_shape_t * new_custom_shape(int id);
+custom_shape_t * find_custom_shape(int id, preset_t * preset, int create_flag);
+void load_unspecified_init_conds_shape(custom_shape_t * custom_shape);
+inline void evalCustomShapeInitConditions();
+inline custom_shape_t * nextCustomShape();
+#endif
diff --git a/modules/visualization/galaktos/custom_shape_types.h b/modules/visualization/galaktos/custom_shape_types.h
new file mode 100644 (file)
index 0000000..23b69e9
--- /dev/null
@@ -0,0 +1,75 @@
+#ifndef CUSTOM_SHAPE_TYPES_H
+#define CUSTOM_SHAPE_TYPES_H
+#include "common.h"
+#include "splaytree_types.h"
+#include "expr_types.h"
+
+typedef struct CUSTOM_SHAPE_T {
+
+  /* Numerical id */
+  int id;
+  int per_frame_count;
+
+  /* Parameter tree associated with this custom shape */
+  splaytree_t * param_tree;
+
+
+  /* Engine variables */
+  int sides;
+  int thickOutline;
+  int enabled;
+  int additive;
+  int textured;
+
+  double tex_zoom;
+  double tex_ang;
+  
+  double x; /* x position for per point equations */
+  double y; /* y position for per point equations */
+  double rad;
+  double ang;
+
+  double r; /* red color value */
+  double g; /* green color value */
+  double b; /* blue color value */
+  double a; /* alpha color value */
+  double r2; /* red color value */
+  double g2; /* green color value */
+  double b2; /* blue color value */
+  double a2; /* alpha color value */
+
+  double border_r; /* red color value */
+  double border_g; /* green color value */
+  double border_b; /* blue color value */
+  double border_a; /* alpha color value */
+
+  /* stupid t variables */
+  double t1;
+  double t2;
+  double t3;
+  double t4;
+  double t5;
+  double t6;
+  double t7;
+  double t8;
+
+  /* Data structure to hold per frame  / per frame init equations */
+  splaytree_t * init_cond_tree;
+  splaytree_t * per_frame_eqn_tree;
+  splaytree_t * per_frame_init_eqn_tree;
+
+  /* Denotes the index of the last character for each string buffer */
+  int per_frame_eqn_string_index;
+  int per_frame_init_eqn_string_index;
+
+  /* String buffers for per frame / per frame init equations */
+  char per_frame_eqn_string_buffer[STRING_BUFFER_SIZE];
+  char per_frame_init_eqn_string_buffer[STRING_BUFFER_SIZE];
+  /* Per point equation array */
+  
+  
+} custom_shape_t;
+
+
+#endif
diff --git a/modules/visualization/galaktos/custom_wave.c b/modules/visualization/galaktos/custom_wave.c
new file mode 100644 (file)
index 0000000..2166109
--- /dev/null
@@ -0,0 +1,744 @@
+/*****************************************************************************
+ * custom_wave.c:
+ *****************************************************************************
+ * Copyright (C) 2004 VideoLAN
+ * $Id$
+ *
+ * Authors: Cyril Deguet <asmax@videolan.org>
+ *          code from projectM http://xmms-projectm.sourceforge.net
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ *****************************************************************************/
+
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "common.h"
+#include "fatal.h"
+
+#include "param_types.h"
+#include "param.h"
+
+#include "expr_types.h"
+#include "eval.h"
+
+#include "splaytree_types.h"
+#include "splaytree.h"
+#include "tree_types.h"
+
+#include "per_frame_eqn_types.h"
+#include "per_frame_eqn.h"
+
+#include "init_cond_types.h"
+#include "init_cond.h"
+
+#include "preset_types.h"
+
+#include "custom_wave_types.h"
+#include "custom_wave.h"
+
+#include "init_cond_types.h"
+#include "init_cond.h"
+
+#include "engine_vars.h"
+#define MAX_SAMPLE_SIZE 4096
+
+extern int mesh_i;
+
+custom_wave_t * interface_wave = NULL;
+int interface_id = 0;
+extern preset_t * active_preset;
+inline void eval_custom_wave_init_conds(custom_wave_t * custom_wave);
+void load_unspec_init_cond(param_t * param);
+void destroy_per_point_eqn_tree(splaytree_t * tree);
+void destroy_param_db_tree(splaytree_t * tree);
+void destroy_per_frame_eqn_tree(splaytree_t * tree);
+void destroy_per_frame_init_eqn_tree(splaytree_t * tree);
+void destroy_init_cond_tree(splaytree_t * tree);
+inline void evalPerPointEqn(per_point_eqn_t * per_point_eqn);
+
+custom_wave_t * new_custom_wave(int id) {
+
+  custom_wave_t * custom_wave;
+  param_t * param;
+  
+  if ((custom_wave = (custom_wave_t*)malloc(sizeof(custom_wave_t))) == NULL)
+    return NULL;
+
+  custom_wave->id = id;
+  custom_wave->per_frame_count = 0;
+
+  custom_wave->samples = 512;
+  custom_wave->bSpectrum = 0;
+  custom_wave->enabled = 1;
+  custom_wave->sep = 1;
+  custom_wave->smoothing = 0.0;
+  custom_wave->bUseDots = 0;
+  custom_wave->bAdditive = 0;
+  custom_wave->r = custom_wave->g = custom_wave->b = custom_wave->a = 0.0;
+  custom_wave->scaling = 1.0;
+  custom_wave->per_frame_eqn_string_index = 0;
+  custom_wave->per_frame_init_eqn_string_index = 0;
+  custom_wave->per_point_eqn_string_index = 0;
+
+  custom_wave->r_mesh = malloc(MAX_SAMPLE_SIZE*sizeof(double));
+  custom_wave->g_mesh = malloc(MAX_SAMPLE_SIZE*sizeof(double));
+  custom_wave->b_mesh = malloc(MAX_SAMPLE_SIZE*sizeof(double));
+  custom_wave->a_mesh = malloc(MAX_SAMPLE_SIZE*sizeof(double));
+  custom_wave->x_mesh = malloc(MAX_SAMPLE_SIZE*sizeof(double));
+  custom_wave->y_mesh = malloc(MAX_SAMPLE_SIZE*sizeof(double));
+  custom_wave->value1 = malloc(MAX_SAMPLE_SIZE*sizeof(double));
+  custom_wave->value2 = malloc(MAX_SAMPLE_SIZE*sizeof(double));
+  custom_wave->sample_mesh = malloc(MAX_SAMPLE_SIZE*sizeof(double));
+
+  /* Initialize tree data structures */
+  
+  if ((custom_wave->param_tree = 
+       create_splaytree(compare_string, copy_string, free_string)) == NULL) {
+    free_custom_wave(custom_wave);
+    return NULL;
+  }
+
+  if ((custom_wave->per_point_eqn_tree = 
+       create_splaytree(compare_int, copy_int, free_int)) == NULL) {
+    free_custom_wave(custom_wave);
+    return NULL;
+  }
+
+  if ((custom_wave->per_frame_eqn_tree = 
+       create_splaytree(compare_int, copy_int, free_int)) == NULL) {
+    free_custom_wave(custom_wave);
+    return NULL;
+  }
+
+  if ((custom_wave->init_cond_tree = 
+       create_splaytree(compare_string, copy_string, free_string)) == NULL) {
+    free_custom_wave(custom_wave);
+    return NULL;
+  }
+  
+  if ((custom_wave->per_frame_init_eqn_tree = 
+       create_splaytree(compare_string, copy_string, free_string)) == NULL) {
+    free_custom_wave(custom_wave);
+    return NULL;
+  }
+
+  
+  /* Start: Load custom wave parameters */
+
+  if ((param = new_param_double("r", P_FLAG_DONT_FREE_MATRIX | P_FLAG_PER_POINT, &custom_wave->r, custom_wave->r_mesh, 1.0, 0.0, .5)) == NULL) {
+    free_custom_wave(custom_wave);
+    return NULL;
+  }
+
+  if (insert_param(param, custom_wave->param_tree) < 0) {
+    free_custom_wave(custom_wave);
+    return NULL;
+  }
+  if ((param = new_param_double("g", P_FLAG_DONT_FREE_MATRIX | P_FLAG_PER_POINT, &custom_wave->g,  custom_wave->g_mesh, 1.0, 0.0, .5)) == NULL){
+    free_custom_wave(custom_wave);
+    return NULL;
+  }
+
+  if (insert_param(param, custom_wave->param_tree) < 0) {
+    free_custom_wave(custom_wave);
+    return NULL;
+  }
+
+  if ((param = new_param_double("b", P_FLAG_DONT_FREE_MATRIX | P_FLAG_PER_POINT, &custom_wave->b,  custom_wave->b_mesh, 1.0, 0.0, .5)) == NULL){
+    free_custom_wave(custom_wave);
+    return NULL;                                      
+  }
+
+  if (insert_param(param, custom_wave->param_tree) < 0) {
+    free_custom_wave(custom_wave);
+    return NULL;
+  }
+
+  if ((param = new_param_double("a", P_FLAG_DONT_FREE_MATRIX | P_FLAG_PER_POINT, &custom_wave->a,  custom_wave->a_mesh, 1.0, 0.0, .5)) == NULL){
+    free_custom_wave(custom_wave);
+    return NULL;
+  }
+  
+  if (insert_param(param, custom_wave->param_tree) < 0) {
+    free_custom_wave(custom_wave);
+    return NULL;
+  }
+
+  if ((param = new_param_double("x", P_FLAG_DONT_FREE_MATRIX | P_FLAG_PER_POINT, &custom_wave->x,  custom_wave->x_mesh, 1.0, 0.0, .5)) == NULL) {
+    free_custom_wave(custom_wave);
+    return NULL;
+  }
+
+  if (insert_param(param, custom_wave->param_tree) < 0) {
+    free_custom_wave(custom_wave);
+    return NULL;
+  }
+
+  if ((param = new_param_double("y", P_FLAG_DONT_FREE_MATRIX | P_FLAG_PER_POINT, &custom_wave->y,  custom_wave->y_mesh, 1.0, 0.0, .5)) == NULL) {
+    free_custom_wave(custom_wave);
+    return NULL;
+  }
+
+  if (insert_param(param, custom_wave->param_tree) < 0) {
+    free_custom_wave(custom_wave);
+    return NULL;
+  }
+
+  if ((param = new_param_bool("enabled", P_FLAG_NONE, &custom_wave->enabled, 1, 0, 0)) == NULL) {
+    free_custom_wave(custom_wave);
+    return NULL;
+  }
+
+  if (insert_param(param, custom_wave->param_tree) < 0) {
+    free_custom_wave(custom_wave);
+    return NULL;
+  }
+
+  if ((param = new_param_int("sep", P_FLAG_NONE, &custom_wave->sep, 100, -100, 0)) == NULL) {
+    free_custom_wave(custom_wave);
+    return NULL;
+  }
+
+  if (insert_param(param, custom_wave->param_tree) < 0) {
+    free_custom_wave(custom_wave);
+    return NULL;
+  }
+
+  if ((param = new_param_bool("bSpectrum", P_FLAG_NONE, &custom_wave->bSpectrum, 1, 0, 0)) == NULL) {
+    free_custom_wave(custom_wave);
+    return NULL;
+  }
+
+  if (insert_param(param, custom_wave->param_tree) < 0) {
+    free_custom_wave(custom_wave);
+    return NULL;
+  }
+
+  if ((param = new_param_bool("bDrawThick", P_FLAG_NONE, &custom_wave->bDrawThick, 1, 0, 0)) == NULL) {
+    free_custom_wave(custom_wave);
+    return NULL;
+  }
+
+  if (insert_param(param, custom_wave->param_tree) < 0) {
+    free_custom_wave(custom_wave);
+    return NULL;
+  }
+
+  if ((param = new_param_bool("bUseDots", P_FLAG_NONE, &custom_wave->bUseDots, 1, 0, 0)) == NULL) {
+    free_custom_wave(custom_wave);
+    return NULL;
+  }
+
+  if (insert_param(param, custom_wave->param_tree) < 0) {
+    free_custom_wave(custom_wave);
+    return NULL;
+  }
+  if ((param = new_param_bool("bAdditive", P_FLAG_NONE, &custom_wave->bAdditive, 1, 0, 0)) == NULL) {
+    free_custom_wave(custom_wave);
+    return NULL;
+  }
+
+  if (insert_param(param, custom_wave->param_tree) < 0) {
+    free_custom_wave(custom_wave);
+    return NULL;
+  }
+
+  if ((param = new_param_int("samples", P_FLAG_NONE, &custom_wave->samples, 2048, 1, 512)) == NULL) {
+    free_custom_wave(custom_wave);
+    return NULL;
+  }
+  if (insert_param(param, custom_wave->param_tree) < 0) {
+    free_custom_wave(custom_wave);
+    return NULL;
+  }
+
+  if ((param = new_param_double("sample", P_FLAG_READONLY | P_FLAG_DONT_FREE_MATRIX | P_FLAG_ALWAYS_MATRIX | P_FLAG_PER_POINT,
+                               &custom_wave->sample, custom_wave->sample_mesh, 1.0, 0.0, 0.0)) == NULL) {
+    free_custom_wave(custom_wave);
+    return NULL;
+  }
+ if (insert_param(param, custom_wave->param_tree) < 0) {
+    printf("failed to insert sample\n");
+    free_custom_wave(custom_wave);
+    return NULL;
+  }
+
+  if ((param = new_param_double("value1", P_FLAG_READONLY | P_FLAG_DONT_FREE_MATRIX | P_FLAG_ALWAYS_MATRIX | P_FLAG_PER_POINT, &custom_wave->v1, custom_wave->value1, 1.0, -1.0, 0.0)) == NULL) {
+    free_custom_wave(custom_wave);
+    return NULL;
+  }
+
+  if (insert_param(param, custom_wave->param_tree) < 0) {
+    free_custom_wave(custom_wave);
+    return NULL;
+  }
+
+  if ((param = new_param_double("value2", P_FLAG_READONLY | P_FLAG_DONT_FREE_MATRIX | P_FLAG_ALWAYS_MATRIX | P_FLAG_PER_POINT, &custom_wave->v2, custom_wave->value2, 1.0, -1.0, 0.0)) == NULL) {
+    free_custom_wave(custom_wave);
+    return NULL;
+  }
+
+  if (insert_param(param, custom_wave->param_tree) < 0) {
+    free_custom_wave(custom_wave);
+    return NULL;
+  }
+
+  if ((param = new_param_double("smoothing", P_FLAG_NONE, &custom_wave->smoothing, NULL, 1.0, 0.0, 0.0)) == NULL) {
+    free_custom_wave(custom_wave);
+    return NULL;
+  }
+
+  if (insert_param(param, custom_wave->param_tree) < 0) {
+    free_custom_wave(custom_wave);
+    return NULL;
+  }
+
+  if ((param = new_param_double("scaling", P_FLAG_NONE, &custom_wave->scaling, NULL, MAX_DOUBLE_SIZE, 0.0, 1.0)) == NULL) {
+    free_custom_wave(custom_wave);
+    return NULL;
+  }
+
+  if (insert_param(param, custom_wave->param_tree) < 0) {
+    free_custom_wave(custom_wave);
+    return NULL;
+  }
+  if ((param = new_param_double("t1", P_FLAG_PER_POINT | P_FLAG_TVAR, &custom_wave->t1, NULL, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0)) == NULL) {
+    free_custom_wave(custom_wave);
+    return NULL;
+  }
+
+  if (insert_param(param, custom_wave->param_tree) < 0) {
+    free_custom_wave(custom_wave);
+    return NULL;
+  }
+
+  if ((param = new_param_double("t2",  P_FLAG_PER_POINT |P_FLAG_TVAR, &custom_wave->t2, NULL, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0)) == NULL) {
+    free_custom_wave(custom_wave);
+    return NULL;
+  }
+
+  if (insert_param(param, custom_wave->param_tree) < 0) {
+    free_custom_wave(custom_wave);
+    return NULL;
+  }
+
+  if ((param = new_param_double("t3",  P_FLAG_PER_POINT |P_FLAG_TVAR, &custom_wave->t3, NULL, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0)) == NULL) {
+    free_custom_wave(custom_wave);
+    return NULL;
+  }
+
+  if (insert_param(param, custom_wave->param_tree) < 0) {
+    free_custom_wave(custom_wave);
+    return NULL;
+  }
+  if ((param = new_param_double("t4",  P_FLAG_PER_POINT |P_FLAG_TVAR, &custom_wave->t4, NULL, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0)) == NULL) {
+    free_custom_wave(custom_wave);
+    return NULL;
+  }
+
+  if (insert_param(param, custom_wave->param_tree) < 0) {
+    free_custom_wave(custom_wave);
+    return NULL;
+  }
+  if ((param = new_param_double("t5", P_FLAG_TVAR, &custom_wave->t5, NULL, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0)) == NULL) {
+    free_custom_wave(custom_wave);
+    return NULL;
+  }
+  if (insert_param(param, custom_wave->param_tree) < 0) {
+    free_custom_wave(custom_wave);
+    return NULL;
+  }
+  if ((param = new_param_double("t6", P_FLAG_TVAR | P_FLAG_PER_POINT, &custom_wave->t6, NULL, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0)) == NULL) {
+    free_custom_wave(custom_wave);
+    return NULL;
+  }
+
+  if (insert_param(param, custom_wave->param_tree) < 0) {
+    free_custom_wave(custom_wave);
+    return NULL;
+  }
+  if ((param = new_param_double("t7", P_FLAG_TVAR | P_FLAG_PER_POINT, &custom_wave->t7, NULL, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0)) == NULL) {
+    free_custom_wave(custom_wave);
+    return NULL;
+  }
+
+  if (insert_param(param, custom_wave->param_tree) < 0) {
+    free_custom_wave(custom_wave);
+    return NULL;
+  }
+
+  if ((param = new_param_double("t8", P_FLAG_TVAR | P_FLAG_PER_POINT, &custom_wave->t8, NULL, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, 0.0)) == NULL) {
+    free_custom_wave(custom_wave);
+    return NULL;
+  }
+
+  if (insert_param(param, custom_wave->param_tree) < 0) {
+    free_custom_wave(custom_wave);
+    return NULL;
+  }
+  
+  /* End of parameter loading. Note that the read only parameters associated
+     with custom waves (ie, sample) are global variables, and not specific to 
+     the custom wave datastructure. */
+
+
+  return custom_wave;
+
+}
+
+void destroy_per_frame_init_eqn_tree(splaytree_t * tree) {
+
+  if (!tree)
+    return;
+
+  splay_traverse(free_init_cond, tree);
+  destroy_splaytree(tree);
+
+}
+
+
+void destroy_per_point_eqn_tree(splaytree_t * tree) {
+
+  if (!tree)
+    return;
+
+  splay_traverse(free_per_point_eqn, tree);
+  destroy_splaytree(tree);
+
+}
+
+void destroy_init_cond_tree(splaytree_t * tree) {
+
+  if (!tree)
+    return;
+
+  splay_traverse(free_init_cond, tree);
+  destroy_splaytree(tree);
+
+}
+
+void destroy_per_frame_eqn_tree(splaytree_t * tree) {
+
+
+  if (!tree)
+    return;
+
+  splay_traverse(free_per_frame_eqn, tree);
+  destroy_splaytree(tree);
+
+}
+
+
+void destroy_param_db_tree(splaytree_t * tree) {
+
+  if (!tree)
+    return;
+
+  splay_traverse(free_param, tree);
+  destroy_splaytree(tree);
+
+}
+
+/* Frees a custom wave form object */
+void free_custom_wave(custom_wave_t * custom_wave) {
+
+  if (custom_wave == NULL)
+    return;
+
+  if (custom_wave->param_tree == NULL)
+    return;
+
+  destroy_per_point_eqn_tree(custom_wave->per_point_eqn_tree);
+  destroy_per_frame_eqn_tree(custom_wave->per_frame_eqn_tree);
+  destroy_init_cond_tree(custom_wave->init_cond_tree);
+  destroy_param_db_tree(custom_wave->param_tree);
+  destroy_per_frame_init_eqn_tree(custom_wave->per_frame_init_eqn_tree);
+
+  free(custom_wave->r_mesh);
+  free(custom_wave->g_mesh);
+  free(custom_wave->b_mesh);
+  free(custom_wave->a_mesh);
+  free(custom_wave->x_mesh);
+  free(custom_wave->y_mesh);
+  free(custom_wave->value1);
+  free(custom_wave->value2);
+  free(custom_wave->sample_mesh);
+
+  free(custom_wave);
+
+  return;
+
+}
+
+
+
+int add_per_point_eqn(char * name, gen_expr_t * gen_expr, custom_wave_t * custom_wave) {
+
+  per_point_eqn_t * per_point_eqn;
+  int index;
+  param_t * param = NULL;
+
+  /* Argument checks */
+  if (custom_wave == NULL)
+         return FAILURE;
+  if (gen_expr == NULL)
+         return FAILURE;
+  if (name == NULL)
+         return FAILURE;
+  
+ if (CUSTOM_WAVE_DEBUG) printf("add_per_point_eqn: per pixel equation (name = \"%s\")\n", name);
+
+ /* Search for the parameter so we know what matrix the per pixel equation is referencing */
+
+ if ((param = find_param_db(name, custom_wave->param_tree, TRUE)) == NULL) {
+   if (CUSTOM_WAVE_DEBUG) printf("add_per_point_eqn: failed to allocate a new parameter!\n");
+   return FAILURE;
+ }      
+
+ /* Find most largest index in the splaytree */
+ if ((per_point_eqn = splay_find_max(custom_wave->per_point_eqn_tree)) == NULL)
+   index = 0;
+ else
+   index = per_point_eqn->index+1;
+
+ /* Create the per pixel equation given the index, parameter, and general expression */
+ if ((per_point_eqn = new_per_point_eqn(index, param, gen_expr)) == NULL)
+        return FAILURE;
+ if (CUSTOM_WAVE_DEBUG) 
+   printf("add_per_point_eqn: created new equation (index = %d) (name = \"%s\")\n", per_point_eqn->index, per_point_eqn->param->name);
+ /* Insert the per pixel equation into the preset per pixel database */
+ if (splay_insert(per_point_eqn, &per_point_eqn->index, custom_wave->per_point_eqn_tree) < 0) {
+       free_per_point_eqn(per_point_eqn);
+       return FAILURE;  
+ }
+        
+ /* Done */ 
+ return SUCCESS;
+}
+
+per_point_eqn_t * new_per_point_eqn(int index, param_t * param, gen_expr_t * gen_expr) {
+
+       per_point_eqn_t * per_point_eqn;
+       
+       if (param == NULL)
+               return NULL;
+       if (gen_expr == NULL)
+               return NULL;
+
+       if ((per_point_eqn = (per_point_eqn_t*)malloc(sizeof(per_point_eqn_t))) == NULL)
+               return NULL;
+
+      
+       per_point_eqn->index = index;
+       per_point_eqn->gen_expr = gen_expr;
+       per_point_eqn->param = param;
+       return per_point_eqn;   
+}
+
+
+void free_per_point_eqn(per_point_eqn_t * per_point_eqn) {
+
+       if (per_point_eqn == NULL)
+               return;
+       
+       free_gen_expr(per_point_eqn->gen_expr);
+       
+       free(per_point_eqn);
+       
+       return;
+}
+
+custom_wave_t * find_custom_wave(int id, preset_t * preset, int create_flag) {
+
+  custom_wave_t * custom_wave = NULL;
+
+  if (preset == NULL)
+    return NULL;
+  
+  if ((custom_wave = splay_find(&id, preset->custom_wave_tree)) == NULL) {
+
+    if (CUSTOM_WAVE_DEBUG) { printf("find_custom_wave: creating custom wave (id = %d)...", id);fflush(stdout);}
+
+    if (create_flag == FALSE) {
+      if (CUSTOM_WAVE_DEBUG) printf("you specified not to (create flag = false), returning null\n");
+       return NULL;
+    }
+
+    if ((custom_wave = new_custom_wave(id)) == NULL) {
+      if (CUSTOM_WAVE_DEBUG) printf("failed...out of memory?\n");
+      return NULL;
+    }
+
+    if  (CUSTOM_WAVE_DEBUG) {printf("success.Inserting..."); fflush(stdout);}
+
+   if (splay_insert(custom_wave, &custom_wave->id, preset->custom_wave_tree) < 0) {
+     if (CUSTOM_WAVE_DEBUG) printf("failed!\n");
+     free_custom_wave(custom_wave);
+     return NULL;
+    }
+   if (CUSTOM_WAVE_DEBUG) printf("done.\n");
+  }
+  return custom_wave;
+}
+
+inline void evalCustomWaveInitConditions() {
+  splay_traverse(eval_custom_wave_init_conds, active_preset->custom_wave_tree);
+}
+
+inline void eval_custom_wave_init_conds(custom_wave_t * custom_wave) {
+  splay_traverse(eval_init_cond, custom_wave->init_cond_tree);
+  splay_traverse(eval_init_cond, custom_wave->per_frame_init_eqn_tree);
+}
+
+/* Interface function. Makes another custom wave the current
+   concern for per frame / point equations */
+inline custom_wave_t * nextCustomWave() {
+
+  if ((interface_wave = splay_find(&interface_id, active_preset->custom_wave_tree)) == NULL) {
+    interface_id = 0;
+    return NULL;
+  }
+
+  interface_id++;
+
+  /* Evaluate all per frame equations associated with this wave */
+  splay_traverse(eval_per_frame_eqn, interface_wave->per_frame_eqn_tree);
+  return interface_wave;
+}
+
+
+inline void evalPerPointEqns() { 
+
+  int x;
+
+  for (x = 0; x < interface_wave->samples; x++)
+    interface_wave->r_mesh[x] = interface_wave->r;
+  for (x = 0; x < interface_wave->samples; x++)
+    interface_wave->g_mesh[x] = interface_wave->g;
+  for (x = 0; x < interface_wave->samples; x++)
+    interface_wave->b_mesh[x] = interface_wave->b;
+  for (x = 0; x < interface_wave->samples; x++)
+    interface_wave->a_mesh[x] = interface_wave->a;
+  for (x = 0; x < interface_wave->samples; x++)
+    interface_wave->x_mesh[x] = interface_wave->x;
+  for (x = 0; x < interface_wave->samples; x++)
+    interface_wave->y_mesh[x] = interface_wave->y;
+
+  /* Evaluate per pixel equations */
+  splay_traverse(evalPerPointEqn, interface_wave->per_point_eqn_tree);
+
+  /* Reset index */
+  mesh_i = -1;
+}
+
+/* Evaluates a per point equation for the current custom wave given by interface_wave ptr */
+inline void evalPerPointEqn(per_point_eqn_t * per_point_eqn) {
+  
+  
+  int samples, size;
+  double * param_matrix;
+  gen_expr_t * eqn_ptr;
+
+  samples = interface_wave->samples;
+  eqn_ptr = per_point_eqn->gen_expr;
+  if (per_point_eqn->param->matrix == NULL) {
+    if ((param_matrix = per_point_eqn->param->matrix = malloc(size = samples*sizeof(double))) == NULL)
+      return;
+    memset(param_matrix, 0, size);
+  }
+  else 
+    param_matrix = (double*)per_point_eqn->param->matrix;
+  
+  for (mesh_i = 0; mesh_i < samples; mesh_i++) {    
+      param_matrix[mesh_i] = eval_gen_expr(eqn_ptr);
+  }
+  
+  /* Now that this parameter has been referenced with a per
+     point equation, we let the evaluator know by setting
+     this flag */
+  per_point_eqn->param->matrix_flag = 1; 
+
+}
+
+
+void load_unspecified_init_conds(custom_wave_t * custom_wave) {
+
+  interface_wave = custom_wave;
+  splay_traverse(load_unspec_init_cond, interface_wave->param_tree);
+  interface_wave = NULL;
+}
+
+void load_unspec_init_cond(param_t * param) {
+
+  init_cond_t * init_cond;
+  value_t init_val;
+
+  /* Don't count these parameters as initial conditions */
+  if (param->flags & P_FLAG_READONLY)
+    return;
+  if (param->flags & P_FLAG_QVAR)
+    return;
+  if (param->flags & P_FLAG_TVAR)
+    return;
+  if (param->flags & P_FLAG_USERDEF)
+    return;
+
+  /* If initial condition was not defined by the preset file, force a default one
+     with the following code */
+  if ((init_cond = splay_find(param->name, interface_wave->init_cond_tree)) == NULL) {
+    
+    /* Make sure initial condition does not exist in the set of per frame initial equations */
+    if ((init_cond = splay_find(param->name, interface_wave->per_frame_init_eqn_tree)) != NULL)
+      return;
+    
+    if (param->type == P_TYPE_BOOL)
+      init_val.bool_val = 0;
+    
+    else if (param->type == P_TYPE_INT)
+      init_val.int_val = *(int*)param->engine_val;
+
+    else if (param->type == P_TYPE_DOUBLE)
+      init_val.double_val = *(double*)param->engine_val;
+
+    //printf("%s\n", param->name);
+    /* Create new initial condition */
+    if ((init_cond = new_init_cond(param, init_val)) == NULL)
+      return;
+    
+    /* Insert the initial condition into this presets tree */
+    if (splay_insert(init_cond, init_cond->param->name, interface_wave->init_cond_tree) < 0) {
+      free_init_cond(init_cond);
+      return;
+    }
+    
+  }
+}
diff --git a/modules/visualization/galaktos/custom_wave.h b/modules/visualization/galaktos/custom_wave.h
new file mode 100644 (file)
index 0000000..af330bf
--- /dev/null
@@ -0,0 +1,22 @@
+#ifndef CUSTOM_WAVE_H
+#define CUSTOM_WAVE_H
+#define CUSTOM_WAVE_DEBUG 0
+#include "expr_types.h"
+#include "custom_wave_types.h"
+#include "preset_types.h"
+
+void free_custom_wave(custom_wave_t * custom_wave);
+custom_wave_t * new_custom_wave(int id);
+
+void free_per_point_eqn(per_point_eqn_t * per_point_eqn);
+per_point_eqn_t * new_per_point_eqn(int index, param_t * param,gen_expr_t * gen_expr);
+void reset_per_point_eqn_array(custom_wave_t * custom_wave);
+custom_wave_t * find_custom_wave(int id, preset_t * preset, int create_flag);
+
+int add_per_point_eqn(char * name, gen_expr_t * gen_expr, custom_wave_t * custom_wave);
+inline void evalCustomWaveInitConditions();
+inline void evalPerPointEqns();
+inline custom_wave_t * nextCustomWave();
+void load_unspecified_init_conds(custom_wave_t * custom_wave);
+
+#endif
diff --git a/modules/visualization/galaktos/custom_wave_types.h b/modules/visualization/galaktos/custom_wave_types.h
new file mode 100644 (file)
index 0000000..3148181
--- /dev/null
@@ -0,0 +1,92 @@
+#ifndef CUSTOM_WAVE_TYPES_H
+#define CUSTOM_WAVE_TYPES_H
+#include "common.h"
+#include "splaytree_types.h"
+#include "expr_types.h"
+
+#define X_POINT_OP 0
+#define Y_POINT_OP 1
+#define R_POINT_OP 2
+#define G_POINT_OP 3
+#define B_POINT_OP 4
+#define A_POINT_OP 5
+#define NUM_POINT_OPS 6
+
+typedef struct PER_POINT_EQN_T {
+  int index;
+  param_t * param;
+  gen_expr_t * gen_expr;       
+} per_point_eqn_t;
+
+typedef struct CUSTOM_WAVE_T {
+
+  /* Numerical id */
+  int id;
+  int per_frame_count;
+
+  /* Parameter tree associated with this custom wave */
+  splaytree_t * param_tree;
+
+
+  /* Engine variables */
+
+  double x; /* x position for per point equations */
+  double y; /* y position for per point equations */
+  double r; /* red color value */
+  double g; /* green color value */
+  double b; /* blue color value */
+  double a; /* alpha color value */
+  double * x_mesh;
+  double * y_mesh;
+  double * r_mesh;
+  double * b_mesh;
+  double * g_mesh;
+  double * a_mesh;
+  double * value1;
+  double * value2;
+  double * sample_mesh;
+
+  int enabled; /* if nonzero then wave is visible, hidden otherwise */
+  int samples; /* number of samples associated with this wave form. Usually powers of 2 */
+  double sample;
+  int bSpectrum; /* spectrum data or pcm data */
+  int bUseDots; /* draw wave as dots or lines */
+  int bDrawThick; /* draw thicker lines */
+  int bAdditive; /* add color values together */
+
+  double scaling; /* scale factor of waveform */
+  double smoothing; /* smooth factor of waveform */
+  int sep;  /* no idea what this is yet... */
+
+  /* stupid t variables */
+  double t1;
+  double t2;
+  double t3;
+  double t4;
+  double t5;
+  double t6;
+  double t7;
+  double t8;
+  double v1,v2;
+  /* Data structure to hold per frame and per point equations */
+  splaytree_t * init_cond_tree;
+  splaytree_t * per_frame_eqn_tree;
+  splaytree_t * per_point_eqn_tree;
+  splaytree_t * per_frame_init_eqn_tree;
+
+  /* Denotes the index of the last character for each string buffer */
+  int per_point_eqn_string_index;
+  int per_frame_eqn_string_index;
+  int per_frame_init_eqn_string_index;
+
+  /* String buffers for per point and per frame equations */
+  char per_point_eqn_string_buffer[STRING_BUFFER_SIZE];
+  char per_frame_eqn_string_buffer[STRING_BUFFER_SIZE];
+  char per_frame_init_eqn_string_buffer[STRING_BUFFER_SIZE];
+  /* Per point equation array */
+  gen_expr_t * per_point_eqn_array[NUM_POINT_OPS];
+  
+} custom_wave_t;
+
+
+#endif
diff --git a/modules/visualization/galaktos/engine_vars.c b/modules/visualization/galaktos/engine_vars.c
new file mode 100644 (file)
index 0000000..9ad71a5
--- /dev/null
@@ -0,0 +1,166 @@
+/*****************************************************************************
+ * engine_vars.c:
+ *****************************************************************************
+ * Copyright (C) 2004 VideoLAN
+ * $Id$
+ *
+ * Authors: Cyril Deguet <asmax@videolan.org>
+ *          code from projectM http://xmms-projectm.sourceforge.net
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ *****************************************************************************/
+
+
+
+/* Include engine_vars.h to use these variables */
+ char preset_name[256];
+/* PER FRAME CONSTANTS BEGIN */
+ double zoom=1.0;
+ double zoomexp= 1.0;
+ double rot= 0.0;
+ double warp= 0.0;
+
+ double sx= 1.0;
+ double sy= 1.0;
+ double dx= 0.0;
+ double dy= 0.0;
+ double cx= 0.5;
+ double cy= 0.5;
+
+  int gx = 32;
+  int gy = 24;
+
+ double decay=.98;
+
+ double wave_r= 1.0;
+ double wave_g= 0.2;
+ double wave_b= 0.0;
+ double wave_x= 0.5;
+ double wave_y= 0.5;
+ double wave_mystery= 0.0;
+
+ double ob_size= 0.0;
+ double ob_r= 0.0;
+ double ob_g= 0.0;
+ double ob_b= 0.0;
+ double ob_a= 0.0;
+
+ double ib_size = 0.0;
+ double ib_r = 0.0;
+ double ib_g = 0.0;
+ double ib_b = 0.0;
+ double ib_a = 0.0;
+
+ double mv_a = 0.0;
+ double mv_r = 0.0;
+ double mv_g = 0.0;
+ double mv_b = 0.0;
+ double mv_l = 1.0;
+ double mv_x = 16.0;
+ double mv_y = 12.0;
+ double mv_dy = 0.02;
+ double mv_dx = 0.02;
+  
+ int meshx = 0;
+ int meshy = 0;
+ double Time = 0;
+ double treb = 0;
+ double mid = 0;
+ double bass = 0;
+ double treb_att = 0;
+ double mid_att = 0;
+ double bass_att = 0;
+ double progress = 0;
+ int frame = 0;
+ int fps = 30;
+//double bass_thresh = 0;
+
+/* PER_FRAME CONSTANTS END */
+ double fRating = 0;
+ double fGammaAdj = 1.0;
+ double fVideoEchoZoom = 1.0;
+ double fVideoEchoAlpha = 0;
+ double nVideoEchoOrientation = 0;
+ int nWaveMode = 7;
+ int bAdditiveWaves = 0;
+ int bWaveDots = 0;
+ int bWaveThick = 0;
+ int bModWaveAlphaByVolume = 0;
+ int bMaximizeWaveColor = 0;
+ int bTexWrap = 0;
+ int bDarkenCenter = 0;
+ int bRedBlueStereo = 0;
+ int bBrighten = 0;
+ int bDarken = 0;
+ int bSolarize = 0;
+int bInvert = 0;
+int bMotionVectorsOn = 1;
+ double fWaveAlpha =1.0;
+ double fWaveScale = 1.0;
+ double fWaveSmoothing = 0;
+ double fWaveParam = 0;
+ double fModWaveAlphaStart = 0;
+ double fModWaveAlphaEnd = 0;
+ double fWarpAnimSpeed = 0;
+ double fWarpScale = 0;
+ double fShader = 0;
+
+
+/* PER_PIXEL CONSTANTS BEGIN */
+double x_per_pixel = 0;
+double y_per_pixel = 0;
+double rad_per_pixel = 0;
+double ang_per_pixel = 0;
+
+/* PER_PIXEL CONSTANT END */
+
+
+/* Q AND T VARIABLES START */
+
+double q1 = 0;
+double q2 = 0;
+double q3 = 0;
+double q4 = 0;
+double q5 = 0;
+double q6 = 0;
+double q7 = 0;
+double q8 = 0;
+
+
+/* Q AND T VARIABLES END */
+
+//per pixel meshes
+ double **zoom_mesh;
+ double **zoomexp_mesh;
+ double **rot_mesh;
+
+ double **sx_mesh;
+ double **sy_mesh;
+ double **dx_mesh;
+ double **dy_mesh;
+ double **cx_mesh;
+ double **cy_mesh;
+
+ double **x_mesh;
+ double **y_mesh;
+ double **rad_mesh;
+ double **theta_mesh;
+
+//custom wave per point meshes
+
diff --git a/modules/visualization/galaktos/engine_vars.h b/modules/visualization/galaktos/engine_vars.h
new file mode 100644 (file)
index 0000000..3854d3d
--- /dev/null
@@ -0,0 +1,142 @@
+/* Temporay file until these variables are all externed */
+#ifndef ENGINE_VARS_H
+#define ENGINE_VARS_H
+
+extern char preset_name[256];
+
+/* PER FRAME CONSTANTS BEGIN */
+extern double zoom;
+extern double zoomexp;
+extern double rot;
+extern double warp;
+
+extern double sx;
+extern double sy;
+extern double dx;
+extern double dy;
+extern double cx;
+extern double cy;
+
+extern int gy;
+extern int gx;
+
+extern double decay;
+
+extern double wave_r;
+extern double wave_g;
+extern double wave_b;
+extern double wave_x;
+extern double wave_y;
+extern double wave_mystery;
+
+extern double ob_size;
+extern double ob_r;
+extern double ob_g;
+extern double ob_b;
+extern double ob_a;
+
+extern double ib_size;
+extern double ib_r;
+extern double ib_g;
+extern double ib_b;
+extern double ib_a;
+
+extern int meshx;
+extern int meshy;
+
+extern double mv_a ;
+extern double mv_r ;
+extern double mv_g ;
+extern double mv_b ;
+extern double mv_l;
+extern double mv_x;
+extern double mv_y;
+extern double mv_dy;
+extern double mv_dx;
+
+extern double Time;
+extern double treb ;
+extern double mid ;
+extern double bass ;
+extern double treb_att ;
+extern double mid_att ;
+extern double bass_att ;
+extern double progress ;
+extern int frame ;
+
+/* PER_FRAME CONSTANTS END */
+
+/* PER_PIXEL CONSTANTS BEGIN */
+
+extern double x_per_pixel;
+extern double y_per_pixel;
+extern double rad_per_pixel;
+extern double ang_per_pixel;
+
+/* PER_PIXEL CONSTANT END */
+
+
+extern double fRating;
+extern double fGammaAdj;
+extern double fVideoEchoZoom;
+extern double fVideoEchoAlpha;
+
+extern int nVideoEchoOrientation;
+extern int nWaveMode;
+extern int bAdditiveWaves;
+extern int bWaveDots;
+extern int bWaveThick;
+extern int bModWaveAlphaByVolume;
+extern int bMaximizeWaveColor;
+extern int bTexWrap;
+extern int bDarkenCenter;
+extern int bRedBlueStereo;
+extern int bBrighten;
+extern int bDarken;
+extern int bSolarize;
+extern int bInvert;
+extern int bMotionVectorsOn;
+extern int fps; 
+
+extern double fWaveAlpha ;
+extern double fWaveScale;
+extern double fWaveSmoothing;
+extern double fWaveParam;
+extern double fModWaveAlphaStart;
+extern double fModWaveAlphaEnd;
+extern double fWarpAnimSpeed;
+extern double fWarpScale;
+extern double fShader;
+
+
+/* Q VARIABLES START */
+
+extern double q1;
+extern double q2;
+extern double q3;
+extern double q4;
+extern double q5;
+extern double q6;
+extern double q7;
+extern double q8;
+
+
+/* Q VARIABLES END */
+
+extern double **zoom_mesh;
+extern double **zoomexp_mesh;
+extern double **rot_mesh;
+
+extern double **sx_mesh;
+extern double **sy_mesh;
+extern double **dx_mesh;
+extern double **dy_mesh;
+extern double **cx_mesh;
+extern double **cy_mesh;
+
+extern double **x_mesh;
+extern double **y_mesh;
+extern double **rad_mesh;
+extern double **theta_mesh;
+
+#endif
diff --git a/modules/visualization/galaktos/eval.c b/modules/visualization/galaktos/eval.c
new file mode 100644 (file)
index 0000000..608bae6
--- /dev/null
@@ -0,0 +1,785 @@
+/*****************************************************************************
+ * eval.c:
+ *****************************************************************************
+ * Copyright (C) 2004 VideoLAN
+ * $Id$
+ *
+ * Authors: Cyril Deguet <asmax@videolan.org>
+ *          code from projectM http://xmms-projectm.sourceforge.net
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ *****************************************************************************/
+
+
+
+/* Evaluation Code */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "common.h"
+#include "fatal.h"
+
+#include "param_types.h"
+#include "func_types.h"
+#include "expr_types.h"
+#include "eval.h"
+#include "engine_vars.h"
+#include "builtin_funcs.h"
+#define EVAL_ERROR -1
+
+/* All infix operators (except '=') are prototyped here */
+infix_op_t * infix_add, * infix_minus, * infix_div, * infix_mult,
+  * infix_or, * infix_and, * infix_mod, * infix_negative, * infix_positive;
+int mesh_i=-1, mesh_j=-1;
+
+static inline double eval_tree_expr(tree_expr_t * tree_expr);
+static inline double eval_prefun_expr(prefun_expr_t * prefun_expr);
+static inline double eval_val_expr(val_expr_t * val_expr);
+
+
+inline double eval_gen_expr(gen_expr_t * gen_expr) {
+  double l;
+
+  if (gen_expr == NULL) 
+       return 0;
+       
+  switch(gen_expr->type) {
+  case VAL_T:  
+    return eval_val_expr(gen_expr->item);
+  case PREFUN_T:
+    l = eval_prefun_expr(gen_expr->item);
+    //if (EVAL_DEBUG) printf("eval_gen_expr: prefix function return value: %f\n", l);
+    return l;          
+  case TREE_T:
+    return eval_tree_expr(gen_expr->item);
+  default:
+    #ifdef EVAL_DEBUG
+    printf("eval_gen_expr: general expression matched no cases!\n");
+    #endif
+    return EVAL_ERROR;
+  }  
+       
+}
+
+/* Evaluates functions in prefix form */
+static inline double eval_prefun_expr(prefun_expr_t * prefun_expr) {
+       int i;
+       
+       
+       /* This is slightly less than safe, since
+          who knows if the passed argument is valid. For 
+          speed purposes we'll go with this */
+       double arg_list[prefun_expr->num_args];
+       
+       #ifdef EVAL_DEBUG 
+               printf("fn[");
+               fflush(stdout);
+       #endif
+       /* Evaluate each argument before calling the function itself */
+       for (i = 0; i < prefun_expr->num_args; i++) {
+               arg_list[i] = eval_gen_expr(prefun_expr->expr_list[i]);
+               #ifdef EVAL_DEBUG 
+                       if (i < (prefun_expr->num_args - 1))
+                               printf(", ");
+                       fflush(stdout);
+               #endif
+       }
+       
+       #ifdef EVAL_DEBUG 
+               printf("]");
+               fflush(stdout);
+       #endif
+       
+       /* Now we call the function, passing a list of  
+          doubles as its argument */
+     
+
+     
+       return (prefun_expr->func_ptr)(arg_list);       
+}      
+
+/* Evaluates a value expression */
+static inline double eval_val_expr(val_expr_t * val_expr) {
+
+  /* Shouldn't happen */
+  if (val_expr == NULL)
+    return EVAL_ERROR;
+
+  /* Value is a constant, return the double value */
+  if (val_expr->type == CONSTANT_TERM_T) {
+    #ifdef EVAL_DEBUG 
+               printf("%.4f", val_expr->term.constant);
+               fflush(stdout);
+    #endif
+    return (val_expr->term.constant);
+  }
+
+  /* Value is variable, dereference it */
+  if (val_expr->type == PARAM_TERM_T) {
+       switch (val_expr->term.param->type) {
+               
+       case P_TYPE_BOOL:
+               #ifdef EVAL_DEBUG 
+                       printf("(%s:%.4f)", val_expr->term.param->name, (double)(*((int*)(val_expr->term.param->engine_val))));
+                       fflush(stdout);
+               #endif
+              
+                 
+               return (double)(*((int*)(val_expr->term.param->engine_val)));
+       case P_TYPE_INT:
+               #ifdef EVAL_DEBUG 
+                       printf("(%s:%.4f)", val_expr->term.param->name, (double)(*((int*)(val_expr->term.param->engine_val))));
+                       fflush(stdout);
+               #endif
+
+            
+               return (double)(*((int*)(val_expr->term.param->engine_val)));
+       case P_TYPE_DOUBLE:             
+               #ifdef EVAL_DEBUG 
+                       printf("(%s:%.4f)", val_expr->term.param->name, (*((double*)val_expr->term.param->engine_val)));
+                       fflush(stdout);
+               #endif
+                       
+               if (val_expr->term.param->matrix_flag | (val_expr->term.param->flags & P_FLAG_ALWAYS_MATRIX)) {
+                 if (mesh_j >= 0) {
+                   return (((double**)val_expr->term.param->matrix)[mesh_i][mesh_j]);
+                 }
+                 else {
+                   return (((double*)val_expr->term.param->matrix)[mesh_i]);
+                 }
+               }
+               return *((double*)(val_expr->term.param->engine_val));
+       default:
+         return ERROR; 
+    }
+  }
+  /* Unknown type, return failure */
+  return FAILURE;
+}
+
+/* Evaluates an expression tree */
+static inline double eval_tree_expr(tree_expr_t * tree_expr) {
+               
+       double left_arg, right_arg;     
+       infix_op_t * infix_op;
+       
+       /* Shouldn't happen */
+       if (tree_expr == NULL)
+         return EVAL_ERROR;
+
+       /* A leaf node, evaluate the general expression. If the expression is null as well, return zero */
+       if (tree_expr->infix_op == NULL) {
+               if (tree_expr->gen_expr == NULL)
+                       return 0;
+               else
+                       return eval_gen_expr(tree_expr->gen_expr);
+       }
+       
+       /* Otherwise, this node is an infix operator. Evaluate
+          accordingly */
+       
+       infix_op = (infix_op_t*)tree_expr->infix_op;    
+       #ifdef EVAL_DEBUG 
+               printf("(");
+               fflush(stdout);
+       #endif
+       
+       left_arg = eval_tree_expr(tree_expr->left);
+
+       #ifdef EVAL_DEBUG 
+               
+               switch (infix_op->type) {
+               case INFIX_ADD:
+                       printf("+");
+                       break;          
+               case INFIX_MINUS:
+                       printf("-");
+                       break;
+               case INFIX_MULT:
+                       printf("*");
+                       break;
+               case INFIX_MOD:
+                       printf("%%");
+                       break;
+               case INFIX_OR:
+                       printf("|");
+                       break;
+               case INFIX_AND:
+                       printf("&");
+                       break;
+               case INFIX_DIV:
+                       printf("/");
+                       break;
+               default:
+                       printf("?");
+               }
+       
+       fflush(stdout); 
+       #endif
+       
+       right_arg = eval_tree_expr(tree_expr->right);
+       
+       #ifdef EVAL_DEBUG
+               printf(")");
+               fflush(stdout);
+       #endif
+       
+       switch (infix_op->type) {               
+       case INFIX_ADD:
+         return (left_arg + right_arg);                
+       case INFIX_MINUS:
+               return (left_arg - right_arg);
+       case INFIX_MULT:
+               return (left_arg * right_arg);
+       case INFIX_MOD:
+         if ((int)right_arg == 0) {
+           #ifdef EVAL_DEBUG 
+           printf("eval_tree_expr: modulo zero!\n");
+           #endif
+           return DIV_BY_ZERO; 
+         }
+         return ((int)left_arg % (int)right_arg);
+       case INFIX_OR:
+               return ((int)left_arg | (int)right_arg);
+       case INFIX_AND:
+               return ((int)left_arg & (int)right_arg);
+       case INFIX_DIV:
+         if (right_arg == 0) {
+           #ifdef EVAL_DEBUG 
+           printf("eval_tree_expr: division by zero!\n");
+           #endif
+           return MAX_DOUBLE_SIZE;
+         }             
+         return (left_arg / right_arg);
+       default:
+          #ifdef EVAL_DEBUG 
+           printf("eval_tree_expr: unknown infix operator!\n");
+          #endif
+               return ERROR;
+       }
+       
+       return ERROR;
+}      
+
+/* Converts a double value to a general expression */
+gen_expr_t * const_to_expr(double val) {
+
+  gen_expr_t * gen_expr;
+  val_expr_t * val_expr;
+  term_t term;
+  
+  term.constant = val;
+    
+  if ((val_expr = new_val_expr(CONSTANT_TERM_T, term)) == NULL)
+    return NULL;
+
+  gen_expr = new_gen_expr(VAL_T, (void*)val_expr);
+
+  if (gen_expr == NULL) {
+       free_val_expr(val_expr);
+  }
+  
+  return gen_expr;
+}
+
+/* Converts a regular parameter to an expression */
+gen_expr_t * param_to_expr(param_t * param) {
+
+  gen_expr_t * gen_expr = NULL;
+  val_expr_t * val_expr = NULL;
+  term_t term;
+
+  if (param == NULL)
+    return NULL;
+  /* This code is still a work in progress. We need
+     to figure out if the initial condition is used for 
+     each per frame equation or not. I am guessing that
+     it isn't, and it is thusly implemented this way */
+  
+  /* Current guess of true behavior (08/01/03) note from carm
+     First try to use the per_pixel_expr (with cloning). 
+     If it is null however, use the engine variable instead. */
+  
+  /* 08/20/03 : Presets are now objects, as well as per pixel equations. This ends up
+     making the parser handle the case where parameters are essentially per pixel equation
+     substitutions */
+       
+  
+  term.param = param;
+  if ((val_expr = new_val_expr(PARAM_TERM_T, term)) == NULL)
+    return NULL;
+  
+  if ((gen_expr = new_gen_expr(VAL_T, (void*)val_expr)) == NULL) {
+    free_val_expr(val_expr);
+       return NULL;      
+  } 
+  return gen_expr;
+}
+
+/* Converts a prefix function to an expression */
+gen_expr_t * prefun_to_expr(double (*func_ptr)(), gen_expr_t ** expr_list, int num_args) {
+
+  gen_expr_t * gen_expr;
+  prefun_expr_t * prefun_expr;
+  
+
+  /* Malloc a new prefix function expression */
+  prefun_expr = (prefun_expr_t*)malloc(sizeof(prefun_expr_t));
+
+  if (prefun_expr == NULL)
+         return NULL;
+  
+  prefun_expr->num_args = num_args;
+  prefun_expr->func_ptr = func_ptr;
+  prefun_expr->expr_list = expr_list;
+
+  gen_expr = new_gen_expr(PREFUN_T, (void*)prefun_expr);
+
+  if (gen_expr == NULL)
+         free_prefun_expr(prefun_expr);
+  
+  return gen_expr;
+}
+
+/* Creates a new tree expression */
+tree_expr_t * new_tree_expr(infix_op_t * infix_op, gen_expr_t * gen_expr, tree_expr_t * left, tree_expr_t * right) {
+
+               tree_expr_t * tree_expr;
+               tree_expr = (tree_expr_t*)malloc(sizeof(tree_expr_t));
+       
+               if (tree_expr == NULL)
+                       return NULL;
+               tree_expr->infix_op = infix_op;
+               tree_expr->gen_expr = gen_expr;
+               tree_expr->left = left;
+               tree_expr->right = right;
+               return tree_expr;
+}
+
+
+/* Creates a new value expression */
+val_expr_t * new_val_expr(int type, term_t term) {
+
+  val_expr_t * val_expr;
+  val_expr = (val_expr_t*)malloc(sizeof(val_expr_t));
+
+  if (val_expr == NULL)
+    return NULL;
+
+  val_expr->type = type;
+  val_expr->term = term;
+
+  return val_expr;
+}
+
+/* Creates a new general expression */
+gen_expr_t * new_gen_expr(int type, void * item) {
+
+       gen_expr_t * gen_expr;
+
+       gen_expr = (gen_expr_t*)malloc(sizeof(gen_expr_t));
+       if (gen_expr == NULL)
+               return NULL;
+       gen_expr->type = type;
+       gen_expr->item = item;  
+
+       return gen_expr;
+}
+
+/* Frees a general expression */
+int free_gen_expr(gen_expr_t * gen_expr) {
+
+       if (gen_expr == NULL)
+               return SUCCESS;
+       
+       switch (gen_expr->type) {
+       case VAL_T:
+               free_val_expr(gen_expr->item);
+               break;
+       case PREFUN_T:
+               free_prefun_expr(gen_expr->item);
+               break;
+       case TREE_T:
+               free_tree_expr(gen_expr->item);
+               break;
+       default:
+               return FAILURE;
+       }       
+
+       free(gen_expr);
+       return SUCCESS;
+
+}
+
+
+/* Frees a function in prefix notation */
+int free_prefun_expr(prefun_expr_t * prefun_expr) {
+
+       int i;
+       if (prefun_expr == NULL)
+               return SUCCESS;
+       
+       /* Free every element in expression list */
+       for (i = 0 ; i < prefun_expr->num_args; i++) {
+               free_gen_expr(prefun_expr->expr_list[i]);
+       }
+
+       free(prefun_expr);
+       return SUCCESS;
+}
+
+/* Frees values of type VARIABLE and CONSTANT */
+int free_val_expr(val_expr_t * val_expr) {
+
+       if (val_expr == NULL)
+               return SUCCESS; 
+       
+       free(val_expr);
+       return SUCCESS;
+}
+
+/* Frees a tree expression */
+int free_tree_expr(tree_expr_t * tree_expr) {
+
+       if (tree_expr == NULL)
+               return SUCCESS;
+       
+       /* free left tree */
+       free_tree_expr(tree_expr->left);
+       
+       /* free general expression object */
+       free_gen_expr(tree_expr->gen_expr);
+       
+       /* Note that infix operators are always
+          stored in memory unless the program 
+          exits, so we don't remove them here */
+       
+       /* free right tree */
+       free_tree_expr(tree_expr->right);
+       
+       
+       /* finally, free the struct itself */
+       free(tree_expr);
+       return SUCCESS;
+}
+
+
+
+/* Initializes all infix operators */
+int init_infix_ops() {
+
+       infix_add = new_infix_op(INFIX_ADD, 4);
+       infix_minus = new_infix_op(INFIX_MINUS, 3);
+       infix_div = new_infix_op(INFIX_DIV, 2);
+       infix_or = new_infix_op(INFIX_OR, 5);
+       infix_and = new_infix_op(INFIX_AND,4);
+       infix_mod = new_infix_op(INFIX_MOD, 1);
+       infix_mult = new_infix_op(INFIX_MULT, 2);
+       
+       /* Prefix operators */
+       infix_positive = new_infix_op(INFIX_ADD, 0);
+       infix_negative = new_infix_op(INFIX_MINUS, 0);
+
+       return SUCCESS;
+}
+
+/* Destroys the infix operator list. This should
+   be done on program exit */
+int destroy_infix_ops()
+{
+
+  free(infix_add);
+  free(infix_minus);
+  free(infix_div);
+  free(infix_or);
+  free(infix_and);
+  free(infix_mod);
+  free(infix_mult);
+  free(infix_positive);
+  free(infix_negative);
+
+  return SUCCESS;
+}
+
+/* Initializes an infix operator */
+infix_op_t * new_infix_op(int type, int precedence) {
+
+       infix_op_t * infix_op;
+       
+       infix_op = (infix_op_t*)malloc(sizeof(infix_op_t));
+       
+       if (infix_op == NULL)
+               return NULL;
+       
+       infix_op->type = type;
+       infix_op->precedence = precedence;
+       
+       return infix_op;
+}
+
+
+
+
+/* Clones a general expression */
+gen_expr_t * clone_gen_expr(gen_expr_t * gen_expr) {
+
+  gen_expr_t * new_gen_expr;
+  val_expr_t * val_expr;
+  tree_expr_t * tree_expr;
+  prefun_expr_t * prefun_expr;
+
+  /* Null argument check */
+  if (gen_expr == NULL)
+    return NULL;
+
+  /* Out of memory */
+  if ((new_gen_expr = (gen_expr_t*)malloc(sizeof(gen_expr_t))) == NULL)
+    return NULL;
+
+  /* Case on the type of general expression */
+  switch (new_gen_expr->type = gen_expr->type) {
+
+  case VAL_T: /* val expression */
+    if ((val_expr = clone_val_expr((val_expr_t*)gen_expr->item)) == NULL) {
+      free(new_gen_expr);
+      return NULL;
+    }
+    new_gen_expr->item = (void*)val_expr;
+    break;
+    
+  case PREFUN_T: /* prefix function expression */
+    if ((prefun_expr = clone_prefun_expr((prefun_expr_t*)gen_expr->item)) == NULL) {
+      free(new_gen_expr);
+      return NULL;
+    }
+    new_gen_expr->item = (void*)prefun_expr;
+    break;
+    
+  case TREE_T:  /* tree expression */
+    if ((tree_expr = clone_tree_expr((tree_expr_t*)gen_expr->item)) == NULL) {
+      free(new_gen_expr);
+      return NULL;
+    }
+    new_gen_expr->item = (void*)tree_expr;
+    break;
+    
+  default: /* unknown type, ut oh.. */
+    free(new_gen_expr);
+    return NULL;
+  }
+  
+  return new_gen_expr; /* Return the new (cloned) general expression */
+}
+
+
+/* Clones a tree expression */
+tree_expr_t * clone_tree_expr(tree_expr_t * tree_expr) {
+
+  tree_expr_t * new_tree_expr;
+
+  /* Null argument */
+  if (tree_expr == NULL)
+    return NULL;
+  
+  /* Out of memory */
+  if ((new_tree_expr = (tree_expr_t*)malloc(sizeof(tree_expr_t))) == NULL) 
+    return NULL;
+  
+  /* Set each argument in tree_expr_t struct */
+  new_tree_expr->infix_op = tree_expr->infix_op;  /* infix operators are in shared memory */
+  new_tree_expr->gen_expr = clone_gen_expr(tree_expr->gen_expr); /* clone the general expression */
+  new_tree_expr->left = clone_tree_expr(tree_expr->left); /* clone the left tree expression */
+  new_tree_expr->right = clone_tree_expr(tree_expr->right); /* clone the right tree expression */
+
+  return new_tree_expr; /* Return the new (cloned) tree expression */
+}
+
+/* Clones a value expression, currently only passes the pointer to 
+   the value that this object represents, not a pointer to a copy of the value */
+val_expr_t * clone_val_expr(val_expr_t * val_expr) {
+
+  val_expr_t * new_val_expr;
+
+  /* Null argument */
+  if (val_expr == NULL)
+    return NULL;
+  
+  /* Allocate space, check for out of memory */
+  if ((new_val_expr = (val_expr_t*)malloc(sizeof(val_expr_t))) == NULL) 
+    return NULL;
+
+  /* Set the values in the val_expr_t struct */
+  new_val_expr->type = val_expr->type;
+  new_val_expr->term = val_expr->term;
+  
+  /* Return the new (cloned) value expression */
+  return new_val_expr;
+}
+
+/* Clones a prefix function with its arguments */
+prefun_expr_t * clone_prefun_expr(prefun_expr_t * prefun_expr) {
+
+  int i;
+  prefun_expr_t * new_prefun_expr;
+  
+  /* Null argument */
+  if (prefun_expr == NULL)
+    return NULL;
+  
+  /* Out of memory */
+  if ((new_prefun_expr = (prefun_expr_t*)malloc(sizeof(prefun_expr_t))) == NULL) 
+    return NULL;
+  
+  /* Set the function argument paired with its number of arguments */
+  new_prefun_expr->num_args = prefun_expr->num_args;
+  new_prefun_expr->func_ptr = prefun_expr->func_ptr;
+
+  /* Allocate space for the expression list pointers */
+  if ((new_prefun_expr->expr_list = (gen_expr_t**)malloc(sizeof(gen_expr_t*)*new_prefun_expr->num_args)) == NULL) {
+    free(new_prefun_expr);
+    return NULL;
+  }
+
+  /* Now copy each general expression from the argument expression list */
+  for (i = 0; i < new_prefun_expr->num_args;i++) 
+    new_prefun_expr->expr_list[i] = clone_gen_expr(prefun_expr->expr_list[i]);
+  
+  /* Finally, return the new (cloned) prefix function expression */
+  return new_prefun_expr;
+}
+
+/* Reinitializes the engine variables to a default (conservative and sane) value */
+void reset_engine_vars() {
+
+  zoom=1.0;
+  zoomexp= 1.0;
+  rot= 0.0;
+  warp= 0.0;
+  
+  sx= 1.0;
+  sy= 1.0;
+  dx= 0.0;
+  dy= 0.0;
+  cx= 0.5;
+  cy= 0.5;
+
+  
+  decay=.98;
+  
+  wave_r= 1.0;
+  wave_g= 0.2;
+  wave_b= 0.0;
+  wave_x= 0.5;
+  wave_y= 0.5;
+  wave_mystery= 0.0;
+
+  ob_size= 0.0;
+  ob_r= 0.0;
+  ob_g= 0.0;
+  ob_b= 0.0;
+  ob_a= 0.0;
+
+  ib_size = 0.0;
+  ib_r = 0.0;
+  ib_g = 0.0;
+  ib_b = 0.0;
+  ib_a = 0.0;
+
+  mv_a = 0.0;
+  mv_r = 0.0;
+  mv_g = 0.0;
+  mv_b = 0.0;
+  mv_l = 1.0;
+  mv_x = 16.0;
+  mv_y = 12.0;
+  mv_dy = 0.02;
+  mv_dx = 0.02;
+  
+  meshx = 0;
+  meshy = 0;
+  Time = 0;
+  treb = 0;
+  mid = 0;
+  bass = 0;
+  treb_att = 0;
+  mid_att = 0;
+  bass_att = 0;
+  progress = 0;
+  frame = 0;
+
+// bass_thresh = 0;
+
+/* PER_FRAME CONSTANTS END */
+  fRating = 0;
+  fGammaAdj = 1.0;
+  fVideoEchoZoom = 1.0;
+  fVideoEchoAlpha = 0;
+  nVideoEchoOrientation = 0;
+  nWaveMode = 7;
+  bAdditiveWaves = 0;
+  bWaveDots = 0;
+  bWaveThick = 0;
+  bModWaveAlphaByVolume = 0;
+  bMaximizeWaveColor = 0;
+  bTexWrap = 0;
+  bDarkenCenter = 0;
+  bRedBlueStereo = 0;
+  bBrighten = 0;
+  bDarken = 0;
+  bSolarize = 0;
+ bInvert = 0;
+ bMotionVectorsOn = 1;
+  fWaveAlpha =1.0;
+  fWaveScale = 1.0;
+  fWaveSmoothing = 0;
+  fWaveParam = 0;
+  fModWaveAlphaStart = 0;
+  fModWaveAlphaEnd = 0;
+  fWarpAnimSpeed = 0;
+  fWarpScale = 0;
+  fShader = 0;
+
+
+/* PER_PIXEL CONSTANTS BEGIN */
+ x_per_pixel = 0;
+ y_per_pixel = 0;
+ rad_per_pixel = 0;
+ ang_per_pixel = 0;
+
+/* PER_PIXEL CONSTANT END */
+
+
+/* Q VARIABLES START */
+
+ q1 = 0;
+ q2 = 0;
+ q3 = 0;
+ q4 = 0;
+ q5 = 0;
+ q6 = 0;
+ q7 = 0;
+ q8 = 0;
+
+
+ /* Q VARIABLES END */
+
+
+}
+
+
diff --git a/modules/visualization/galaktos/eval.h b/modules/visualization/galaktos/eval.h
new file mode 100644 (file)
index 0000000..60ae143
--- /dev/null
@@ -0,0 +1,55 @@
+/* eval.h: evaluation functions of expressions */
+#ifndef EVAL_H
+#define EVAL_H
+#include "func_types.h"
+#include "param_types.h"
+
+#define VAL_T 1
+#define PREFUN_T 3
+#define TREE_T 4
+#define NONE_T 0
+
+
+#define CONSTANT_TERM_T 0
+#define PARAM_TERM_T 1
+
+#define INFIX_ADD 0
+#define INFIX_MINUS 1
+#define INFIX_MOD 2
+#define INFIX_DIV 3
+#define INFIX_MULT 4
+#define INFIX_OR 5
+#define INFIX_AND 6
+
+//#define EVAL_DEBUG 
+
+
+inline double eval_gen_expr(gen_expr_t * gen_expr);
+inline gen_expr_t * opt_gen_expr(gen_expr_t * gen_expr, int ** param_list);
+
+gen_expr_t * const_to_expr(double val);
+gen_expr_t * param_to_expr(struct PARAM_T * param);
+gen_expr_t * prefun_to_expr(double (*func_ptr)(), gen_expr_t ** expr_list, int num_args);
+
+tree_expr_t * new_tree_expr(infix_op_t * infix_op, gen_expr_t * gen_expr, tree_expr_t * left, tree_expr_t * right);
+gen_expr_t * new_gen_expr(int type, void * item);
+val_expr_t * new_val_expr(int type, term_t term);
+
+int free_gen_expr(gen_expr_t * gen_expr);
+int free_prefun_expr(prefun_expr_t * prefun_expr);
+int free_tree_expr(tree_expr_t * tree_expr);
+int free_val_expr(val_expr_t * val_expr);
+
+infix_op_t * new_infix_op(int type, int precedence);
+int init_infix_ops();
+int destroy_infix_ops();
+void reset_engine_vars();
+
+gen_expr_t * clone_gen_expr(gen_expr_t * gen_expr);
+tree_expr_t * clone_tree_expr(tree_expr_t * tree_expr);
+val_expr_t * clone_val_expr(val_expr_t * val_expr);
+prefun_expr_t * clone_prefun_expr(prefun_expr_t * prefun_expr);
+
+
+
+#endif
diff --git a/modules/visualization/galaktos/expr_types.h b/modules/visualization/galaktos/expr_types.h
new file mode 100644 (file)
index 0000000..a5563f0
--- /dev/null
@@ -0,0 +1,48 @@
+#ifndef EXPR_TYPES_H
+#define EXPR_TYPES_H
+#include "param_types.h"
+
+#define CONST_STACK_ELEMENT 0
+#define EXPR_STACK_ELEMENT 1
+
+/* General Expression Type */
+typedef struct GEN_EXPR_T {
+  int type;
+  void * item;
+} gen_expr_t;
+
+typedef union TERM_T {
+  double constant; /* static variable */
+  struct PARAM_T * param; /* pointer to a changing variable */
+} term_t;
+
+/* Value expression, contains a term union */
+typedef struct VAL_EXPR_T {
+  int type;
+  term_t term;
+} val_expr_t;
+
+/* Infix Operator Function */
+typedef struct INFIX_OP_T {
+  int type;
+  int precedence;  
+} infix_op_t;
+
+/* A binary expression tree ordered by operator precedence */
+typedef struct TREE_EXPR_T {
+  infix_op_t * infix_op; /* null if leaf */
+  gen_expr_t * gen_expr;
+  struct TREE_EXPR_T * left, * right;
+} tree_expr_t;
+
+/* A function expression in prefix form */
+typedef struct PREFUN_EXPR_T {
+  double (*func_ptr)();
+  int num_args;
+  gen_expr_t ** expr_list;
+} prefun_expr_t;
+
+
+
+
+#endif
diff --git a/modules/visualization/galaktos/fatal.h b/modules/visualization/galaktos/fatal.h
new file mode 100644 (file)
index 0000000..352bccb
--- /dev/null
@@ -0,0 +1,9 @@
+/* Fatal Error Definitions */
+
+#define OUTOFMEM_ERROR -7; /* out of memory */
+#define ERROR -1 /* non specific error */
+#define SUCCESS 1
+#define FAILURE -1
+#define PARSE_ERROR -11
+#define DIV_BY_ZERO -3
+#define OK 2
diff --git a/modules/visualization/galaktos/fftsg.c b/modules/visualization/galaktos/fftsg.c
new file mode 100644 (file)
index 0000000..9564121
--- /dev/null
@@ -0,0 +1,3340 @@
+/*****************************************************************************
+ * fftsg.c:
+ *****************************************************************************
+ * Copyright (C) 2004 VideoLAN
+ * $Id$
+ *
+ * Authors: Cyril Deguet <asmax@videolan.org>
+ *          code from projectM http://xmms-projectm.sourceforge.net
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ *****************************************************************************/
+
+
+
+/*
+Fast Fourier/Cosine/Sine Transform
+    dimension   :one
+    data length :power of 2
+    decimation  :frequency
+    radix       :split-radix
+    data        :inplace
+    table       :use
+functions
+    cdft: Complex Discrete Fourier Transform
+    rdft: Real Discrete Fourier Transform
+    ddct: Discrete Cosine Transform
+    ddst: Discrete Sine Transform
+    dfct: Cosine Transform of RDFT (Real Symmetric DFT)
+    dfst: Sine Transform of RDFT (Real Anti-symmetric DFT)
+function prototypes
+    void cdft(int, int, double *, int *, double *);
+    void rdft(int, int, double *, int *, double *);
+    void ddct(int, int, double *, int *, double *);
+    void ddst(int, int, double *, int *, double *);
+    void dfct(int, double *, double *, int *, double *);
+    void dfst(int, double *, double *, int *, double *);
+macro definitions
+    USE_CDFT_PTHREADS : default=not defined
+        CDFT_THREADS_BEGIN_N  : must be >= 512, default=8192
+        CDFT_4THREADS_BEGIN_N : must be >= 512, default=65536
+    USE_CDFT_WINTHREADS : default=not defined
+        CDFT_THREADS_BEGIN_N  : must be >= 512, default=32768
+        CDFT_4THREADS_BEGIN_N : must be >= 512, default=524288
+
+
+-------- Complex DFT (Discrete Fourier Transform) --------
+    [definition]
+        <case1>
+            X[k] = sum_j=0^n-1 x[j]*exp(2*pi*i*j*k/n), 0<=k<n
+        <case2>
+            X[k] = sum_j=0^n-1 x[j]*exp(-2*pi*i*j*k/n), 0<=k<n
+        (notes: sum_j=0^n-1 is a summation from j=0 to n-1)
+    [usage]
+        <case1>
+            ip[0] = 0; // first time only
+            cdft(2*n, 1, a, ip, w);
+        <case2>
+            ip[0] = 0; // first time only
+            cdft(2*n, -1, a, ip, w);
+    [parameters]
+        2*n            :data length (int)
+                        n >= 1, n = power of 2
+        a[0...2*n-1]   :input/output data (double *)
+                        input data
+                            a[2*j] = Re(x[j]), 
+                            a[2*j+1] = Im(x[j]), 0<=j<n
+                        output data
+                            a[2*k] = Re(X[k]), 
+                            a[2*k+1] = Im(X[k]), 0<=k<n
+        ip[0...*]      :work area for bit reversal (int *)
+                        length of ip >= 2+sqrt(n)
+                        strictly, 
+                        length of ip >= 
+                            2+(1<<(int)(log(n+0.5)/log(2))/2).
+                        ip[0],ip[1] are pointers of the cos/sin table.
+        w[0...n/2-1]   :cos/sin table (double *)
+                        w[],ip[] are initialized if ip[0] == 0.
+    [remark]
+        Inverse of 
+            cdft(2*n, -1, a, ip, w);
+        is 
+            cdft(2*n, 1, a, ip, w);
+            for (j = 0; j <= 2 * n - 1; j++) {
+                a[j] *= 1.0 / n;
+            }
+        .
+
+
+-------- Real DFT / Inverse of Real DFT --------
+    [definition]
+        <case1> RDFT
+            R[k] = sum_j=0^n-1 a[j]*cos(2*pi*j*k/n), 0<=k<=n/2
+            I[k] = sum_j=0^n-1 a[j]*sin(2*pi*j*k/n), 0<k<n/2
+        <case2> IRDFT (excluding scale)
+            a[k] = (R[0] + R[n/2]*cos(pi*k))/2 + 
+                   sum_j=1^n/2-1 R[j]*cos(2*pi*j*k/n) + 
+                   sum_j=1^n/2-1 I[j]*sin(2*pi*j*k/n), 0<=k<n
+    [usage]
+        <case1>
+            ip[0] = 0; // first time only
+            rdft(n, 1, a, ip, w);
+        <case2>
+            ip[0] = 0; // first time only
+            rdft(n, -1, a, ip, w);
+    [parameters]
+        n              :data length (int)
+                        n >= 2, n = power of 2
+        a[0...n-1]     :input/output data (double *)
+                        <case1>
+                            output data
+                                a[2*k] = R[k], 0<=k<n/2
+                                a[2*k+1] = I[k], 0<k<n/2
+                                a[1] = R[n/2]
+                        <case2>
+                            input data
+                                a[2*j] = R[j], 0<=j<n/2
+                                a[2*j+1] = I[j], 0<j<n/2
+                                a[1] = R[n/2]
+        ip[0...*]      :work area for bit reversal (int *)
+                        length of ip >= 2+sqrt(n/2)
+                        strictly, 
+                        length of ip >= 
+                            2+(1<<(int)(log(n/2+0.5)/log(2))/2).
+                        ip[0],ip[1] are pointers of the cos/sin table.
+        w[0...n/2-1]   :cos/sin table (double *)
+                        w[],ip[] are initialized if ip[0] == 0.
+    [remark]
+        Inverse of 
+            rdft(n, 1, a, ip, w);
+        is 
+            rdft(n, -1, a, ip, w);
+            for (j = 0; j <= n - 1; j++) {
+                a[j] *= 2.0 / n;
+            }
+        .
+
+
+-------- DCT (Discrete Cosine Transform) / Inverse of DCT --------
+    [definition]
+        <case1> IDCT (excluding scale)
+            C[k] = sum_j=0^n-1 a[j]*cos(pi*j*(k+1/2)/n), 0<=k<n
+        <case2> DCT
+            C[k] = sum_j=0^n-1 a[j]*cos(pi*(j+1/2)*k/n), 0<=k<n
+    [usage]
+        <case1>
+            ip[0] = 0; // first time only
+            ddct(n, 1, a, ip, w);
+        <case2>
+            ip[0] = 0; // first time only
+            ddct(n, -1, a, ip, w);
+    [parameters]
+        n              :data length (int)
+                        n >= 2, n = power of 2
+        a[0...n-1]     :input/output data (double *)
+                        output data
+                            a[k] = C[k], 0<=k<n
+        ip[0...*]      :work area for bit reversal (int *)
+                        length of ip >= 2+sqrt(n/2)
+                        strictly, 
+                        length of ip >= 
+                            2+(1<<(int)(log(n/2+0.5)/log(2))/2).
+                        ip[0],ip[1] are pointers of the cos/sin table.
+        w[0...n*5/4-1] :cos/sin table (double *)
+                        w[],ip[] are initialized if ip[0] == 0.
+    [remark]
+        Inverse of 
+            ddct(n, -1, a, ip, w);
+        is 
+            a[0] *= 0.5;
+            ddct(n, 1, a, ip, w);
+            for (j = 0; j <= n - 1; j++) {
+                a[j] *= 2.0 / n;
+            }
+        .
+
+
+-------- DST (Discrete Sine Transform) / Inverse of DST --------
+    [definition]
+        <case1> IDST (excluding scale)
+            S[k] = sum_j=1^n A[j]*sin(pi*j*(k+1/2)/n), 0<=k<n
+        <case2> DST
+            S[k] = sum_j=0^n-1 a[j]*sin(pi*(j+1/2)*k/n), 0<k<=n
+    [usage]
+        <case1>
+            ip[0] = 0; // first time only
+            ddst(n, 1, a, ip, w);
+        <case2>
+            ip[0] = 0; // first time only
+            ddst(n, -1, a, ip, w);
+    [parameters]
+        n              :data length (int)
+                        n >= 2, n = power of 2
+        a[0...n-1]     :input/output data (double *)
+                        <case1>
+                            input data
+                                a[j] = A[j], 0<j<n
+                                a[0] = A[n]
+                            output data
+                                a[k] = S[k], 0<=k<n
+                        <case2>
+                            output data
+                                a[k] = S[k], 0<k<n
+                                a[0] = S[n]
+        ip[0...*]      :work area for bit reversal (int *)
+                        length of ip >= 2+sqrt(n/2)
+                        strictly, 
+                        length of ip >= 
+                            2+(1<<(int)(log(n/2+0.5)/log(2))/2).
+                        ip[0],ip[1] are pointers of the cos/sin table.
+        w[0...n*5/4-1] :cos/sin table (double *)
+                        w[],ip[] are initialized if ip[0] == 0.
+    [remark]
+        Inverse of 
+            ddst(n, -1, a, ip, w);
+        is 
+            a[0] *= 0.5;
+            ddst(n, 1, a, ip, w);
+            for (j = 0; j <= n - 1; j++) {
+                a[j] *= 2.0 / n;
+            }
+        .
+
+
+-------- Cosine Transform of RDFT (Real Symmetric DFT) --------
+    [definition]
+        C[k] = sum_j=0^n a[j]*cos(pi*j*k/n), 0<=k<=n
+    [usage]
+        ip[0] = 0; // first time only
+        dfct(n, a, t, ip, w);
+    [parameters]
+        n              :data length - 1 (int)
+                        n >= 2, n = power of 2
+        a[0...n]       :input/output data (double *)
+                        output data
+                            a[k] = C[k], 0<=k<=n
+        t[0...n/2]     :work area (double *)
+        ip[0...*]      :work area for bit reversal (int *)
+                        length of ip >= 2+sqrt(n/4)
+                        strictly, 
+                        length of ip >= 
+                            2+(1<<(int)(log(n/4+0.5)/log(2))/2).
+                        ip[0],ip[1] are pointers of the cos/sin table.
+        w[0...n*5/8-1] :cos/sin table (double *)
+                        w[],ip[] are initialized if ip[0] == 0.
+    [remark]
+        Inverse of 
+            a[0] *= 0.5;
+            a[n] *= 0.5;
+            dfct(n, a, t, ip, w);
+        is 
+            a[0] *= 0.5;
+            a[n] *= 0.5;
+            dfct(n, a, t, ip, w);
+            for (j = 0; j <= n; j++) {
+                a[j] *= 2.0 / n;
+            }
+        .
+
+
+-------- Sine Transform of RDFT (Real Anti-symmetric DFT) --------
+    [definition]
+        S[k] = sum_j=1^n-1 a[j]*sin(pi*j*k/n), 0<k<n
+    [usage]
+        ip[0] = 0; // first time only
+        dfst(n, a, t, ip, w);
+    [parameters]
+        n              :data length + 1 (int)
+                        n >= 2, n = power of 2
+        a[0...n-1]     :input/output data (double *)
+                        output data
+                            a[k] = S[k], 0<k<n
+                        (a[0] is used for work area)
+        t[0...n/2-1]   :work area (double *)
+        ip[0...*]      :work area for bit reversal (int *)
+                        length of ip >= 2+sqrt(n/4)
+                        strictly, 
+                        length of ip >= 
+                            2+(1<<(int)(log(n/4+0.5)/log(2))/2).
+                        ip[0],ip[1] are pointers of the cos/sin table.
+        w[0...n*5/8-1] :cos/sin table (double *)
+                        w[],ip[] are initialized if ip[0] == 0.
+    [remark]
+        Inverse of 
+            dfst(n, a, t, ip, w);
+        is 
+            dfst(n, a, t, ip, w);
+            for (j = 1; j <= n - 1; j++) {
+                a[j] *= 2.0 / n;
+            }
+        .
+
+
+Appendix :
+    The cos/sin table is recalculated when the larger table required.
+    w[] and ip[] are compatible with all routines.
+*/
+
+
+void cdft(int n, int isgn, double *a, int *ip, double *w)
+{
+    void makewt(int nw, int *ip, double *w);
+    void cftfsub(int n, double *a, int *ip, int nw, double *w);
+    void cftbsub(int n, double *a, int *ip, int nw, double *w);
+    int nw;
+    
+    nw = ip[0];
+    if (n > (nw << 2)) {
+        nw = n >> 2;
+        makewt(nw, ip, w);
+    }
+    if (isgn >= 0) {
+        cftfsub(n, a, ip, nw, w);
+    } else {
+        cftbsub(n, a, ip, nw, w);
+    }
+}
+
+
+void rdft(int n, int isgn, double *a, int *ip, double *w)
+{
+    void makewt(int nw, int *ip, double *w);
+    void makect(int nc, int *ip, double *c);
+    void cftfsub(int n, double *a, int *ip, int nw, double *w);
+    void cftbsub(int n, double *a, int *ip, int nw, double *w);
+    void rftfsub(int n, double *a, int nc, double *c);
+    void rftbsub(int n, double *a, int nc, double *c);
+    int nw, nc;
+    double xi;
+    
+    nw = ip[0];
+    if (n > (nw << 2)) {
+        nw = n >> 2;
+        makewt(nw, ip, w);
+    }
+    nc = ip[1];
+    if (n > (nc << 2)) {
+        nc = n >> 2;
+        makect(nc, ip, w + nw);
+    }
+    if (isgn >= 0) {
+        if (n > 4) {
+            cftfsub(n, a, ip, nw, w);
+            rftfsub(n, a, nc, w + nw);
+        } else if (n == 4) {
+            cftfsub(n, a, ip, nw, w);
+        }
+        xi = a[0] - a[1];
+        a[0] += a[1];
+        a[1] = xi;
+    } else {
+        a[1] = 0.5 * (a[0] - a[1]);
+        a[0] -= a[1];
+        if (n > 4) {
+            rftbsub(n, a, nc, w + nw);
+            cftbsub(n, a, ip, nw, w);
+        } else if (n == 4) {
+            cftbsub(n, a, ip, nw, w);
+        }
+    }
+}
+
+
+void ddct(int n, int isgn, double *a, int *ip, double *w)
+{
+    void makewt(int nw, int *ip, double *w);
+    void makect(int nc, int *ip, double *c);
+    void cftfsub(int n, double *a, int *ip, int nw, double *w);
+    void cftbsub(int n, double *a, int *ip, int nw, double *w);
+    void rftfsub(int n, double *a, int nc, double *c);
+    void rftbsub(int n, double *a, int nc, double *c);
+    void dctsub(int n, double *a, int nc, double *c);
+    int j, nw, nc;
+    double xr;
+    
+    nw = ip[0];
+    if (n > (nw << 2)) {
+        nw = n >> 2;
+        makewt(nw, ip, w);
+    }
+    nc = ip[1];
+    if (n > nc) {
+        nc = n;
+        makect(nc, ip, w + nw);
+    }
+    if (isgn < 0) {
+        xr = a[n - 1];
+        for (j = n - 2; j >= 2; j -= 2) {
+            a[j + 1] = a[j] - a[j - 1];
+            a[j] += a[j - 1];
+        }
+        a[1] = a[0] - xr;
+        a[0] += xr;
+        if (n > 4) {
+            rftbsub(n, a, nc, w + nw);
+            cftbsub(n, a, ip, nw, w);
+        } else if (n == 4) {
+            cftbsub(n, a, ip, nw, w);
+        }
+    }
+    dctsub(n, a, nc, w + nw);
+    if (isgn >= 0) {
+        if (n > 4) {
+            cftfsub(n, a, ip, nw, w);
+            rftfsub(n, a, nc, w + nw);
+        } else if (n == 4) {
+            cftfsub(n, a, ip, nw, w);
+        }
+        xr = a[0] - a[1];
+        a[0] += a[1];
+        for (j = 2; j < n; j += 2) {
+            a[j - 1] = a[j] - a[j + 1];
+            a[j] += a[j + 1];
+        }
+        a[n - 1] = xr;
+    }
+}
+
+
+void ddst(int n, int isgn, double *a, int *ip, double *w)
+{
+    void makewt(int nw, int *ip, double *w);
+    void makect(int nc, int *ip, double *c);
+    void cftfsub(int n, double *a, int *ip, int nw, double *w);
+    void cftbsub(int n, double *a, int *ip, int nw, double *w);
+    void rftfsub(int n, double *a, int nc, double *c);
+    void rftbsub(int n, double *a, int nc, double *c);
+    void dstsub(int n, double *a, int nc, double *c);
+    int j, nw, nc;
+    double xr;
+    
+    nw = ip[0];
+    if (n > (nw << 2)) {
+        nw = n >> 2;
+        makewt(nw, ip, w);
+    }
+    nc = ip[1];
+    if (n > nc) {
+        nc = n;
+        makect(nc, ip, w + nw);
+    }
+    if (isgn < 0) {
+        xr = a[n - 1];
+        for (j = n - 2; j >= 2; j -= 2) {
+            a[j + 1] = -a[j] - a[j - 1];
+            a[j] -= a[j - 1];
+        }
+        a[1] = a[0] + xr;
+        a[0] -= xr;
+        if (n > 4) {
+            rftbsub(n, a, nc, w + nw);
+            cftbsub(n, a, ip, nw, w);
+        } else if (n == 4) {
+            cftbsub(n, a, ip, nw, w);
+        }
+    }
+    dstsub(n, a, nc, w + nw);
+    if (isgn >= 0) {
+        if (n > 4) {
+            cftfsub(n, a, ip, nw, w);
+            rftfsub(n, a, nc, w + nw);
+        } else if (n == 4) {
+            cftfsub(n, a, ip, nw, w);
+        }
+        xr = a[0] - a[1];
+        a[0] += a[1];
+        for (j = 2; j < n; j += 2) {
+            a[j - 1] = -a[j] - a[j + 1];
+            a[j] -= a[j + 1];
+        }
+        a[n - 1] = -xr;
+    }
+}
+
+
+void dfct(int n, double *a, double *t, int *ip, double *w)
+{
+    void makewt(int nw, int *ip, double *w);
+    void makect(int nc, int *ip, double *c);
+    void cftfsub(int n, double *a, int *ip, int nw, double *w);
+    void rftfsub(int n, double *a, int nc, double *c);
+    void dctsub(int n, double *a, int nc, double *c);
+    int j, k, l, m, mh, nw, nc;
+    double xr, xi, yr, yi;
+    
+    nw = ip[0];
+    if (n > (nw << 3)) {
+        nw = n >> 3;
+        makewt(nw, ip, w);
+    }
+    nc = ip[1];
+    if (n > (nc << 1)) {
+        nc = n >> 1;
+        makect(nc, ip, w + nw);
+    }
+    m = n >> 1;
+    yi = a[m];
+    xi = a[0] + a[n];
+    a[0] -= a[n];
+    t[0] = xi - yi;
+    t[m] = xi + yi;
+    if (n > 2) {
+        mh = m >> 1;
+        for (j = 1; j < mh; j++) {
+            k = m - j;
+            xr = a[j] - a[n - j];
+            xi = a[j] + a[n - j];
+            yr = a[k] - a[n - k];
+            yi = a[k] + a[n - k];
+            a[j] = xr;
+            a[k] = yr;
+            t[j] = xi - yi;
+            t[k] = xi + yi;
+        }
+        t[mh] = a[mh] + a[n - mh];
+        a[mh] -= a[n - mh];
+        dctsub(m, a, nc, w + nw);
+        if (m > 4) {
+            cftfsub(m, a, ip, nw, w);
+            rftfsub(m, a, nc, w + nw);
+        } else if (m == 4) {
+            cftfsub(m, a, ip, nw, w);
+        }
+        a[n - 1] = a[0] - a[1];
+        a[1] = a[0] + a[1];
+        for (j = m - 2; j >= 2; j -= 2) {
+            a[2 * j + 1] = a[j] + a[j + 1];
+            a[2 * j - 1] = a[j] - a[j + 1];
+        }
+        l = 2;
+        m = mh;
+        while (m >= 2) {
+            dctsub(m, t, nc, w + nw);
+            if (m > 4) {
+                cftfsub(m, t, ip, nw, w);
+                rftfsub(m, t, nc, w + nw);
+            } else if (m == 4) {
+                cftfsub(m, t, ip, nw, w);
+            }
+            a[n - l] = t[0] - t[1];
+            a[l] = t[0] + t[1];
+            k = 0;
+            for (j = 2; j < m; j += 2) {
+                k += l << 2;
+                a[k - l] = t[j] - t[j + 1];
+                a[k + l] = t[j] + t[j + 1];
+            }
+            l <<= 1;
+            mh = m >> 1;
+            for (j = 0; j < mh; j++) {
+                k = m - j;
+                t[j] = t[m + k] - t[m + j];
+                t[k] = t[m + k] + t[m + j];
+            }
+            t[mh] = t[m + mh];
+            m = mh;
+        }
+        a[l] = t[0];
+        a[n] = t[2] - t[1];
+        a[0] = t[2] + t[1];
+    } else {
+        a[1] = a[0];
+        a[2] = t[0];
+        a[0] = t[1];
+    }
+}
+
+
+void dfst(int n, double *a, double *t, int *ip, double *w)
+{
+    void makewt(int nw, int *ip, double *w);
+    void makect(int nc, int *ip, double *c);
+    void cftfsub(int n, double *a, int *ip, int nw, double *w);
+    void rftfsub(int n, double *a, int nc, double *c);
+    void dstsub(int n, double *a, int nc, double *c);
+    int j, k, l, m, mh, nw, nc;
+    double xr, xi, yr, yi;
+    
+    nw = ip[0];
+    if (n > (nw << 3)) {
+        nw = n >> 3;
+        makewt(nw, ip, w);
+    }
+    nc = ip[1];
+    if (n > (nc << 1)) {
+        nc = n >> 1;
+        makect(nc, ip, w + nw);
+    }
+    if (n > 2) {
+        m = n >> 1;
+        mh = m >> 1;
+        for (j = 1; j < mh; j++) {
+            k = m - j;
+            xr = a[j] + a[n - j];
+            xi = a[j] - a[n - j];
+            yr = a[k] + a[n - k];
+            yi = a[k] - a[n - k];
+            a[j] = xr;
+            a[k] = yr;
+            t[j] = xi + yi;
+            t[k] = xi - yi;
+        }
+        t[0] = a[mh] - a[n - mh];
+        a[mh] += a[n - mh];
+        a[0] = a[m];
+        dstsub(m, a, nc, w + nw);
+        if (m > 4) {
+            cftfsub(m, a, ip, nw, w);
+            rftfsub(m, a, nc, w + nw);
+        } else if (m == 4) {
+            cftfsub(m, a, ip, nw, w);
+        }
+        a[n - 1] = a[1] - a[0];
+        a[1] = a[0] + a[1];
+        for (j = m - 2; j >= 2; j -= 2) {
+            a[2 * j + 1] = a[j] - a[j + 1];
+            a[2 * j - 1] = -a[j] - a[j + 1];
+        }
+        l = 2;
+        m = mh;
+        while (m >= 2) {
+            dstsub(m, t, nc, w + nw);
+            if (m > 4) {
+                cftfsub(m, t, ip, nw, w);
+                rftfsub(m, t, nc, w + nw);
+            } else if (m == 4) {
+                cftfsub(m, t, ip, nw, w);
+            }
+            a[n - l] = t[1] - t[0];
+            a[l] = t[0] + t[1];
+            k = 0;
+            for (j = 2; j < m; j += 2) {
+                k += l << 2;
+                a[k - l] = -t[j] - t[j + 1];
+                a[k + l] = t[j] - t[j + 1];
+            }
+            l <<= 1;
+            mh = m >> 1;
+            for (j = 1; j < mh; j++) {
+                k = m - j;
+                t[j] = t[m + k] + t[m + j];
+                t[k] = t[m + k] - t[m + j];
+            }
+            t[0] = t[m + mh];
+            m = mh;
+        }
+        a[l] = t[0];
+    }
+    a[0] = 0;
+}
+
+
+/* -------- initializing routines -------- */
+
+
+#include <math.h>
+
+void makewt(int nw, int *ip, double *w)
+{
+    void makeipt(int nw, int *ip);
+    int j, nwh, nw0, nw1;
+    double delta, wn4r, wk1r, wk1i, wk3r, wk3i;
+    
+    ip[0] = nw;
+    ip[1] = 1;
+    if (nw > 2) {
+        nwh = nw >> 1;
+        delta = atan(1.0) / nwh;
+        wn4r = cos(delta * nwh);
+        w[0] = 1;
+        w[1] = wn4r;
+        if (nwh == 4) {
+            w[2] = cos(delta * 2);
+            w[3] = sin(delta * 2);
+        } else if (nwh > 4) {
+            makeipt(nw, ip);
+            w[2] = 0.5 / cos(delta * 2);
+            w[3] = 0.5 / cos(delta * 6);
+            for (j = 4; j < nwh; j += 4) {
+                w[j] = cos(delta * j);
+                w[j + 1] = sin(delta * j);
+                w[j + 2] = cos(3 * delta * j);
+                w[j + 3] = -sin(3 * delta * j);
+            }
+        }
+        nw0 = 0;
+        while (nwh > 2) {
+            nw1 = nw0 + nwh;
+            nwh >>= 1;
+            w[nw1] = 1;
+            w[nw1 + 1] = wn4r;
+            if (nwh == 4) {
+                wk1r = w[nw0 + 4];
+                wk1i = w[nw0 + 5];
+                w[nw1 + 2] = wk1r;
+                w[nw1 + 3] = wk1i;
+            } else if (nwh > 4) {
+                wk1r = w[nw0 + 4];
+                wk3r = w[nw0 + 6];
+                w[nw1 + 2] = 0.5 / wk1r;
+                w[nw1 + 3] = 0.5 / wk3r;
+                for (j = 4; j < nwh; j += 4) {
+                    wk1r = w[nw0 + 2 * j];
+                    wk1i = w[nw0 + 2 * j + 1];
+                    wk3r = w[nw0 + 2 * j + 2];
+                    wk3i = w[nw0 + 2 * j + 3];
+                    w[nw1 + j] = wk1r;
+                    w[nw1 + j + 1] = wk1i;
+                    w[nw1 + j + 2] = wk3r;
+                    w[nw1 + j + 3] = wk3i;
+                }
+            }
+            nw0 = nw1;
+        }
+    }
+}
+
+
+void makeipt(int nw, int *ip)
+{
+    int j, l, m, m2, p, q;
+    
+    ip[2] = 0;
+    ip[3] = 16;
+    m = 2;
+    for (l = nw; l > 32; l >>= 2) {
+        m2 = m << 1;
+        q = m2 << 3;
+        for (j = m; j < m2; j++) {
+            p = ip[j] << 2;
+            ip[m + j] = p;
+            ip[m2 + j] = p + q;
+        }
+        m = m2;
+    }
+}
+
+
+void makect(int nc, int *ip, double *c)
+{
+    int j, nch;
+    double delta;
+    
+    ip[1] = nc;
+    if (nc > 1) {
+        nch = nc >> 1;
+        delta = atan(1.0) / nch;
+        c[0] = cos(delta * nch);
+        c[nch] = 0.5 * c[0];
+        for (j = 1; j < nch; j++) {
+            c[j] = 0.5 * cos(delta * j);
+            c[nc - j] = 0.5 * sin(delta * j);
+        }
+    }
+}
+
+
+/* -------- child routines -------- */
+
+
+#ifdef USE_CDFT_PTHREADS
+#define USE_CDFT_THREADS
+#ifndef CDFT_THREADS_BEGIN_N
+#define CDFT_THREADS_BEGIN_N 8192
+#endif
+#ifndef CDFT_4THREADS_BEGIN_N
+#define CDFT_4THREADS_BEGIN_N 65536
+#endif
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#define cdft_thread_t pthread_t
+#define cdft_thread_create(thp,func,argp) { \
+    if (pthread_create(thp, NULL, func, (void *) argp) != 0) { \
+        fprintf(stderr, "cdft thread error\n"); \
+        exit(1); \
+    } \
+}
+#define cdft_thread_wait(th) { \
+    if (pthread_join(th, NULL) != 0) { \
+        fprintf(stderr, "cdft thread error\n"); \
+        exit(1); \
+    } \
+}
+#endif /* USE_CDFT_PTHREADS */
+
+
+#ifdef USE_CDFT_WINTHREADS
+#define USE_CDFT_THREADS
+#ifndef CDFT_THREADS_BEGIN_N
+#define CDFT_THREADS_BEGIN_N 32768
+#endif
+#ifndef CDFT_4THREADS_BEGIN_N
+#define CDFT_4THREADS_BEGIN_N 524288
+#endif
+#include <windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+#define cdft_thread_t HANDLE
+#define cdft_thread_create(thp,func,argp) { \
+    DWORD thid; \
+    *(thp) = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) func, (LPVOID) argp, 0, &thid); \
+    if (*(thp) == 0) { \
+        fprintf(stderr, "cdft thread error\n"); \
+        exit(1); \
+    } \
+}
+#define cdft_thread_wait(th) { \
+    WaitForSingleObject(th, INFINITE); \
+    CloseHandle(th); \
+}
+#endif /* USE_CDFT_WINTHREADS */
+
+
+void cftfsub(int n, double *a, int *ip, int nw, double *w)
+{
+    void bitrv2(int n, int *ip, double *a);
+    void bitrv216(double *a);
+    void bitrv208(double *a);
+    void cftf1st(int n, double *a, double *w);
+    void cftrec4(int n, double *a, int nw, double *w);
+    void cftleaf(int n, int isplt, double *a, int nw, double *w);
+    void cftfx41(int n, double *a, int nw, double *w);
+    void cftf161(double *a, double *w);
+    void cftf081(double *a, double *w);
+    void cftf040(double *a);
+    void cftx020(double *a);
+#ifdef USE_CDFT_THREADS
+    void cftrec4_th(int n, double *a, int nw, double *w);
+#endif /* USE_CDFT_THREADS */
+    
+    if (n > 8) {
+        if (n > 32) {
+            cftf1st(n, a, &w[nw - (n >> 2)]);
+#ifdef USE_CDFT_THREADS
+            if (n > CDFT_THREADS_BEGIN_N) {
+                cftrec4_th(n, a, nw, w);
+            } else 
+#endif /* USE_CDFT_THREADS */
+            if (n > 512) {
+                cftrec4(n, a, nw, w);
+            } else if (n > 128) {
+                cftleaf(n, 1, a, nw, w);
+            } else {
+                cftfx41(n, a, nw, w);
+            }
+            bitrv2(n, ip, a);
+        } else if (n == 32) {
+            cftf161(a, &w[nw - 8]);
+            bitrv216(a);
+        } else {
+            cftf081(a, w);
+            bitrv208(a);
+        }
+    } else if (n == 8) {
+        cftf040(a);
+    } else if (n == 4) {
+        cftx020(a);
+    }
+}
+
+
+void cftbsub(int n, double *a, int *ip, int nw, double *w)
+{
+    void bitrv2conj(int n, int *ip, double *a);
+    void bitrv216neg(double *a);
+    void bitrv208neg(double *a);
+    void cftb1st(int n, double *a, double *w);
+    void cftrec4(int n, double *a, int nw, double *w);
+    void cftleaf(int n, int isplt, double *a, int nw, double *w);
+    void cftfx41(int n, double *a, int nw, double *w);
+    void cftf161(double *a, double *w);
+    void cftf081(double *a, double *w);
+    void cftb040(double *a);
+    void cftx020(double *a);
+#ifdef USE_CDFT_THREADS
+    void cftrec4_th(int n, double *a, int nw, double *w);
+#endif /* USE_CDFT_THREADS */
+    
+    if (n > 8) {
+        if (n > 32) {
+            cftb1st(n, a, &w[nw - (n >> 2)]);
+#ifdef USE_CDFT_THREADS
+            if (n > CDFT_THREADS_BEGIN_N) {
+                cftrec4_th(n, a, nw, w);
+            } else 
+#endif /* USE_CDFT_THREADS */
+            if (n > 512) {
+                cftrec4(n, a, nw, w);
+            } else if (n > 128) {
+                cftleaf(n, 1, a, nw, w);
+            } else {
+                cftfx41(n, a, nw, w);
+            }
+            bitrv2conj(n, ip, a);
+        } else if (n == 32) {
+            cftf161(a, &w[nw - 8]);
+            bitrv216neg(a);
+        } else {
+            cftf081(a, w);
+            bitrv208neg(a);
+        }
+    } else if (n == 8) {
+        cftb040(a);
+    } else if (n == 4) {
+        cftx020(a);
+    }
+}
+
+
+void bitrv2(int n, int *ip, double *a)
+{
+    int j, j1, k, k1, l, m, nh, nm;
+    double xr, xi, yr, yi;
+    
+    m = 1;
+    for (l = n >> 2; l > 8; l >>= 2) {
+        m <<= 1;
+    }
+    nh = n >> 1;
+    nm = 4 * m;
+    if (l == 8) {
+        for (k = 0; k < m; k++) {
+            for (j = 0; j < k; j++) {
+                j1 = 4 * j + 2 * ip[m + k];
+                k1 = 4 * k + 2 * ip[m + j];
+                xr = a[j1];
+                xi = a[j1 + 1];
+                yr = a[k1];
+                yi = a[k1 + 1];
+                a[j1] = yr;
+                a[j1 + 1] = yi;
+                a[k1] = xr;
+                a[k1 + 1] = xi;
+                j1 += nm;
+                k1 += 2 * nm;
+                xr = a[j1];
+                xi = a[j1 + 1];
+                yr = a[k1];
+                yi = a[k1 + 1];
+                a[j1] = yr;
+                a[j1 + 1] = yi;
+                a[k1] = xr;
+                a[k1 + 1] = xi;
+                j1 += nm;
+                k1 -= nm;
+                xr = a[j1];
+                xi = a[j1 + 1];
+                yr = a[k1];
+                yi = a[k1 + 1];
+                a[j1] = yr;
+                a[j1 + 1] = yi;
+                a[k1] = xr;
+                a[k1 + 1] = xi;
+                j1 += nm;
+                k1 += 2 * nm;
+                xr = a[j1];
+                xi = a[j1 + 1];
+                yr = a[k1];
+                yi = a[k1 + 1];
+                a[j1] = yr;
+                a[j1 + 1] = yi;
+                a[k1] = xr;
+                a[k1 + 1] = xi;
+                j1 += nh;
+                k1 += 2;
+                xr = a[j1];
+                xi = a[j1 + 1];
+                yr = a[k1];
+                yi = a[k1 + 1];
+                a[j1] = yr;
+                a[j1 + 1] = yi;
+                a[k1] = xr;
+                a[k1 + 1] = xi;
+                j1 -= nm;
+                k1 -= 2 * nm;
+                xr = a[j1];
+                xi = a[j1 + 1];
+                yr = a[k1];
+                yi = a[k1 + 1];
+                a[j1] = yr;
+                a[j1 + 1] = yi;
+                a[k1] = xr;
+                a[k1 + 1] = xi;
+                j1 -= nm;
+                k1 += nm;
+                xr = a[j1];
+                xi = a[j1 + 1];
+                yr = a[k1];
+                yi = a[k1 + 1];
+                a[j1] = yr;
+                a[j1 + 1] = yi;
+                a[k1] = xr;
+                a[k1 + 1] = xi;
+                j1 -= nm;
+                k1 -= 2 * nm;
+                xr = a[j1];
+                xi = a[j1 + 1];
+                yr = a[k1];
+                yi = a[k1 + 1];
+                a[j1] = yr;
+                a[j1 + 1] = yi;
+                a[k1] = xr;
+                a[k1 + 1] = xi;
+                j1 += 2;
+                k1 += nh;
+                xr = a[j1];
+                xi = a[j1 + 1];
+                yr = a[k1];
+                yi = a[k1 + 1];
+                a[j1] = yr;
+                a[j1 + 1] = yi;
+                a[k1] = xr;
+                a[k1 + 1] = xi;
+                j1 += nm;
+                k1 += 2 * nm;
+                xr = a[j1];
+                xi = a[j1 + 1];
+                yr = a[k1];
+                yi = a[k1 + 1];
+                a[j1] = yr;
+                a[j1 + 1] = yi;
+                a[k1] = xr;
+                a[k1 + 1] = xi;
+                j1 += nm;
+                k1 -= nm;
+                xr = a[j1];
+                xi = a[j1 + 1];
+                yr = a[k1];
+                yi = a[k1 + 1];
+                a[j1] = yr;
+                a[j1 + 1] = yi;
+                a[k1] = xr;
+                a[k1 + 1] = xi;
+                j1 += nm;
+                k1 += 2 * nm;
+                xr = a[j1];
+                xi = a[j1 + 1];
+                yr = a[k1];
+                yi = a[k1 + 1];
+                a[j1] = yr;
+                a[j1 + 1] = yi;
+                a[k1] = xr;
+                a[k1 + 1] = xi;
+                j1 -= nh;
+                k1 -= 2;
+                xr = a[j1];
+                xi = a[j1 + 1];
+                yr = a[k1];
+                yi = a[k1 + 1];
+                a[j1] = yr;
+                a[j1 + 1] = yi;
+                a[k1] = xr;
+                a[k1 + 1] = xi;
+                j1 -= nm;
+                k1 -= 2 * nm;
+                xr = a[j1];
+                xi = a[j1 + 1];
+                yr = a[k1];
+                yi = a[k1 + 1];
+                a[j1] = yr;
+                a[j1 + 1] = yi;
+                a[k1] = xr;
+                a[k1 + 1] = xi;
+                j1 -= nm;
+                k1 += nm;
+                xr = a[j1];
+                xi = a[j1 + 1];
+                yr = a[k1];
+                yi = a[k1 + 1];
+                a[j1] = yr;
+                a[j1 + 1] = yi;
+                a[k1] = xr;
+                a[k1 + 1] = xi;
+                j1 -= nm;
+                k1 -= 2 * nm;
+                xr = a[j1];
+                xi = a[j1 + 1];
+                yr = a[k1];
+                yi = a[k1 + 1];
+                a[j1] = yr;
+                a[j1 + 1] = yi;
+                a[k1] = xr;
+                a[k1 + 1] = xi;
+            }
+            k1 = 4 * k + 2 * ip[m + k];
+            j1 = k1 + 2;
+            k1 += nh;
+            xr = a[j1];
+            xi = a[j1 + 1];
+            yr = a[k1];
+            yi = a[k1 + 1];
+            a[j1] = yr;
+            a[j1 + 1] = yi;
+            a[k1] = xr;
+            a[k1 + 1] = xi;
+            j1 += nm;
+            k1 += 2 * nm;
+            xr = a[j1];
+            xi = a[j1 + 1];
+            yr = a[k1];
+            yi = a[k1 + 1];
+            a[j1] = yr;
+            a[j1 + 1] = yi;
+            a[k1] = xr;
+            a[k1 + 1] = xi;
+            j1 += nm;
+            k1 -= nm;
+            xr = a[j1];
+            xi = a[j1 + 1];
+            yr = a[k1];
+            yi = a[k1 + 1];
+            a[j1] = yr;
+            a[j1 + 1] = yi;
+            a[k1] = xr;
+            a[k1 + 1] = xi;
+            j1 -= 2;
+            k1 -= nh;
+            xr = a[j1];
+            xi = a[j1 + 1];
+            yr = a[k1];
+            yi = a[k1 + 1];
+            a[j1] = yr;
+            a[j1 + 1] = yi;
+            a[k1] = xr;
+            a[k1 + 1] = xi;
+            j1 += nh + 2;
+            k1 += nh + 2;
+            xr = a[j1];
+            xi = a[j1 + 1];
+            yr = a[k1];
+            yi = a[k1 + 1];
+            a[j1] = yr;
+            a[j1 + 1] = yi;
+            a[k1] = xr;
+            a[k1 + 1] = xi;
+            j1 -= nh - nm;
+            k1 += 2 * nm - 2;
+            xr = a[j1];
+            xi = a[j1 + 1];
+            yr = a[k1];
+            yi = a[k1 + 1];
+            a[j1] = yr;
+            a[j1 + 1] = yi;
+            a[k1] = xr;
+            a[k1 + 1] = xi;
+        }
+    } else {
+        for (k = 0; k < m; k++) {
+            for (j = 0; j < k; j++) {
+                j1 = 4 * j + ip[m + k];
+                k1 = 4 * k + ip[m + j];
+                xr = a[j1];
+                xi = a[j1 + 1];
+                yr = a[k1];
+                yi = a[k1 + 1];
+                a[j1] = yr;
+                a[j1 + 1] = yi;
+                a[k1] = xr;
+                a[k1 + 1] = xi;
+                j1 += nm;
+                k1 += nm;
+                xr = a[j1];
+                xi = a[j1 + 1];
+                yr = a[k1];
+                yi = a[k1 + 1];
+                a[j1] = yr;
+                a[j1 + 1] = yi;
+                a[k1] = xr;
+                a[k1 + 1] = xi;
+                j1 += nh;
+                k1 += 2;
+                xr = a[j1];
+                xi = a[j1 + 1];
+                yr = a[k1];
+                yi = a[k1 + 1];
+                a[j1] = yr;
+                a[j1 + 1] = yi;
+                a[k1] = xr;
+                a[k1 + 1] = xi;
+                j1 -= nm;
+                k1 -= nm;
+                xr = a[j1];
+                xi = a[j1 + 1];
+                yr = a[k1];
+                yi = a[k1 + 1];
+                a[j1] = yr;
+                a[j1 + 1] = yi;
+                a[k1] = xr;
+                a[k1 + 1] = xi;
+                j1 += 2;
+                k1 += nh;
+                xr = a[j1];
+                xi = a[j1 + 1];
+                yr = a[k1];
+                yi = a[k1 + 1];
+                a[j1] = yr;
+                a[j1 + 1] = yi;
+                a[k1] = xr;
+                a[k1 + 1] = xi;
+                j1 += nm;
+                k1 += nm;
+                xr = a[j1];
+                xi = a[j1 + 1];
+                yr = a[k1];
+                yi = a[k1 + 1];
+                a[j1] = yr;
+                a[j1 + 1] = yi;
+                a[k1] = xr;
+                a[k1 + 1] = xi;
+                j1 -= nh;
+                k1 -= 2;
+                xr = a[j1];
+                xi = a[j1 + 1];
+                yr = a[k1];
+                yi = a[k1 + 1];
+                a[j1] = yr;
+                a[j1 + 1] = yi;
+                a[k1] = xr;
+                a[k1 + 1] = xi;
+                j1 -= nm;
+                k1 -= nm;
+                xr = a[j1];
+                xi = a[j1 + 1];
+                yr = a[k1];
+                yi = a[k1 + 1];
+                a[j1] = yr;
+                a[j1 + 1] = yi;
+                a[k1] = xr;
+                a[k1 + 1] = xi;
+            }
+            k1 = 4 * k + ip[m + k];
+            j1 = k1 + 2;
+            k1 += nh;
+            xr = a[j1];
+            xi = a[j1 + 1];
+            yr = a[k1];
+            yi = a[k1 + 1];
+            a[j1] = yr;
+            a[j1 + 1] = yi;
+            a[k1] = xr;
+            a[k1 + 1] = xi;
+            j1 += nm;
+            k1 += nm;
+            xr = a[j1];
+            xi = a[j1 + 1];
+            yr = a[k1];
+            yi = a[k1 + 1];
+            a[j1] = yr;
+            a[j1 + 1] = yi;
+            a[k1] = xr;
+            a[k1 + 1] = xi;
+        }
+    }
+}
+
+
+void bitrv2conj(int n, int *ip, double *a)
+{
+    int j, j1, k, k1, l, m, nh, nm;
+    double xr, xi, yr, yi;
+    
+    m = 1;
+    for (l = n >> 2; l > 8; l >>= 2) {
+        m <<= 1;
+    }
+    nh = n >> 1;
+    nm = 4 * m;
+    if (l == 8) {
+        for (k = 0; k < m; k++) {
+            for (j = 0; j < k; j++) {
+                j1 = 4 * j + 2 * ip[m + k];
+                k1 = 4 * k + 2 * ip[m + j];
+                xr = a[j1];
+                xi = -a[j1 + 1];
+                yr = a[k1];
+                yi = -a[k1 + 1];
+                a[j1] = yr;
+                a[j1 + 1] = yi;
+                a[k1] = xr;
+                a[k1 + 1] = xi;
+                j1 += nm;
+                k1 += 2 * nm;
+                xr = a[j1];
+                xi = -a[j1 + 1];
+                yr = a[k1];
+                yi = -a[k1 + 1];
+                a[j1] = yr;
+                a[j1 + 1] = yi;
+                a[k1] = xr;
+                a[k1 + 1] = xi;
+                j1 += nm;
+                k1 -= nm;
+                xr = a[j1];
+                xi = -a[j1 + 1];
+                yr = a[k1];
+                yi = -a[k1 + 1];
+                a[j1] = yr;
+                a[j1 + 1] = yi;
+                a[k1] = xr;
+                a[k1 + 1] = xi;
+                j1 += nm;
+                k1 += 2 * nm;
+                xr = a[j1];
+                xi = -a[j1 + 1];
+                yr = a[k1];
+                yi = -a[k1 + 1];
+                a[j1] = yr;
+                a[j1 + 1] = yi;
+                a[k1] = xr;
+                a[k1 + 1] = xi;
+                j1 += nh;
+                k1 += 2;
+                xr = a[j1];
+                xi = -a[j1 + 1];
+                yr = a[k1];
+                yi = -a[k1 + 1];
+                a[j1] = yr;
+                a[j1 + 1] = yi;
+                a[k1] = xr;
+                a[k1 + 1] = xi;
+                j1 -= nm;
+                k1 -= 2 * nm;
+                xr = a[j1];
+                xi = -a[j1 + 1];
+                yr = a[k1];
+                yi = -a[k1 + 1];
+                a[j1] = yr;
+                a[j1 + 1] = yi;
+                a[k1] = xr;
+                a[k1 + 1] = xi;
+                j1 -= nm;
+                k1 += nm;
+                xr = a[j1];
+                xi = -a[j1 + 1];
+                yr = a[k1];
+                yi = -a[k1 + 1];
+                a[j1] = yr;
+                a[j1 + 1] = yi;
+                a[k1] = xr;
+                a[k1 + 1] = xi;
+                j1 -= nm;
+                k1 -= 2 * nm;
+                xr = a[j1];
+                xi = -a[j1 + 1];
+                yr = a[k1];
+                yi = -a[k1 + 1];
+                a[j1] = yr;
+                a[j1 + 1] = yi;
+                a[k1] = xr;
+                a[k1 + 1] = xi;
+                j1 += 2;
+                k1 += nh;
+                xr = a[j1];
+                xi = -a[j1 + 1];
+                yr = a[k1];
+                yi = -a[k1 + 1];
+                a[j1] = yr;
+                a[j1 + 1] = yi;
+                a[k1] = xr;
+                a[k1 + 1] = xi;
+                j1 += nm;
+                k1 += 2 * nm;
+                xr = a[j1];
+                xi = -a[j1 + 1];
+                yr = a[k1];
+                yi = -a[k1 + 1];
+                a[j1] = yr;
+                a[j1 + 1] = yi;
+                a[k1] = xr;
+                a[k1 + 1] = xi;
+                j1 += nm;
+                k1 -= nm;
+                xr = a[j1];
+                xi = -a[j1 + 1];
+                yr = a[k1];
+                yi = -a[k1 + 1];
+                a[j1] = yr;
+                a[j1 + 1] = yi;
+                a[k1] = xr;
+                a[k1 + 1] = xi;
+                j1 += nm;
+                k1 += 2 * nm;
+                xr = a[j1];
+                xi = -a[j1 + 1];
+                yr = a[k1];
+                yi = -a[k1 + 1];
+                a[j1] = yr;
+                a[j1 + 1] = yi;
+                a[k1] = xr;
+                a[k1 + 1] = xi;
+                j1 -= nh;
+                k1 -= 2;
+                xr = a[j1];
+                xi = -a[j1 + 1];
+                yr = a[k1];
+                yi = -a[k1 + 1];
+                a[j1] = yr;
+                a[j1 + 1] = yi;
+                a[k1] = xr;
+                a[k1 + 1] = xi;
+                j1 -= nm;
+                k1 -= 2 * nm;
+                xr = a[j1];
+                xi = -a[j1 + 1];
+                yr = a[k1];
+                yi = -a[k1 + 1];
+                a[j1] = yr;
+                a[j1 + 1] = yi;
+                a[k1] = xr;
+                a[k1 + 1] = xi;
+                j1 -= nm;
+                k1 += nm;
+                xr = a[j1];
+                xi = -a[j1 + 1];
+                yr = a[k1];
+                yi = -a[k1 + 1];
+                a[j1] = yr;
+                a[j1 + 1] = yi;
+                a[k1] = xr;
+                a[k1 + 1] = xi;
+                j1 -= nm;
+                k1 -= 2 * nm;
+                xr = a[j1];
+                xi = -a[j1 + 1];
+                yr = a[k1];
+                yi = -a[k1 + 1];
+                a[j1] = yr;
+                a[j1 + 1] = yi;
+                a[k1] = xr;
+                a[k1 + 1] = xi;
+            }
+            k1 = 4 * k + 2 * ip[m + k];
+            j1 = k1 + 2;
+            k1 += nh;
+            a[j1 - 1] = -a[j1 - 1];
+            xr = a[j1];
+            xi = -a[j1 + 1];
+            yr = a[k1];
+            yi = -a[k1 + 1];
+            a[j1] = yr;
+            a[j1 + 1] = yi;
+            a[k1] = xr;
+            a[k1 + 1] = xi;
+            a[k1 + 3] = -a[k1 + 3];
+            j1 += nm;
+            k1 += 2 * nm;
+            xr = a[j1];
+            xi = -a[j1 + 1];
+            yr = a[k1];
+            yi = -a[k1 + 1];
+            a[j1] = yr;
+            a[j1 + 1] = yi;
+            a[k1] = xr;
+            a[k1 + 1] = xi;
+            j1 += nm;
+            k1 -= nm;
+            xr = a[j1];
+            xi = -a[j1 + 1];
+            yr = a[k1];
+            yi = -a[k1 + 1];
+            a[j1] = yr;
+            a[j1 + 1] = yi;
+            a[k1] = xr;
+            a[k1 + 1] = xi;
+            j1 -= 2;
+            k1 -= nh;
+            xr = a[j1];
+            xi = -a[j1 + 1];
+            yr = a[k1];
+            yi = -a[k1 + 1];
+            a[j1] = yr;
+            a[j1 + 1] = yi;
+            a[k1] = xr;
+            a[k1 + 1] = xi;
+            j1 += nh + 2;
+            k1 += nh + 2;
+            xr = a[j1];
+            xi = -a[j1 + 1];
+            yr = a[k1];
+            yi = -a[k1 + 1];
+            a[j1] = yr;
+            a[j1 + 1] = yi;
+            a[k1] = xr;
+            a[k1 + 1] = xi;
+            j1 -= nh - nm;
+            k1 += 2 * nm - 2;
+            a[j1 - 1] = -a[j1 - 1];
+            xr = a[j1];
+            xi = -a[j1 + 1];
+            yr = a[k1];
+            yi = -a[k1 + 1];
+            a[j1] = yr;
+            a[j1 + 1] = yi;
+            a[k1] = xr;
+            a[k1 + 1] = xi;
+            a[k1 + 3] = -a[k1 + 3];
+        }
+    } else {
+        for (k = 0; k < m; k++) {
+            for (j = 0; j < k; j++) {
+                j1 = 4 * j + ip[m + k];
+                k1 = 4 * k + ip[m + j];
+                xr = a[j1];
+                xi = -a[j1 + 1];
+                yr = a[k1];
+                yi = -a[k1 + 1];
+                a[j1] = yr;
+                a[j1 + 1] = yi;
+                a[k1] = xr;
+                a[k1 + 1] = xi;
+                j1 += nm;
+                k1 += nm;
+                xr = a[j1];
+                xi = -a[j1 + 1];
+                yr = a[k1];
+                yi = -a[k1 + 1];
+                a[j1] = yr;
+                a[j1 + 1] = yi;
+                a[k1] = xr;
+                a[k1 + 1] = xi;
+                j1 += nh;
+                k1 += 2;
+                xr = a[j1];
+                xi = -a[j1 + 1];
+                yr = a[k1];
+                yi = -a[k1 + 1];
+                a[j1] = yr;
+                a[j1 + 1] = yi;
+                a[k1] = xr;
+                a[k1 + 1] = xi;
+                j1 -= nm;
+                k1 -= nm;
+                xr = a[j1];
+                xi = -a[j1 + 1];
+                yr = a[k1];
+                yi = -a[k1 + 1];
+                a[j1] = yr;
+                a[j1 + 1] = yi;
+                a[k1] = xr;
+                a[k1 + 1] = xi;
+                j1 += 2;
+                k1 += nh;
+                xr = a[j1];
+                xi = -a[j1 + 1];
+                yr = a[k1];
+                yi = -a[k1 + 1];
+                a[j1] = yr;
+                a[j1 + 1] = yi;
+                a[k1] = xr;
+                a[k1 + 1] = xi;
+                j1 += nm;
+                k1 += nm;
+                xr = a[j1];
+                xi = -a[j1 + 1];
+                yr = a[k1];
+                yi = -a[k1 + 1];
+                a[j1] = yr;
+                a[j1 + 1] = yi;
+                a[k1] = xr;
+                a[k1 + 1] = xi;
+                j1 -= nh;
+                k1 -= 2;
+                xr = a[j1];
+                xi = -a[j1 + 1];
+                yr = a[k1];
+                yi = -a[k1 + 1];
+                a[j1] = yr;
+                a[j1 + 1] = yi;
+                a[k1] = xr;
+                a[k1 + 1] = xi;
+                j1 -= nm;
+                k1 -= nm;
+                xr = a[j1];
+                xi = -a[j1 + 1];
+                yr = a[k1];
+                yi = -a[k1 + 1];
+                a[j1] = yr;
+                a[j1 + 1] = yi;
+                a[k1] = xr;
+                a[k1 + 1] = xi;
+            }
+            k1 = 4 * k + ip[m + k];
+            j1 = k1 + 2;
+            k1 += nh;
+            a[j1 - 1] = -a[j1 - 1];
+            xr = a[j1];
+            xi = -a[j1 + 1];
+            yr = a[k1];
+            yi = -a[k1 + 1];
+            a[j1] = yr;
+            a[j1 + 1] = yi;
+            a[k1] = xr;
+            a[k1 + 1] = xi;
+            a[k1 + 3] = -a[k1 + 3];
+            j1 += nm;
+            k1 += nm;
+            a[j1 - 1] = -a[j1 - 1];
+            xr = a[j1];
+            xi = -a[j1 + 1];
+            yr = a[k1];
+            yi = -a[k1 + 1];
+            a[j1] = yr;
+            a[j1 + 1] = yi;
+            a[k1] = xr;
+            a[k1 + 1] = xi;
+            a[k1 + 3] = -a[k1 + 3];
+        }
+    }
+}
+
+
+void bitrv216(double *a)
+{
+    double x1r, x1i, x2r, x2i, x3r, x3i, x4r, x4i, 
+        x5r, x5i, x7r, x7i, x8r, x8i, x10r, x10i, 
+        x11r, x11i, x12r, x12i, x13r, x13i, x14r, x14i;
+    
+    x1r = a[2];
+    x1i = a[3];
+    x2r = a[4];
+    x2i = a[5];
+    x3r = a[6];
+    x3i = a[7];
+    x4r = a[8];
+    x4i = a[9];
+    x5r = a[10];
+    x5i = a[11];
+    x7r = a[14];
+    x7i = a[15];
+    x8r = a[16];
+    x8i = a[17];
+    x10r = a[20];
+    x10i = a[21];
+    x11r = a[22];
+    x11i = a[23];
+    x12r = a[24];
+    x12i = a[25];
+    x13r = a[26];
+    x13i = a[27];
+    x14r = a[28];
+    x14i = a[29];
+    a[2] = x8r;
+    a[3] = x8i;
+    a[4] = x4r;
+    a[5] = x4i;
+    a[6] = x12r;
+    a[7] = x12i;
+    a[8] = x2r;
+    a[9] = x2i;
+    a[10] = x10r;
+    a[11] = x10i;
+    a[14] = x14r;
+    a[15] = x14i;
+    a[16] = x1r;
+    a[17] = x1i;
+    a[20] = x5r;
+    a[21] = x5i;
+    a[22] = x13r;
+    a[23] = x13i;
+    a[24] = x3r;
+    a[25] = x3i;
+    a[26] = x11r;
+    a[27] = x11i;
+    a[28] = x7r;
+    a[29] = x7i;
+}
+
+
+void bitrv216neg(double *a)
+{
+    double x1r, x1i, x2r, x2i, x3r, x3i, x4r, x4i, 
+        x5r, x5i, x6r, x6i, x7r, x7i, x8r, x8i, 
+        x9r, x9i, x10r, x10i, x11r, x11i, x12r, x12i, 
+        x13r, x13i, x14r, x14i, x15r, x15i;
+    
+    x1r = a[2];
+    x1i = a[3];
+    x2r = a[4];
+    x2i = a[5];
+    x3r = a[6];
+    x3i = a[7];
+    x4r = a[8];
+    x4i = a[9];
+    x5r = a[10];
+    x5i = a[11];
+    x6r = a[12];
+    x6i = a[13];
+    x7r = a[14];
+    x7i = a[15];
+    x8r = a[16];
+    x8i = a[17];
+    x9r = a[18];
+    x9i = a[19];
+    x10r = a[20];
+    x10i = a[21];
+    x11r = a[22];
+    x11i = a[23];
+    x12r = a[24];
+    x12i = a[25];
+    x13r = a[26];
+    x13i = a[27];
+    x14r = a[28];
+    x14i = a[29];
+    x15r = a[30];
+    x15i = a[31];
+    a[2] = x15r;
+    a[3] = x15i;
+    a[4] = x7r;
+    a[5] = x7i;
+    a[6] = x11r;
+    a[7] = x11i;
+    a[8] = x3r;
+    a[9] = x3i;
+    a[10] = x13r;
+    a[11] = x13i;
+    a[12] = x5r;
+    a[13] = x5i;
+    a[14] = x9r;
+    a[15] = x9i;
+    a[16] = x1r;
+    a[17] = x1i;
+    a[18] = x14r;
+    a[19] = x14i;
+    a[20] = x6r;
+    a[21] = x6i;
+    a[22] = x10r;
+    a[23] = x10i;
+    a[24] = x2r;
+    a[25] = x2i;
+    a[26] = x12r;
+    a[27] = x12i;
+    a[28] = x4r;
+    a[29] = x4i;
+    a[30] = x8r;
+    a[31] = x8i;
+}
+
+
+void bitrv208(double *a)
+{
+    double x1r, x1i, x3r, x3i, x4r, x4i, x6r, x6i;
+    
+    x1r = a[2];
+    x1i = a[3];
+    x3r = a[6];
+    x3i = a[7];
+    x4r = a[8];
+    x4i = a[9];
+    x6r = a[12];
+    x6i = a[13];
+    a[2] = x4r;
+    a[3] = x4i;
+    a[6] = x6r;
+    a[7] = x6i;
+    a[8] = x1r;
+    a[9] = x1i;
+    a[12] = x3r;
+    a[13] = x3i;
+}
+
+
+void bitrv208neg(double *a)
+{
+    double x1r, x1i, x2r, x2i, x3r, x3i, x4r, x4i, 
+        x5r, x5i, x6r, x6i, x7r, x7i;
+    
+    x1r = a[2];
+    x1i = a[3];
+    x2r = a[4];
+    x2i = a[5];
+    x3r = a[6];
+    x3i = a[7];
+    x4r = a[8];
+    x4i = a[9];
+    x5r = a[10];
+    x5i = a[11];
+    x6r = a[12];
+    x6i = a[13];
+    x7r = a[14];
+    x7i = a[15];
+    a[2] = x7r;
+    a[3] = x7i;
+    a[4] = x3r;
+    a[5] = x3i;
+    a[6] = x5r;
+    a[7] = x5i;
+    a[8] = x1r;
+    a[9] = x1i;
+    a[10] = x6r;
+    a[11] = x6i;
+    a[12] = x2r;
+    a[13] = x2i;
+    a[14] = x4r;
+    a[15] = x4i;
+}
+
+
+void cftf1st(int n, double *a, double *w)
+{
+    int j, j0, j1, j2, j3, k, m, mh;
+    double wn4r, csc1, csc3, wk1r, wk1i, wk3r, wk3i, 
+        wd1r, wd1i, wd3r, wd3i;
+    double x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i, 
+        y0r, y0i, y1r, y1i, y2r, y2i, y3r, y3i;
+    
+    mh = n >> 3;
+    m = 2 * mh;
+    j1 = m;
+    j2 = j1 + m;
+    j3 = j2 + m;
+    x0r = a[0] + a[j2];
+    x0i = a[1] + a[j2 + 1];
+    x1r = a[0] - a[j2];
+    x1i = a[1] - a[j2 + 1];
+    x2r = a[j1] + a[j3];
+    x2i = a[j1 + 1] + a[j3 + 1];
+    x3r = a[j1] - a[j3];
+    x3i = a[j1 + 1] - a[j3 + 1];
+    a[0] = x0r + x2r;
+    a[1] = x0i + x2i;
+    a[j1] = x0r - x2r;
+    a[j1 + 1] = x0i - x2i;
+    a[j2] = x1r - x3i;
+    a[j2 + 1] = x1i + x3r;
+    a[j3] = x1r + x3i;
+    a[j3 + 1] = x1i - x3r;
+    wn4r = w[1];
+    csc1 = w[2];
+    csc3 = w[3];
+    wd1r = 1;
+    wd1i = 0;
+    wd3r = 1;
+    wd3i = 0;
+    k = 0;
+    for (j = 2; j < mh - 2; j += 4) {
+        k += 4;
+        wk1r = csc1 * (wd1r + w[k]);
+        wk1i = csc1 * (wd1i + w[k + 1]);
+        wk3r = csc3 * (wd3r + w[k + 2]);
+        wk3i = csc3 * (wd3i + w[k + 3]);
+        wd1r = w[k];
+        wd1i = w[k + 1];
+        wd3r = w[k + 2];
+        wd3i = w[k + 3];
+        j1 = j + m;
+        j2 = j1 + m;
+        j3 = j2 + m;
+        x0r = a[j] + a[j2];
+        x0i = a[j + 1] + a[j2 + 1];
+        x1r = a[j] - a[j2];
+        x1i = a[j + 1] - a[j2 + 1];
+        y0r = a[j + 2] + a[j2 + 2];
+        y0i = a[j + 3] + a[j2 + 3];
+        y1r = a[j + 2] - a[j2 + 2];
+        y1i = a[j + 3] - a[j2 + 3];
+        x2r = a[j1] + a[j3];
+        x2i = a[j1 + 1] + a[j3 + 1];
+        x3r = a[j1] - a[j3];
+        x3i = a[j1 + 1] - a[j3 + 1];
+        y2r = a[j1 + 2] + a[j3 + 2];
+        y2i = a[j1 + 3] + a[j3 + 3];
+        y3r = a[j1 + 2] - a[j3 + 2];
+        y3i = a[j1 + 3] - a[j3 + 3];
+        a[j] = x0r + x2r;
+        a[j + 1] = x0i + x2i;
+        a[j + 2] = y0r + y2r;
+        a[j + 3] = y0i + y2i;
+        a[j1] = x0r - x2r;
+        a[j1 + 1] = x0i - x2i;
+        a[j1 + 2] = y0r - y2r;
+        a[j1 + 3] = y0i - y2i;
+        x0r = x1r - x3i;
+        x0i = x1i + x3r;
+        a[j2] = wk1r * x0r - wk1i * x0i;
+        a[j2 + 1] = wk1r * x0i + wk1i * x0r;
+        x0r = y1r - y3i;
+        x0i = y1i + y3r;
+        a[j2 + 2] = wd1r * x0r - wd1i * x0i;
+        a[j2 + 3] = wd1r * x0i + wd1i * x0r;
+        x0r = x1r + x3i;
+        x0i = x1i - x3r;
+        a[j3] = wk3r * x0r + wk3i * x0i;
+        a[j3 + 1] = wk3r * x0i - wk3i * x0r;
+        x0r = y1r + y3i;
+        x0i = y1i - y3r;
+        a[j3 + 2] = wd3r * x0r + wd3i * x0i;
+        a[j3 + 3] = wd3r * x0i - wd3i * x0r;
+        j0 = m - j;
+        j1 = j0 + m;
+        j2 = j1 + m;
+        j3 = j2 + m;
+        x0r = a[j0] + a[j2];
+        x0i = a[j0 + 1] + a[j2 + 1];
+        x1r = a[j0] - a[j2];
+        x1i = a[j0 + 1] - a[j2 + 1];
+        y0r = a[j0 - 2] + a[j2 - 2];
+        y0i = a[j0 - 1] + a[j2 - 1];
+        y1r = a[j0 - 2] - a[j2 - 2];
+        y1i = a[j0 - 1] - a[j2 - 1];
+        x2r = a[j1] + a[j3];
+        x2i = a[j1 + 1] + a[j3 + 1];
+        x3r = a[j1] - a[j3];
+        x3i = a[j1 + 1] - a[j3 + 1];
+        y2r = a[j1 - 2] + a[j3 - 2];
+        y2i = a[j1 - 1] + a[j3 - 1];
+        y3r = a[j1 - 2] - a[j3 - 2];
+        y3i = a[j1 - 1] - a[j3 - 1];
+        a[j0] = x0r + x2r;
+        a[j0 + 1] = x0i + x2i;
+        a[j0 - 2] = y0r + y2r;
+        a[j0 - 1] = y0i + y2i;
+        a[j1] = x0r - x2r;
+        a[j1 + 1] = x0i - x2i;
+        a[j1 - 2] = y0r - y2r;
+        a[j1 - 1] = y0i - y2i;
+        x0r = x1r - x3i;
+        x0i = x1i + x3r;
+        a[j2] = wk1i * x0r - wk1r * x0i;
+        a[j2 + 1] = wk1i * x0i + wk1r * x0r;
+        x0r = y1r - y3i;
+        x0i = y1i + y3r;
+        a[j2 - 2] = wd1i * x0r - wd1r * x0i;
+        a[j2 - 1] = wd1i * x0i + wd1r * x0r;
+        x0r = x1r + x3i;
+        x0i = x1i - x3r;
+        a[j3] = wk3i * x0r + wk3r * x0i;
+        a[j3 + 1] = wk3i * x0i - wk3r * x0r;
+        x0r = y1r + y3i;
+        x0i = y1i - y3r;
+        a[j3 - 2] = wd3i * x0r + wd3r * x0i;
+        a[j3 - 1] = wd3i * x0i - wd3r * x0r;
+    }
+    wk1r = csc1 * (wd1r + wn4r);
+    wk1i = csc1 * (wd1i + wn4r);
+    wk3r = csc3 * (wd3r - wn4r);
+    wk3i = csc3 * (wd3i - wn4r);
+    j0 = mh;
+    j1 = j0 + m;
+    j2 = j1 + m;
+    j3 = j2 + m;
+    x0r = a[j0 - 2] + a[j2 - 2];
+    x0i = a[j0 - 1] + a[j2 - 1];
+    x1r = a[j0 - 2] - a[j2 - 2];
+    x1i = a[j0 - 1] - a[j2 - 1];
+    x2r = a[j1 - 2] + a[j3 - 2];
+    x2i = a[j1 - 1] + a[j3 - 1];
+    x3r = a[j1 - 2] - a[j3 - 2];
+    x3i = a[j1 - 1] - a[j3 - 1];
+    a[j0 - 2] = x0r + x2r;
+    a[j0 - 1] = x0i + x2i;
+    a[j1 - 2] = x0r - x2r;
+    a[j1 - 1] = x0i - x2i;
+    x0r = x1r - x3i;
+    x0i = x1i + x3r;
+    a[j2 - 2] = wk1r * x0r - wk1i * x0i;
+    a[j2 - 1] = wk1r * x0i + wk1i * x0r;
+    x0r = x1r + x3i;
+    x0i = x1i - x3r;
+    a[j3 - 2] = wk3r * x0r + wk3i * x0i;
+    a[j3 - 1] = wk3r * x0i - wk3i * x0r;
+    x0r = a[j0] + a[j2];
+    x0i = a[j0 + 1] + a[j2 + 1];
+    x1r = a[j0] - a[j2];
+    x1i = a[j0 + 1] - a[j2 + 1];
+    x2r = a[j1] + a[j3];
+    x2i = a[j1 + 1] + a[j3 + 1];
+    x3r = a[j1] - a[j3];
+    x3i = a[j1 + 1] - a[j3 + 1];
+    a[j0] = x0r + x2r;
+    a[j0 + 1] = x0i + x2i;
+    a[j1] = x0r - x2r;
+    a[j1 + 1] = x0i - x2i;
+    x0r = x1r - x3i;
+    x0i = x1i + x3r;
+    a[j2] = wn4r * (x0r - x0i);
+    a[j2 + 1] = wn4r * (x0i + x0r);
+    x0r = x1r + x3i;
+    x0i = x1i - x3r;
+    a[j3] = -wn4r * (x0r + x0i);
+    a[j3 + 1] = -wn4r * (x0i - x0r);
+    x0r = a[j0 + 2] + a[j2 + 2];
+    x0i = a[j0 + 3] + a[j2 + 3];
+    x1r = a[j0 + 2] - a[j2 + 2];
+    x1i = a[j0 + 3] - a[j2 + 3];
+    x2r = a[j1 + 2] + a[j3 + 2];
+    x2i = a[j1 + 3] + a[j3 + 3];
+    x3r = a[j1 + 2] - a[j3 + 2];
+    x3i = a[j1 + 3] - a[j3 + 3];
+    a[j0 + 2] = x0r + x2r;
+    a[j0 + 3] = x0i + x2i;
+    a[j1 + 2] = x0r - x2r;
+    a[j1 + 3] = x0i - x2i;
+    x0r = x1r - x3i;
+    x0i = x1i + x3r;
+    a[j2 + 2] = wk1i * x0r - wk1r * x0i;
+    a[j2 + 3] = wk1i * x0i + wk1r * x0r;
+    x0r = x1r + x3i;
+    x0i = x1i - x3r;
+    a[j3 + 2] = wk3i * x0r + wk3r * x0i;
+    a[j3 + 3] = wk3i * x0i - wk3r * x0r;
+}
+
+
+void cftb1st(int n, double *a, double *w)
+{
+    int j, j0, j1, j2, j3, k, m, mh;
+    double wn4r, csc1, csc3, wk1r, wk1i, wk3r, wk3i, 
+        wd1r, wd1i, wd3r, wd3i;
+    double x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i, 
+        y0r, y0i, y1r, y1i, y2r, y2i, y3r, y3i;
+    
+    mh = n >> 3;
+    m = 2 * mh;
+    j1 = m;
+    j2 = j1 + m;
+    j3 = j2 + m;
+    x0r = a[0] + a[j2];
+    x0i = -a[1] - a[j2 + 1];
+    x1r = a[0] - a[j2];
+    x1i = -a[1] + a[j2 + 1];
+    x2r = a[j1] + a[j3];
+    x2i = a[j1 + 1] + a[j3 + 1];
+    x3r = a[j1] - a[j3];
+    x3i = a[j1 + 1] - a[j3 + 1];
+    a[0] = x0r + x2r;
+    a[1] = x0i - x2i;
+    a[j1] = x0r - x2r;
+    a[j1 + 1] = x0i + x2i;
+    a[j2] = x1r + x3i;
+    a[j2 + 1] = x1i + x3r;
+    a[j3] = x1r - x3i;
+    a[j3 + 1] = x1i - x3r;
+    wn4r = w[1];
+    csc1 = w[2];
+    csc3 = w[3];
+    wd1r = 1;
+    wd1i = 0;
+    wd3r = 1;
+    wd3i = 0;
+    k = 0;
+    for (j = 2; j < mh - 2; j += 4) {
+        k += 4;
+        wk1r = csc1 * (wd1r + w[k]);
+        wk1i = csc1 * (wd1i + w[k + 1]);
+        wk3r = csc3 * (wd3r + w[k + 2]);
+        wk3i = csc3 * (wd3i + w[k + 3]);
+        wd1r = w[k];
+        wd1i = w[k + 1];
+        wd3r = w[k + 2];
+        wd3i = w[k + 3];
+        j1 = j + m;
+        j2 = j1 + m;
+        j3 = j2 + m;
+        x0r = a[j] + a[j2];
+        x0i = -a[j + 1] - a[j2 + 1];
+        x1r = a[j] - a[j2];
+        x1i = -a[j + 1] + a[j2 + 1];
+        y0r = a[j + 2] + a[j2 + 2];
+        y0i = -a[j + 3] - a[j2 + 3];
+        y1r = a[j + 2] - a[j2 + 2];
+        y1i = -a[j + 3] + a[j2 + 3];
+        x2r = a[j1] + a[j3];
+        x2i = a[j1 + 1] + a[j3 + 1];
+        x3r = a[j1] - a[j3];
+        x3i = a[j1 + 1] - a[j3 + 1];
+        y2r = a[j1 + 2] + a[j3 + 2];
+        y2i = a[j1 + 3] + a[j3 + 3];
+        y3r = a[j1 + 2] - a[j3 + 2];
+        y3i = a[j1 + 3] - a[j3 + 3];
+        a[j] = x0r + x2r;
+        a[j + 1] = x0i - x2i;
+        a[j + 2] = y0r + y2r;
+        a[j + 3] = y0i - y2i;
+        a[j1] = x0r - x2r;
+        a[j1 + 1] = x0i + x2i;
+        a[j1 + 2] = y0r - y2r;
+        a[j1 + 3] = y0i + y2i;
+        x0r = x1r + x3i;
+        x0i = x1i + x3r;
+        a[j2] = wk1r * x0r - wk1i * x0i;
+        a[j2 + 1] = wk1r * x0i + wk1i * x0r;
+        x0r = y1r + y3i;
+        x0i = y1i + y3r;
+        a[j2 + 2] = wd1r * x0r - wd1i * x0i;
+        a[j2 + 3] = wd1r * x0i + wd1i * x0r;
+        x0r = x1r - x3i;
+        x0i = x1i - x3r;
+        a[j3] = wk3r * x0r + wk3i * x0i;
+        a[j3 + 1] = wk3r * x0i - wk3i * x0r;
+        x0r = y1r - y3i;
+        x0i = y1i - y3r;
+        a[j3 + 2] = wd3r * x0r + wd3i * x0i;
+        a[j3 + 3] = wd3r * x0i - wd3i * x0r;
+        j0 = m - j;
+        j1 = j0 + m;
+        j2 = j1 + m;
+        j3 = j2 + m;
+        x0r = a[j0] + a[j2];
+        x0i = -a[j0 + 1] - a[j2 + 1];
+        x1r = a[j0] - a[j2];
+        x1i = -a[j0 + 1] + a[j2 + 1];
+        y0r = a[j0 - 2] + a[j2 - 2];
+        y0i = -a[j0 - 1] - a[j2 - 1];
+        y1r = a[j0 - 2] - a[j2 - 2];
+        y1i = -a[j0 - 1] + a[j2 - 1];
+        x2r = a[j1] + a[j3];
+        x2i = a[j1 + 1] + a[j3 + 1];
+        x3r = a[j1] - a[j3];
+        x3i = a[j1 + 1] - a[j3 + 1];
+        y2r = a[j1 - 2] + a[j3 - 2];
+        y2i = a[j1 - 1] + a[j3 - 1];
+        y3r = a[j1 - 2] - a[j3 - 2];
+        y3i = a[j1 - 1] - a[j3 - 1];
+        a[j0] = x0r + x2r;
+        a[j0 + 1] = x0i - x2i;
+        a[j0 - 2] = y0r + y2r;
+        a[j0 - 1] = y0i - y2i;
+        a[j1] = x0r - x2r;
+        a[j1 + 1] = x0i + x2i;
+        a[j1 - 2] = y0r - y2r;
+        a[j1 - 1] = y0i + y2i;
+        x0r = x1r + x3i;
+        x0i = x1i + x3r;
+        a[j2] = wk1i * x0r - wk1r * x0i;
+        a[j2 + 1] = wk1i * x0i + wk1r * x0r;
+        x0r = y1r + y3i;
+        x0i = y1i + y3r;
+        a[j2 - 2] = wd1i * x0r - wd1r * x0i;
+        a[j2 - 1] = wd1i * x0i + wd1r * x0r;
+        x0r = x1r - x3i;
+        x0i = x1i - x3r;
+        a[j3] = wk3i * x0r + wk3r * x0i;
+        a[j3 + 1] = wk3i * x0i - wk3r * x0r;
+        x0r = y1r - y3i;
+        x0i = y1i - y3r;
+        a[j3 - 2] = wd3i * x0r + wd3r * x0i;
+        a[j3 - 1] = wd3i * x0i - wd3r * x0r;
+    }
+    wk1r = csc1 * (wd1r + wn4r);
+    wk1i = csc1 * (wd1i + wn4r);
+    wk3r = csc3 * (wd3r - wn4r);
+    wk3i = csc3 * (wd3i - wn4r);
+    j0 = mh;
+    j1 = j0 + m;
+    j2 = j1 + m;
+    j3 = j2 + m;
+    x0r = a[j0 - 2] + a[j2 - 2];
+    x0i = -a[j0 - 1] - a[j2 - 1];
+    x1r = a[j0 - 2] - a[j2 - 2];
+    x1i = -a[j0 - 1] + a[j2 - 1];
+    x2r = a[j1 - 2] + a[j3 - 2];
+    x2i = a[j1 - 1] + a[j3 - 1];
+    x3r = a[j1 - 2] - a[j3 - 2];
+    x3i = a[j1 - 1] - a[j3 - 1];
+    a[j0 - 2] = x0r + x2r;
+    a[j0 - 1] = x0i - x2i;
+    a[j1 - 2] = x0r - x2r;
+    a[j1 - 1] = x0i + x2i;
+    x0r = x1r + x3i;
+    x0i = x1i + x3r;
+    a[j2 - 2] = wk1r * x0r - wk1i * x0i;
+    a[j2 - 1] = wk1r * x0i + wk1i * x0r;
+    x0r = x1r - x3i;
+    x0i = x1i - x3r;
+    a[j3 - 2] = wk3r * x0r + wk3i * x0i;
+    a[j3 - 1] = wk3r * x0i - wk3i * x0r;
+    x0r = a[j0] + a[j2];
+    x0i = -a[j0 + 1] - a[j2 + 1];
+    x1r = a[j0] - a[j2];
+    x1i = -a[j0 + 1] + a[j2 + 1];
+    x2r = a[j1] + a[j3];
+    x2i = a[j1 + 1] + a[j3 + 1];
+    x3r = a[j1] - a[j3];
+    x3i = a[j1 + 1] - a[j3 + 1];
+    a[j0] = x0r + x2r;
+    a[j0 + 1] = x0i - x2i;
+    a[j1] = x0r - x2r;
+    a[j1 + 1] = x0i + x2i;
+    x0r = x1r + x3i;
+    x0i = x1i + x3r;
+    a[j2] = wn4r * (x0r - x0i);
+    a[j2 + 1] = wn4r * (x0i + x0r);
+    x0r = x1r - x3i;
+    x0i = x1i - x3r;
+    a[j3] = -wn4r * (x0r + x0i);
+    a[j3 + 1] = -wn4r * (x0i - x0r);
+    x0r = a[j0 + 2] + a[j2 + 2];
+    x0i = -a[j0 + 3] - a[j2 + 3];
+    x1r = a[j0 + 2] - a[j2 + 2];
+    x1i = -a[j0 + 3] + a[j2 + 3];
+    x2r = a[j1 + 2] + a[j3 + 2];
+    x2i = a[j1 + 3] + a[j3 + 3];
+    x3r = a[j1 + 2] - a[j3 + 2];
+    x3i = a[j1 + 3] - a[j3 + 3];
+    a[j0 + 2] = x0r + x2r;
+    a[j0 + 3] = x0i - x2i;
+    a[j1 + 2] = x0r - x2r;
+    a[j1 + 3] = x0i + x2i;
+    x0r = x1r + x3i;
+    x0i = x1i + x3r;
+    a[j2 + 2] = wk1i * x0r - wk1r * x0i;
+    a[j2 + 3] = wk1i * x0i + wk1r * x0r;
+    x0r = x1r - x3i;
+    x0i = x1i - x3r;
+    a[j3 + 2] = wk3i * x0r + wk3r * x0i;
+    a[j3 + 3] = wk3i * x0i - wk3r * x0r;
+}
+
+
+#ifdef USE_CDFT_THREADS
+struct cdft_arg_st {
+    int n0;
+    int n;
+    double *a;
+    int nw;
+    double *w;
+};
+typedef struct cdft_arg_st cdft_arg_t;
+
+
+void cftrec4_th(int n, double *a, int nw, double *w)
+{
+    void *cftrec1_th(void *p);
+    void *cftrec2_th(void *p);
+    int i, idiv4, m, nthread;
+    cdft_thread_t th[4];
+    cdft_arg_t ag[4];
+    
+    nthread = 2;
+    idiv4 = 0;
+    m = n >> 1;
+    if (n > CDFT_4THREADS_BEGIN_N) {
+        nthread = 4;
+        idiv4 = 1;
+        m >>= 1;
+    }
+    for (i = 0; i < nthread; i++) {
+        ag[i].n0 = n;
+        ag[i].n = m;
+        ag[i].a = &a[i * m];
+        ag[i].nw = nw;
+        ag[i].w = w;
+        if (i != idiv4) {
+            cdft_thread_create(&th[i], cftrec1_th, &ag[i]);
+        } else {
+            cdft_thread_create(&th[i], cftrec2_th, &ag[i]);
+        }
+    }
+    for (i = 0; i < nthread; i++) {
+        cdft_thread_wait(th[i]);
+    }
+}
+
+
+void *cftrec1_th(void *p)
+{
+    int cfttree(int n, int j, int k, double *a, int nw, double *w);
+    void cftleaf(int n, int isplt, double *a, int nw, double *w);
+    void cftmdl1(int n, double *a, double *w);
+    int isplt, j, k, m, n, n0, nw;
+    double *a, *w;
+    
+    n0 = ((cdft_arg_t *) p)->n0;
+    n = ((cdft_arg_t *) p)->n;
+    a = ((cdft_arg_t *) p)->a;
+    nw = ((cdft_arg_t *) p)->nw;
+    w = ((cdft_arg_t *) p)->w;
+    m = n0;
+    while (m > 512) {
+        m >>= 2;
+        cftmdl1(m, &a[n - m], &w[nw - (m >> 1)]);
+    }
+    cftleaf(m, 1, &a[n - m], nw, w);
+    k = 0;
+    for (j = n - m; j > 0; j -= m) {
+        k++;
+        isplt = cfttree(m, j, k, a, nw, w);
+        cftleaf(m, isplt, &a[j - m], nw, w);
+    }
+    return (void *) 0;
+}
+
+
+void *cftrec2_th(void *p)
+{
+    int cfttree(int n, int j, int k, double *a, int nw, double *w);
+    void cftleaf(int n, int isplt, double *a, int nw, double *w);
+    void cftmdl2(int n, double *a, double *w);
+    int isplt, j, k, m, n, n0, nw;
+    double *a, *w;
+    
+    n0 = ((cdft_arg_t *) p)->n0;
+    n = ((cdft_arg_t *) p)->n;
+    a = ((cdft_arg_t *) p)->a;
+    nw = ((cdft_arg_t *) p)->nw;
+    w = ((cdft_arg_t *) p)->w;
+    k = 1;
+    m = n0;
+    while (m > 512) {
+        m >>= 2;
+        k <<= 2;
+        cftmdl2(m, &a[n - m], &w[nw - m]);
+    }
+    cftleaf(m, 0, &a[n - m], nw, w);
+    k >>= 1;
+    for (j = n - m; j > 0; j -= m) {
+        k++;
+        isplt = cfttree(m, j, k, a, nw, w);
+        cftleaf(m, isplt, &a[j - m], nw, w);
+    }
+    return (void *) 0;
+}
+#endif /* USE_CDFT_THREADS */
+
+
+void cftrec4(int n, double *a, int nw, double *w)
+{
+    int cfttree(int n, int j, int k, double *a, int nw, double *w);
+    void cftleaf(int n, int isplt, double *a, int nw, double *w);
+    void cftmdl1(int n, double *a, double *w);
+    int isplt, j, k, m;
+    
+    m = n;
+    while (m > 512) {
+        m >>= 2;
+        cftmdl1(m, &a[n - m], &w[nw - (m >> 1)]);
+    }
+    cftleaf(m, 1, &a[n - m], nw, w);
+    k = 0;
+    for (j = n - m; j > 0; j -= m) {
+        k++;
+        isplt = cfttree(m, j, k, a, nw, w);
+        cftleaf(m, isplt, &a[j - m], nw, w);
+    }
+}
+
+
+int cfttree(int n, int j, int k, double *a, int nw, double *w)
+{
+    void cftmdl1(int n, double *a, double *w);
+    void cftmdl2(int n, double *a, double *w);
+    int i, isplt, m;
+    
+    if ((k & 3) != 0) {
+        isplt = k & 1;
+        if (isplt != 0) {
+            cftmdl1(n, &a[j - n], &w[nw - (n >> 1)]);
+        } else {
+            cftmdl2(n, &a[j - n], &w[nw - n]);
+        }
+    } else {
+        m = n;
+        for (i = k; (i & 3) == 0; i >>= 2) {
+            m <<= 2;
+        }
+        isplt = i & 1;
+        if (isplt != 0) {
+            while (m > 128) {
+                cftmdl1(m, &a[j - m], &w[nw - (m >> 1)]);
+                m >>= 2;
+            }
+        } else {
+            while (m > 128) {
+                cftmdl2(m, &a[j - m], &w[nw - m]);
+                m >>= 2;
+            }
+        }
+    }
+    return isplt;
+}
+
+
+void cftleaf(int n, int isplt, double *a, int nw, double *w)
+{
+    void cftmdl1(int n, double *a, double *w);
+    void cftmdl2(int n, double *a, double *w);
+    void cftf161(double *a, double *w);
+    void cftf162(double *a, double *w);
+    void cftf081(double *a, double *w);
+    void cftf082(double *a, double *w);
+    
+    if (n == 512) {
+        cftmdl1(128, a, &w[nw - 64]);
+        cftf161(a, &w[nw - 8]);
+        cftf162(&a[32], &w[nw - 32]);
+        cftf161(&a[64], &w[nw - 8]);
+        cftf161(&a[96], &w[nw - 8]);
+        cftmdl2(128, &a[128], &w[nw - 128]);
+        cftf161(&a[128], &w[nw - 8]);
+        cftf162(&a[160], &w[nw - 32]);
+        cftf161(&a[192], &w[nw - 8]);
+        cftf162(&a[224], &w[nw - 32]);
+        cftmdl1(128, &a[256], &w[nw - 64]);
+        cftf161(&a[256], &w[nw - 8]);
+        cftf162(&a[288], &w[nw - 32]);
+        cftf161(&a[320], &w[nw - 8]);
+        cftf161(&a[352], &w[nw - 8]);
+        if (isplt != 0) {
+            cftmdl1(128, &a[384], &w[nw - 64]);
+            cftf161(&a[480], &w[nw - 8]);
+        } else {
+            cftmdl2(128, &a[384], &w[nw - 128]);
+            cftf162(&a[480], &w[nw - 32]);
+        }
+        cftf161(&a[384], &w[nw - 8]);
+        cftf162(&a[416], &w[nw - 32]);
+        cftf161(&a[448], &w[nw - 8]);
+    } else {
+        cftmdl1(64, a, &w[nw - 32]);
+        cftf081(a, &w[nw - 8]);
+        cftf082(&a[16], &w[nw - 8]);
+        cftf081(&a[32], &w[nw - 8]);
+        cftf081(&a[48], &w[nw - 8]);
+        cftmdl2(64, &a[64], &w[nw - 64]);
+        cftf081(&a[64], &w[nw - 8]);
+        cftf082(&a[80], &w[nw - 8]);
+        cftf081(&a[96], &w[nw - 8]);
+        cftf082(&a[112], &w[nw - 8]);
+        cftmdl1(64, &a[128], &w[nw - 32]);
+        cftf081(&a[128], &w[nw - 8]);
+        cftf082(&a[144], &w[nw - 8]);
+        cftf081(&a[160], &w[nw - 8]);
+        cftf081(&a[176], &w[nw - 8]);
+        if (isplt != 0) {
+            cftmdl1(64, &a[192], &w[nw - 32]);
+            cftf081(&a[240], &w[nw - 8]);
+        } else {
+            cftmdl2(64, &a[192], &w[nw - 64]);
+            cftf082(&a[240], &w[nw - 8]);
+        }
+        cftf081(&a[192], &w[nw - 8]);
+        cftf082(&a[208], &w[nw - 8]);
+        cftf081(&a[224], &w[nw - 8]);
+    }
+}
+
+
+void cftmdl1(int n, double *a, double *w)
+{
+    int j, j0, j1, j2, j3, k, m, mh;
+    double wn4r, wk1r, wk1i, wk3r, wk3i;
+    double x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i;
+    
+    mh = n >> 3;
+    m = 2 * mh;
+    j1 = m;
+    j2 = j1 + m;
+    j3 = j2 + m;
+    x0r = a[0] + a[j2];
+    x0i = a[1] + a[j2 + 1];
+    x1r = a[0] - a[j2];
+    x1i = a[1] - a[j2 + 1];
+    x2r = a[j1] + a[j3];
+    x2i = a[j1 + 1] + a[j3 + 1];
+    x3r = a[j1] - a[j3];
+    x3i = a[j1 + 1] - a[j3 + 1];
+    a[0] = x0r + x2r;
+    a[1] = x0i + x2i;
+    a[j1] = x0r - x2r;
+    a[j1 + 1] = x0i - x2i;
+    a[j2] = x1r - x3i;
+    a[j2 + 1] = x1i + x3r;
+    a[j3] = x1r + x3i;
+    a[j3 + 1] = x1i - x3r;
+    wn4r = w[1];
+    k = 0;
+    for (j = 2; j < mh; j += 2) {
+        k += 4;
+        wk1r = w[k];
+        wk1i = w[k + 1];
+        wk3r = w[k + 2];
+        wk3i = w[k + 3];
+        j1 = j + m;
+        j2 = j1 + m;
+        j3 = j2 + m;
+        x0r = a[j] + a[j2];
+        x0i = a[j + 1] + a[j2 + 1];
+        x1r = a[j] - a[j2];
+        x1i = a[j + 1] - a[j2 + 1];
+        x2r = a[j1] + a[j3];
+        x2i = a[j1 + 1] + a[j3 + 1];
+        x3r = a[j1] - a[j3];
+        x3i = a[j1 + 1] - a[j3 + 1];
+        a[j] = x0r + x2r;
+        a[j + 1] = x0i + x2i;
+        a[j1] = x0r - x2r;
+        a[j1 + 1] = x0i - x2i;
+        x0r = x1r - x3i;
+        x0i = x1i + x3r;
+        a[j2] = wk1r * x0r - wk1i * x0i;
+        a[j2 + 1] = wk1r * x0i + wk1i * x0r;
+        x0r = x1r + x3i;
+        x0i = x1i - x3r;
+        a[j3] = wk3r * x0r + wk3i * x0i;
+        a[j3 + 1] = wk3r * x0i - wk3i * x0r;
+        j0 = m - j;
+        j1 = j0 + m;
+        j2 = j1 + m;
+        j3 = j2 + m;
+        x0r = a[j0] + a[j2];
+        x0i = a[j0 + 1] + a[j2 + 1];
+        x1r = a[j0] - a[j2];
+        x1i = a[j0 + 1] - a[j2 + 1];
+        x2r = a[j1] + a[j3];
+        x2i = a[j1 + 1] + a[j3 + 1];
+        x3r = a[j1] - a[j3];
+        x3i = a[j1 + 1] - a[j3 + 1];
+        a[j0] = x0r + x2r;
+        a[j0 + 1] = x0i + x2i;
+        a[j1] = x0r - x2r;
+        a[j1 + 1] = x0i - x2i;
+        x0r = x1r - x3i;
+        x0i = x1i + x3r;
+        a[j2] = wk1i * x0r - wk1r * x0i;
+        a[j2 + 1] = wk1i * x0i + wk1r * x0r;
+        x0r = x1r + x3i;
+        x0i = x1i - x3r;
+        a[j3] = wk3i * x0r + wk3r * x0i;
+        a[j3 + 1] = wk3i * x0i - wk3r * x0r;
+    }
+    j0 = mh;
+    j1 = j0 + m;
+    j2 = j1 + m;
+    j3 = j2 + m;
+    x0r = a[j0] + a[j2];
+    x0i = a[j0 + 1] + a[j2 + 1];
+    x1r = a[j0] - a[j2];
+    x1i = a[j0 + 1] - a[j2 + 1];
+    x2r = a[j1] + a[j3];
+    x2i = a[j1 + 1] + a[j3 + 1];
+    x3r = a[j1] - a[j3];
+    x3i = a[j1 + 1] - a[j3 + 1];
+    a[j0] = x0r + x2r;
+    a[j0 + 1] = x0i + x2i;
+    a[j1] = x0r - x2r;
+    a[j1 + 1] = x0i - x2i;
+    x0r = x1r - x3i;
+    x0i = x1i + x3r;
+    a[j2] = wn4r * (x0r - x0i);
+    a[j2 + 1] = wn4r * (x0i + x0r);
+    x0r = x1r + x3i;
+    x0i = x1i - x3r;
+    a[j3] = -wn4r * (x0r + x0i);
+    a[j3 + 1] = -wn4r * (x0i - x0r);
+}
+
+
+void cftmdl2(int n, double *a, double *w)
+{
+    int j, j0, j1, j2, j3, k, kr, m, mh;
+    double wn4r, wk1r, wk1i, wk3r, wk3i, wd1r, wd1i, wd3r, wd3i;
+    double x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i, y0r, y0i, y2r, y2i;
+    
+    mh = n >> 3;
+    m = 2 * mh;
+    wn4r = w[1];
+    j1 = m;
+    j2 = j1 + m;
+    j3 = j2 + m;
+    x0r = a[0] - a[j2 + 1];
+    x0i = a[1] + a[j2];
+    x1r = a[0] + a[j2 + 1];
+    x1i = a[1] - a[j2];
+    x2r = a[j1] - a[j3 + 1];
+    x2i = a[j1 + 1] + a[j3];
+    x3r = a[j1] + a[j3 + 1];
+    x3i = a[j1 + 1] - a[j3];
+    y0r = wn4r * (x2r - x2i);
+    y0i = wn4r * (x2i + x2r);
+    a[0] = x0r + y0r;
+    a[1] = x0i + y0i;
+    a[j1] = x0r - y0r;
+    a[j1 + 1] = x0i - y0i;
+    y0r = wn4r * (x3r - x3i);
+    y0i = wn4r * (x3i + x3r);
+    a[j2] = x1r - y0i;
+    a[j2 + 1] = x1i + y0r;
+    a[j3] = x1r + y0i;
+    a[j3 + 1] = x1i - y0r;
+    k = 0;
+    kr = 2 * m;
+    for (j = 2; j < mh; j += 2) {
+        k += 4;
+        wk1r = w[k];
+        wk1i = w[k + 1];
+        wk3r = w[k + 2];
+        wk3i = w[k + 3];
+        kr -= 4;
+        wd1i = w[kr];
+        wd1r = w[kr + 1];
+        wd3i = w[kr + 2];
+        wd3r = w[kr + 3];
+        j1 = j + m;
+        j2 = j1 + m;
+        j3 = j2 + m;
+        x0r = a[j] - a[j2 + 1];
+        x0i = a[j + 1] + a[j2];
+        x1r = a[j] + a[j2 + 1];
+        x1i = a[j + 1] - a[j2];
+        x2r = a[j1] - a[j3 + 1];
+        x2i = a[j1 + 1] + a[j3];
+        x3r = a[j1] + a[j3 + 1];
+        x3i = a[j1 + 1] - a[j3];
+        y0r = wk1r * x0r - wk1i * x0i;
+        y0i = wk1r * x0i + wk1i * x0r;
+        y2r = wd1r * x2r - wd1i * x2i;
+        y2i = wd1r * x2i + wd1i * x2r;
+        a[j] = y0r + y2r;
+        a[j + 1] = y0i + y2i;
+        a[j1] = y0r - y2r;
+        a[j1 + 1] = y0i - y2i;
+        y0r = wk3r * x1r + wk3i * x1i;
+        y0i = wk3r * x1i - wk3i * x1r;
+        y2r = wd3r * x3r + wd3i * x3i;
+        y2i = wd3r * x3i - wd3i * x3r;
+        a[j2] = y0r + y2r;
+        a[j2 + 1] = y0i + y2i;
+        a[j3] = y0r - y2r;
+        a[j3 + 1] = y0i - y2i;
+        j0 = m - j;
+        j1 = j0 + m;
+        j2 = j1 + m;
+        j3 = j2 + m;
+        x0r = a[j0] - a[j2 + 1];
+        x0i = a[j0 + 1] + a[j2];
+        x1r = a[j0] + a[j2 + 1];
+        x1i = a[j0 + 1] - a[j2];
+        x2r = a[j1] - a[j3 + 1];
+        x2i = a[j1 + 1] + a[j3];
+        x3r = a[j1] + a[j3 + 1];
+        x3i = a[j1 + 1] - a[j3];
+        y0r = wd1i * x0r - wd1r * x0i;
+        y0i = wd1i * x0i + wd1r * x0r;
+        y2r = wk1i * x2r - wk1r * x2i;
+        y2i = wk1i * x2i + wk1r * x2r;
+        a[j0] = y0r + y2r;
+        a[j0 + 1] = y0i + y2i;
+        a[j1] = y0r - y2r;
+        a[j1 + 1] = y0i - y2i;
+        y0r = wd3i * x1r + wd3r * x1i;
+        y0i = wd3i * x1i - wd3r * x1r;
+        y2r = wk3i * x3r + wk3r * x3i;
+        y2i = wk3i * x3i - wk3r * x3r;
+        a[j2] = y0r + y2r;
+        a[j2 + 1] = y0i + y2i;
+        a[j3] = y0r - y2r;
+        a[j3 + 1] = y0i - y2i;
+    }
+    wk1r = w[m];
+    wk1i = w[m + 1];
+    j0 = mh;
+    j1 = j0 + m;
+    j2 = j1 + m;
+    j3 = j2 + m;
+    x0r = a[j0] - a[j2 + 1];
+    x0i = a[j0 + 1] + a[j2];
+    x1r = a[j0] + a[j2 + 1];
+    x1i = a[j0 + 1] - a[j2];
+    x2r = a[j1] - a[j3 + 1];
+    x2i = a[j1 + 1] + a[j3];
+    x3r = a[j1] + a[j3 + 1];
+    x3i = a[j1 + 1] - a[j3];
+    y0r = wk1r * x0r - wk1i * x0i;
+    y0i = wk1r * x0i + wk1i * x0r;
+    y2r = wk1i * x2r - wk1r * x2i;
+    y2i = wk1i * x2i + wk1r * x2r;
+    a[j0] = y0r + y2r;
+    a[j0 + 1] = y0i + y2i;
+    a[j1] = y0r - y2r;
+    a[j1 + 1] = y0i - y2i;
+    y0r = wk1i * x1r - wk1r * x1i;
+    y0i = wk1i * x1i + wk1r * x1r;
+    y2r = wk1r * x3r - wk1i * x3i;
+    y2i = wk1r * x3i + wk1i * x3r;
+    a[j2] = y0r - y2r;
+    a[j2 + 1] = y0i - y2i;
+    a[j3] = y0r + y2r;
+    a[j3 + 1] = y0i + y2i;
+}
+
+
+void cftfx41(int n, double *a, int nw, double *w)
+{
+    void cftf161(double *a, double *w);
+    void cftf162(double *a, double *w);
+    void cftf081(double *a, double *w);
+    void cftf082(double *a, double *w);
+    
+    if (n == 128) {
+        cftf161(a, &w[nw - 8]);
+        cftf162(&a[32], &w[nw - 32]);
+        cftf161(&a[64], &w[nw - 8]);
+        cftf161(&a[96], &w[nw - 8]);
+    } else {
+        cftf081(a, &w[nw - 8]);
+        cftf082(&a[16], &w[nw - 8]);
+        cftf081(&a[32], &w[nw - 8]);
+        cftf081(&a[48], &w[nw - 8]);
+    }
+}
+
+
+void cftf161(double *a, double *w)
+{
+    double wn4r, wk1r, wk1i, 
+        x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i, 
+        y0r, y0i, y1r, y1i, y2r, y2i, y3r, y3i, 
+        y4r, y4i, y5r, y5i, y6r, y6i, y7r, y7i, 
+        y8r, y8i, y9r, y9i, y10r, y10i, y11r, y11i, 
+        y12r, y12i, y13r, y13i, y14r, y14i, y15r, y15i;
+    
+    wn4r = w[1];
+    wk1r = w[2];
+    wk1i = w[3];
+    x0r = a[0] + a[16];
+    x0i = a[1] + a[17];
+    x1r = a[0] - a[16];
+    x1i = a[1] - a[17];
+    x2r = a[8] + a[24];
+    x2i = a[9] + a[25];
+    x3r = a[8] - a[24];
+    x3i = a[9] - a[25];
+    y0r = x0r + x2r;
+    y0i = x0i + x2i;
+    y4r = x0r - x2r;
+    y4i = x0i - x2i;
+    y8r = x1r - x3i;
+    y8i = x1i + x3r;
+    y12r = x1r + x3i;
+    y12i = x1i - x3r;
+    x0r = a[2] + a[18];
+    x0i = a[3] + a[19];
+    x1r = a[2] - a[18];
+    x1i = a[3] - a[19];
+    x2r = a[10] + a[26];
+    x2i = a[11] + a[27];
+    x3r = a[10] - a[26];
+    x3i = a[11] - a[27];
+    y1r = x0r + x2r;
+    y1i = x0i + x2i;
+    y5r = x0r - x2r;
+    y5i = x0i - x2i;
+    x0r = x1r - x3i;
+    x0i = x1i + x3r;
+    y9r = wk1r * x0r - wk1i * x0i;
+    y9i = wk1r * x0i + wk1i * x0r;
+    x0r = x1r + x3i;
+    x0i = x1i - x3r;
+    y13r = wk1i * x0r - wk1r * x0i;
+    y13i = wk1i * x0i + wk1r * x0r;
+    x0r = a[4] + a[20];
+    x0i = a[5] + a[21];
+    x1r = a[4] - a[20];
+    x1i = a[5] - a[21];
+    x2r = a[12] + a[28];
+    x2i = a[13] + a[29];
+    x3r = a[12] - a[28];
+    x3i = a[13] - a[29];
+    y2r = x0r + x2r;
+    y2i = x0i + x2i;
+    y6r = x0r - x2r;
+    y6i = x0i - x2i;
+    x0r = x1r - x3i;
+    x0i = x1i + x3r;
+    y10r = wn4r * (x0r - x0i);
+    y10i = wn4r * (x0i + x0r);
+    x0r = x1r + x3i;
+    x0i = x1i - x3r;
+    y14r = wn4r * (x0r + x0i);
+    y14i = wn4r * (x0i - x0r);
+    x0r = a[6] + a[22];
+    x0i = a[7] + a[23];
+    x1r = a[6] - a[22];
+    x1i = a[7] - a[23];
+    x2r = a[14] + a[30];
+    x2i = a[15] + a[31];
+    x3r = a[14] - a[30];
+    x3i = a[15] - a[31];
+    y3r = x0r + x2r;
+    y3i = x0i + x2i;
+    y7r = x0r - x2r;
+    y7i = x0i - x2i;
+    x0r = x1r - x3i;
+    x0i = x1i + x3r;
+    y11r = wk1i * x0r - wk1r * x0i;
+    y11i = wk1i * x0i + wk1r * x0r;
+    x0r = x1r + x3i;
+    x0i = x1i - x3r;
+    y15r = wk1r * x0r - wk1i * x0i;
+    y15i = wk1r * x0i + wk1i * x0r;
+    x0r = y12r - y14r;
+    x0i = y12i - y14i;
+    x1r = y12r + y14r;
+    x1i = y12i + y14i;
+    x2r = y13r - y15r;
+    x2i = y13i - y15i;
+    x3r = y13r + y15r;
+    x3i = y13i + y15i;
+    a[24] = x0r + x2r;
+    a[25] = x0i + x2i;
+    a[26] = x0r - x2r;
+    a[27] = x0i - x2i;
+    a[28] = x1r - x3i;
+    a[29] = x1i + x3r;
+    a[30] = x1r + x3i;
+    a[31] = x1i - x3r;
+    x0r = y8r + y10r;
+    x0i = y8i + y10i;
+    x1r = y8r - y10r;
+    x1i = y8i - y10i;
+    x2r = y9r + y11r;
+    x2i = y9i + y11i;
+    x3r = y9r - y11r;
+    x3i = y9i - y11i;
+    a[16] = x0r + x2r;
+    a[17] = x0i + x2i;
+    a[18] = x0r - x2r;
+    a[19] = x0i - x2i;
+    a[20] = x1r - x3i;
+    a[21] = x1i + x3r;
+    a[22] = x1r + x3i;
+    a[23] = x1i - x3r;
+    x0r = y5r - y7i;
+    x0i = y5i + y7r;
+    x2r = wn4r * (x0r - x0i);
+    x2i = wn4r * (x0i + x0r);
+    x0r = y5r + y7i;
+    x0i = y5i - y7r;
+    x3r = wn4r * (x0r - x0i);
+    x3i = wn4r * (x0i + x0r);
+    x0r = y4r - y6i;
+    x0i = y4i + y6r;
+    x1r = y4r + y6i;
+    x1i = y4i - y6r;
+    a[8] = x0r + x2r;
+    a[9] = x0i + x2i;
+    a[10] = x0r - x2r;
+    a[11] = x0i - x2i;
+    a[12] = x1r - x3i;
+    a[13] = x1i + x3r;
+    a[14] = x1r + x3i;
+    a[15] = x1i - x3r;
+    x0r = y0r + y2r;
+    x0i = y0i + y2i;
+    x1r = y0r - y2r;
+    x1i = y0i - y2i;
+    x2r = y1r + y3r;
+    x2i = y1i + y3i;
+    x3r = y1r - y3r;
+    x3i = y1i - y3i;
+    a[0] = x0r + x2r;
+    a[1] = x0i + x2i;
+    a[2] = x0r - x2r;
+    a[3] = x0i - x2i;
+    a[4] = x1r - x3i;
+    a[5] = x1i + x3r;
+    a[6] = x1r + x3i;
+    a[7] = x1i - x3r;
+}
+
+
+void cftf162(double *a, double *w)
+{
+    double wn4r, wk1r, wk1i, wk2r, wk2i, wk3r, wk3i, 
+        x0r, x0i, x1r, x1i, x2r, x2i, 
+        y0r, y0i, y1r, y1i, y2r, y2i, y3r, y3i, 
+        y4r, y4i, y5r, y5i, y6r, y6i, y7r, y7i, 
+        y8r, y8i, y9r, y9i, y10r, y10i, y11r, y11i, 
+        y12r, y12i, y13r, y13i, y14r, y14i, y15r, y15i;
+    
+    wn4r = w[1];
+    wk1r = w[4];
+    wk1i = w[5];
+    wk3r = w[6];
+    wk3i = -w[7];
+    wk2r = w[8];
+    wk2i = w[9];
+    x1r = a[0] - a[17];
+    x1i = a[1] + a[16];
+    x0r = a[8] - a[25];
+    x0i = a[9] + a[24];
+    x2r = wn4r * (x0r - x0i);
+    x2i = wn4r * (x0i + x0r);
+    y0r = x1r + x2r;
+    y0i = x1i + x2i;
+    y4r = x1r - x2r;
+    y4i = x1i - x2i;
+    x1r = a[0] + a[17];
+    x1i = a[1] - a[16];
+    x0r = a[8] + a[25];
+    x0i = a[9] - a[24];
+    x2r = wn4r * (x0r - x0i);
+    x2i = wn4r * (x0i + x0r);
+    y8r = x1r - x2i;
+    y8i = x1i + x2r;
+    y12r = x1r + x2i;
+    y12i = x1i - x2r;
+    x0r = a[2] - a[19];
+    x0i = a[3] + a[18];
+    x1r = wk1r * x0r - wk1i * x0i;
+    x1i = wk1r * x0i + wk1i * x0r;
+    x0r = a[10] - a[27];
+    x0i = a[11] + a[26];
+    x2r = wk3i * x0r - wk3r * x0i;
+    x2i = wk3i * x0i + wk3r * x0r;
+    y1r = x1r + x2r;
+    y1i = x1i + x2i;
+    y5r = x1r - x2r;
+    y5i = x1i - x2i;
+    x0r = a[2] + a[19];
+    x0i = a[3] - a[18];
+    x1r = wk3r * x0r - wk3i * x0i;
+    x1i = wk3r * x0i + wk3i * x0r;
+    x0r = a[10] + a[27];
+    x0i = a[11] - a[26];
+    x2r = wk1r * x0r + wk1i * x0i;
+    x2i = wk1r * x0i - wk1i * x0r;
+    y9r = x1r - x2r;
+    y9i = x1i - x2i;
+    y13r = x1r + x2r;
+    y13i = x1i + x2i;
+    x0r = a[4] - a[21];
+    x0i = a[5] + a[20];
+    x1r = wk2r * x0r - wk2i * x0i;
+    x1i = wk2r * x0i + wk2i * x0r;
+    x0r = a[12] - a[29];
+    x0i = a[13] + a[28];
+    x2r = wk2i * x0r - wk2r * x0i;
+    x2i = wk2i * x0i + wk2r * x0r;
+    y2r = x1r + x2r;
+    y2i = x1i + x2i;
+    y6r = x1r - x2r;
+    y6i = x1i - x2i;
+    x0r = a[4] + a[21];
+    x0i = a[5] - a[20];
+    x1r = wk2i * x0r - wk2r * x0i;
+    x1i = wk2i * x0i + wk2r * x0r;
+    x0r = a[12] + a[29];
+    x0i = a[13] - a[28];
+    x2r = wk2r * x0r - wk2i * x0i;
+    x2i = wk2r * x0i + wk2i * x0r;
+    y10r = x1r - x2r;
+    y10i = x1i - x2i;
+    y14r = x1r + x2r;
+    y14i = x1i + x2i;
+    x0r = a[6] - a[23];
+    x0i = a[7] + a[22];
+    x1r = wk3r * x0r - wk3i * x0i;
+    x1i = wk3r * x0i + wk3i * x0r;
+    x0r = a[14] - a[31];
+    x0i = a[15] + a[30];
+    x2r = wk1i * x0r - wk1r * x0i;
+    x2i = wk1i * x0i + wk1r * x0r;
+    y3r = x1r + x2r;
+    y3i = x1i + x2i;
+    y7r = x1r - x2r;
+    y7i = x1i - x2i;
+    x0r = a[6] + a[23];
+    x0i = a[7] - a[22];
+    x1r = wk1i * x0r + wk1r * x0i;
+    x1i = wk1i * x0i - wk1r * x0r;
+    x0r = a[14] + a[31];
+    x0i = a[15] - a[30];
+    x2r = wk3i * x0r - wk3r * x0i;
+    x2i = wk3i * x0i + wk3r * x0r;
+    y11r = x1r + x2r;
+    y11i = x1i + x2i;
+    y15r = x1r - x2r;
+    y15i = x1i - x2i;
+    x1r = y0r + y2r;
+    x1i = y0i + y2i;
+    x2r = y1r + y3r;
+    x2i = y1i + y3i;
+    a[0] = x1r + x2r;
+    a[1] = x1i + x2i;
+    a[2] = x1r - x2r;
+    a[3] = x1i - x2i;
+    x1r = y0r - y2r;
+    x1i = y0i - y2i;
+    x2r = y1r - y3r;
+    x2i = y1i - y3i;
+    a[4] = x1r - x2i;
+    a[5] = x1i + x2r;
+    a[6] = x1r + x2i;
+    a[7] = x1i - x2r;
+    x1r = y4r - y6i;
+    x1i = y4i + y6r;
+    x0r = y5r - y7i;
+    x0i = y5i + y7r;
+    x2r = wn4r * (x0r - x0i);
+    x2i = wn4r * (x0i + x0r);
+    a[8] = x1r + x2r;
+    a[9] = x1i + x2i;
+    a[10] = x1r - x2r;
+    a[11] = x1i - x2i;
+    x1r = y4r + y6i;
+    x1i = y4i - y6r;
+    x0r = y5r + y7i;
+    x0i = y5i - y7r;
+    x2r = wn4r * (x0r - x0i);
+    x2i = wn4r * (x0i + x0r);
+    a[12] = x1r - x2i;
+    a[13] = x1i + x2r;
+    a[14] = x1r + x2i;
+    a[15] = x1i - x2r;
+    x1r = y8r + y10r;
+    x1i = y8i + y10i;
+    x2r = y9r - y11r;
+    x2i = y9i - y11i;
+    a[16] = x1r + x2r;
+    a[17] = x1i + x2i;
+    a[18] = x1r - x2r;
+    a[19] = x1i - x2i;
+    x1r = y8r - y10r;
+    x1i = y8i - y10i;
+    x2r = y9r + y11r;
+    x2i = y9i + y11i;
+    a[20] = x1r - x2i;
+    a[21] = x1i + x2r;
+    a[22] = x1r + x2i;
+    a[23] = x1i - x2r;
+    x1r = y12r - y14i;
+    x1i = y12i + y14r;
+    x0r = y13r + y15i;
+    x0i = y13i - y15r;
+    x2r = wn4r * (x0r - x0i);
+    x2i = wn4r * (x0i + x0r);
+    a[24] = x1r + x2r;
+    a[25] = x1i + x2i;
+    a[26] = x1r - x2r;
+    a[27] = x1i - x2i;
+    x1r = y12r + y14i;
+    x1i = y12i - y14r;
+    x0r = y13r - y15i;
+    x0i = y13i + y15r;
+    x2r = wn4r * (x0r - x0i);
+    x2i = wn4r * (x0i + x0r);
+    a[28] = x1r - x2i;
+    a[29] = x1i + x2r;
+    a[30] = x1r + x2i;
+    a[31] = x1i - x2r;
+}
+
+
+void cftf081(double *a, double *w)
+{
+    double wn4r, x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i, 
+        y0r, y0i, y1r, y1i, y2r, y2i, y3r, y3i, 
+        y4r, y4i, y5r, y5i, y6r, y6i, y7r, y7i;
+    
+    wn4r = w[1];
+    x0r = a[0] + a[8];
+    x0i = a[1] + a[9];
+    x1r = a[0] - a[8];
+    x1i = a[1] - a[9];
+    x2r = a[4] + a[12];
+    x2i = a[5] + a[13];
+    x3r = a[4] - a[12];
+    x3i = a[5] - a[13];
+    y0r = x0r + x2r;
+    y0i = x0i + x2i;
+    y2r = x0r - x2r;
+    y2i = x0i - x2i;
+    y1r = x1r - x3i;
+    y1i = x1i + x3r;
+    y3r = x1r + x3i;
+    y3i = x1i - x3r;
+    x0r = a[2] + a[10];
+    x0i = a[3] + a[11];
+    x1r = a[2] - a[10];
+    x1i = a[3] - a[11];
+    x2r = a[6] + a[14];
+    x2i = a[7] + a[15];
+    x3r = a[6] - a[14];
+    x3i = a[7] - a[15];
+    y4r = x0r + x2r;
+    y4i = x0i + x2i;
+    y6r = x0r - x2r;
+    y6i = x0i - x2i;
+    x0r = x1r - x3i;
+    x0i = x1i + x3r;
+    x2r = x1r + x3i;
+    x2i = x1i - x3r;
+    y5r = wn4r * (x0r - x0i);
+    y5i = wn4r * (x0r + x0i);
+    y7r = wn4r * (x2r - x2i);
+    y7i = wn4r * (x2r + x2i);
+    a[8] = y1r + y5r;
+    a[9] = y1i + y5i;
+    a[10] = y1r - y5r;
+    a[11] = y1i - y5i;
+    a[12] = y3r - y7i;
+    a[13] = y3i + y7r;
+    a[14] = y3r + y7i;
+    a[15] = y3i - y7r;
+    a[0] = y0r + y4r;
+    a[1] = y0i + y4i;
+    a[2] = y0r - y4r;
+    a[3] = y0i - y4i;
+    a[4] = y2r - y6i;
+    a[5] = y2i + y6r;
+    a[6] = y2r + y6i;
+    a[7] = y2i - y6r;
+}
+
+
+void cftf082(double *a, double *w)
+{
+    double wn4r, wk1r, wk1i, x0r, x0i, x1r, x1i, 
+        y0r, y0i, y1r, y1i, y2r, y2i, y3r, y3i, 
+        y4r, y4i, y5r, y5i, y6r, y6i, y7r, y7i;
+    
+    wn4r = w[1];
+    wk1r = w[2];
+    wk1i = w[3];
+    y0r = a[0] - a[9];
+    y0i = a[1] + a[8];
+    y1r = a[0] + a[9];
+    y1i = a[1] - a[8];
+    x0r = a[4] - a[13];
+    x0i = a[5] + a[12];
+    y2r = wn4r * (x0r - x0i);
+    y2i = wn4r * (x0i + x0r);
+    x0r = a[4] + a[13];
+    x0i = a[5] - a[12];
+    y3r = wn4r * (x0r - x0i);
+    y3i = wn4r * (x0i + x0r);
+    x0r = a[2] - a[11];
+    x0i = a[3] + a[10];
+    y4r = wk1r * x0r - wk1i * x0i;
+    y4i = wk1r * x0i + wk1i * x0r;
+    x0r = a[2] + a[11];
+    x0i = a[3] - a[10];
+    y5r = wk1i * x0r - wk1r * x0i;
+    y5i = wk1i * x0i + wk1r * x0r;
+    x0r = a[6] - a[15];
+    x0i = a[7] + a[14];
+    y6r = wk1i * x0r - wk1r * x0i;
+    y6i = wk1i * x0i + wk1r * x0r;
+    x0r = a[6] + a[15];
+    x0i = a[7] - a[14];
+    y7r = wk1r * x0r - wk1i * x0i;
+    y7i = wk1r * x0i + wk1i * x0r;
+    x0r = y0r + y2r;
+    x0i = y0i + y2i;
+    x1r = y4r + y6r;
+    x1i = y4i + y6i;
+    a[0] = x0r + x1r;
+    a[1] = x0i + x1i;
+    a[2] = x0r - x1r;
+    a[3] = x0i - x1i;
+    x0r = y0r - y2r;
+    x0i = y0i - y2i;
+    x1r = y4r - y6r;
+    x1i = y4i - y6i;
+    a[4] = x0r - x1i;
+    a[5] = x0i + x1r;
+    a[6] = x0r + x1i;
+    a[7] = x0i - x1r;
+    x0r = y1r - y3i;
+    x0i = y1i + y3r;
+    x1r = y5r - y7r;
+    x1i = y5i - y7i;
+    a[8] = x0r + x1r;
+    a[9] = x0i + x1i;
+    a[10] = x0r - x1r;
+    a[11] = x0i - x1i;
+    x0r = y1r + y3i;
+    x0i = y1i - y3r;
+    x1r = y5r + y7r;
+    x1i = y5i + y7i;
+    a[12] = x0r - x1i;
+    a[13] = x0i + x1r;
+    a[14] = x0r + x1i;
+    a[15] = x0i - x1r;
+}
+
+
+void cftf040(double *a)
+{
+    double x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i;
+    
+    x0r = a[0] + a[4];
+    x0i = a[1] + a[5];
+    x1r = a[0] - a[4];
+    x1i = a[1] - a[5];
+    x2r = a[2] + a[6];
+    x2i = a[3] + a[7];
+    x3r = a[2] - a[6];
+    x3i = a[3] - a[7];
+    a[0] = x0r + x2r;
+    a[1] = x0i + x2i;
+    a[2] = x1r - x3i;
+    a[3] = x1i + x3r;
+    a[4] = x0r - x2r;
+    a[5] = x0i - x2i;
+    a[6] = x1r + x3i;
+    a[7] = x1i - x3r;
+}
+
+
+void cftb040(double *a)
+{
+    double x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i;
+    
+    x0r = a[0] + a[4];
+    x0i = a[1] + a[5];
+    x1r = a[0] - a[4];
+    x1i = a[1] - a[5];
+    x2r = a[2] + a[6];
+    x2i = a[3] + a[7];
+    x3r = a[2] - a[6];
+    x3i = a[3] - a[7];
+    a[0] = x0r + x2r;
+    a[1] = x0i + x2i;
+    a[2] = x1r + x3i;
+    a[3] = x1i - x3r;
+    a[4] = x0r - x2r;
+    a[5] = x0i - x2i;
+    a[6] = x1r - x3i;
+    a[7] = x1i + x3r;
+}
+
+
+void cftx020(double *a)
+{
+    double x0r, x0i;
+    
+    x0r = a[0] - a[2];
+    x0i = a[1] - a[3];
+    a[0] += a[2];
+    a[1] += a[3];
+    a[2] = x0r;
+    a[3] = x0i;
+}
+
+
+void rftfsub(int n, double *a, int nc, double *c)
+{
+    int j, k, kk, ks, m;
+    double wkr, wki, xr, xi, yr, yi;
+    
+    m = n >> 1;
+    ks = 2 * nc / m;
+    kk = 0;
+    for (j = 2; j < m; j += 2) {
+        k = n - j;
+        kk += ks;
+        wkr = 0.5 - c[nc - kk];
+        wki = c[kk];
+        xr = a[j] - a[k];
+        xi = a[j + 1] + a[k + 1];
+        yr = wkr * xr - wki * xi;
+        yi = wkr * xi + wki * xr;
+        a[j] -= yr;
+        a[j + 1] -= yi;
+        a[k] += yr;
+        a[k + 1] -= yi;
+    }
+}
+
+
+void rftbsub(int n, double *a, int nc, double *c)
+{
+    int j, k, kk, ks, m;
+    double wkr, wki, xr, xi, yr, yi;
+    
+    m = n >> 1;
+    ks = 2 * nc / m;
+    kk = 0;
+    for (j = 2; j < m; j += 2) {
+        k = n - j;
+        kk += ks;
+        wkr = 0.5 - c[nc - kk];
+        wki = c[kk];
+        xr = a[j] - a[k];
+        xi = a[j + 1] + a[k + 1];
+        yr = wkr * xr + wki * xi;
+        yi = wkr * xi - wki * xr;
+        a[j] -= yr;
+        a[j + 1] -= yi;
+        a[k] += yr;
+        a[k + 1] -= yi;
+    }
+}
+
+
+void dctsub(int n, double *a, int nc, double *c)
+{
+    int j, k, kk, ks, m;
+    double wkr, wki, xr;
+    
+    m = n >> 1;
+    ks = nc / n;
+    kk = 0;
+    for (j = 1; j < m; j++) {
+        k = n - j;
+        kk += ks;
+        wkr = c[kk] - c[nc - kk];
+        wki = c[kk] + c[nc - kk];
+        xr = wki * a[j] - wkr * a[k];
+        a[j] = wkr * a[j] + wki * a[k];
+        a[k] = xr;
+    }
+    a[m] *= c[0];
+}
+
+
+void dstsub(int n, double *a, int nc, double *c)
+{
+    int j, k, kk, ks, m;
+    double wkr, wki, xr;
+    
+    m = n >> 1;
+    ks = nc / n;
+    kk = 0;
+    for (j = 1; j < m; j++) {
+        k = n - j;
+        kk += ks;
+        wkr = c[kk] - c[nc - kk];
+        wki = c[kk] + c[nc - kk];
+        xr = wki * a[k] - wkr * a[j];
+        a[k] = wkr * a[k] + wki * a[j];
+        a[j] = xr;
+    }
+    a[m] *= c[0];
+}
+
diff --git a/modules/visualization/galaktos/func.c b/modules/visualization/galaktos/func.c
new file mode 100644 (file)
index 0000000..6fac372
--- /dev/null
@@ -0,0 +1,222 @@
+/* Function management */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "common.h"
+#include "fatal.h"
+
+#include "func_types.h"
+#include "func.h"
+
+#include "splaytree_types.h"
+#include "splaytree.h"
+#include "tree_types.h"
+
+#include "builtin_funcs.h"
+
+/* A splay tree of builtin functions */
+splaytree_t * builtin_func_tree;
+
+/* Private function prototypes */
+int compare_func(char * name, char * name2);
+int insert_func(func_t * name);
+void * copy_func_key(char * string);
+
+
+void * copy_func_key(char * string) {
+       
+       char * clone_string;
+       
+       if ((clone_string = malloc(MAX_TOKEN_SIZE)) == NULL)
+               return NULL;
+       
+       strncpy(clone_string, string, MAX_TOKEN_SIZE-1);
+       
+       return (void*)clone_string;
+}      
+
+
+func_t * create_func (char * name, double (*func_ptr)(), int num_args) {
+
+  func_t * func;
+  func = (func_t*)malloc(sizeof(func_t));
+  if (func == NULL)
+    return NULL;
+
+  
+  /* Clear name space */
+  memset(func->name, 0, MAX_TOKEN_SIZE);
+
+  /* Copy given name into function structure */
+  strncpy(func->name, name, MAX_TOKEN_SIZE); 
+
+  /* Assign value pointer */
+  func->func_ptr = func_ptr;
+  func->num_args = num_args;
+  /* Return instantiated function */
+  return func;
+
+}
+
+/* Initialize the builtin function database.
+   Should only be necessary once */
+int init_builtin_func_db() {
+  int retval;
+
+  builtin_func_tree = create_splaytree(compare_string, copy_string, free_string);
+
+  if (builtin_func_tree == NULL)
+    return OUTOFMEM_ERROR;
+
+  retval = load_all_builtin_func();
+  return SUCCESS;
+}
+
+
+/* Destroy the builtin function database.
+   Generally, do this on projectm exit */
+int destroy_builtin_func_db() {
+
+  splay_traverse(free_func, builtin_func_tree);
+  destroy_splaytree(builtin_func_tree);
+  return SUCCESS;
+
+}
+
+/* Insert a function into the database */
+int insert_func(func_t * func) {
+
+  if (func == NULL)
+    return ERROR;
+
+  splay_insert(func, func->name, builtin_func_tree);
+
+  return SUCCESS;
+}
+
+/* Frees a function type, real complicated... */
+void free_func(func_t * func) {
+  free(func);
+}
+
+/* Remove a function from the database */
+int remove_func(func_t * func) {
+
+  if (func == NULL)
+    return ERROR;
+
+    splay_delete(func->name, builtin_func_tree);
+
+  return SUCCESS;
+}
+
+/* Find a function given its name */
+func_t * find_func(char * name) {
+
+  func_t * func = NULL;
+
+  /* First look in the builtin database */
+  func = (func_t *)splay_find(name, builtin_func_tree);
+       
+  return func;
+
+}
+
+/* Compare string name with function name */
+int compare_func(char * name, char * name2) {
+
+  int cmpval;
+
+  /* Uses string comparison function */
+  cmpval = strncmp(name, name2, MAX_TOKEN_SIZE-1);
+  
+  return cmpval;
+}
+
+/* Loads a builtin function */
+int load_builtin_func(char * name,  double (*func_ptr)(), int num_args) {
+
+  func_t * func; 
+  int retval; 
+
+  /* Create new function */
+  func = create_func(name, func_ptr, num_args);
+
+  if (func == NULL)
+    return OUTOFMEM_ERROR;
+
+  retval = insert_func(func);
+
+  return retval;
+
+}
+
+/* Loads all builtin functions */
+int load_all_builtin_func() {
+
+  
+  if (load_builtin_func("int", int_wrapper, 1) < 0)
+    return ERROR;
+  if (load_builtin_func("abs", abs_wrapper, 1) < 0)
+    return ERROR;
+  if (load_builtin_func("sin", sin_wrapper, 1) < 0)
+    return ERROR;
+  if (load_builtin_func("cos", cos_wrapper, 1) < 0)
+    return ERROR;
+  if (load_builtin_func("tan", tan_wrapper, 1) < 0)
+    return ERROR;
+  if (load_builtin_func("asin", asin_wrapper, 1) < 0)
+    return ERROR;
+  if (load_builtin_func("acos", acos_wrapper, 1) < 0)
+    return ERROR;
+  if (load_builtin_func("atan", atan_wrapper, 1) < 0)
+    return ERROR;
+  if (load_builtin_func("sqr", sqr_wrapper, 1) < 0)
+    return ERROR;
+  if (load_builtin_func("sqrt", sqrt_wrapper, 1) < 0)
+    return ERROR;
+  if (load_builtin_func("pow", pow_wrapper, 2) < 0)
+    return ERROR;
+  if (load_builtin_func("exp", exp_wrapper, 1) < 0)
+    return ERROR;
+  if (load_builtin_func("log", log_wrapper, 1) < 0)
+    return ERROR;
+  if (load_builtin_func("log10", log10_wrapper, 1) < 0)
+    return ERROR;
+  if (load_builtin_func("sign", sign_wrapper, 1) < 0)
+    return ERROR;
+  if (load_builtin_func("min", min_wrapper, 2) < 0)
+    return ERROR;
+  if (load_builtin_func("max", max_wrapper, 2) < 0)
+    return ERROR;
+  if (load_builtin_func("sigmoid", sigmoid_wrapper, 2) < 0)
+    return ERROR;
+  if (load_builtin_func("atan2", atan2_wrapper, 2) < 0)
+    return ERROR;
+  if (load_builtin_func("rand", rand_wrapper, 1) < 0)
+    return ERROR;
+  if (load_builtin_func("band", band_wrapper, 2) < 0)
+    return ERROR;
+  if (load_builtin_func("bor", bor_wrapper, 2) < 0)
+    return ERROR;
+  if (load_builtin_func("bnot", bnot_wrapper, 1) < 0)
+    return ERROR;
+  if (load_builtin_func("if", if_wrapper, 3) < 0)
+    return ERROR;
+  if (load_builtin_func("equal", equal_wrapper, 2) < 0)
+    return ERROR;
+  if (load_builtin_func("above", above_wrapper, 2) < 0)
+    return ERROR;
+  if (load_builtin_func("below", below_wrapper, 2) < 0)
+    return ERROR;
+  if (load_builtin_func("nchoosek", nchoosek_wrapper, 2) < 0)
+    return ERROR;
+  if (load_builtin_func("fact", fact_wrapper, 1) < 0)
+    return ERROR;
+
+
+  return SUCCESS;
+}
diff --git a/modules/visualization/galaktos/func.h b/modules/visualization/galaktos/func.h
new file mode 100644 (file)
index 0000000..e83acd9
--- /dev/null
@@ -0,0 +1,14 @@
+#ifndef FUNC_H
+#define FUNC_H
+
+/* Public Prototypes */
+func_t * create_func (char * name, double (*func_ptr)(), int num_args);
+int remove_func(func_t * func);
+func_t * find_func(char * name);
+int init_builtin_func_db();
+int destroy_builtin_func_db();
+int load_all_builtin_func();
+int load_builtin_func(char * name, double (*func_ptr)(), int num_args);
+void free_func(func_t * func);
+
+#endif
diff --git a/modules/visualization/galaktos/func_types.h b/modules/visualization/galaktos/func_types.h
new file mode 100644 (file)
index 0000000..dcd7583
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef FUNC_TYPES_H
+#define FUNC_TYPES_H
+#include "common.h"
+
+
+/* Function Type */
+typedef struct FUNC_T {
+  char name[MAX_TOKEN_SIZE];  
+  double (*func_ptr)();
+  int num_args;
+} func_t;
+
+#endif
index 50b0bc9835c37fe5f5f49edfc8f304e2a65185bd..64e6019ae752e2c47b663cd927d437cf3640b148 100644 (file)
@@ -5,6 +5,7 @@
  * $Id$
  *
  * Authors: Cyril Deguet <asmax@videolan.org>
+ *          based on Scivi http://xmms-scivi.sourceforge.net
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -27,8 +28,8 @@
 #include <GL/glx.h>
 
 /* Local prototypes */
-static int CreateWindow( galaktos_thread_t *p_thread, XVisualInfo *p_vi,
-                         int i_width, int i_height );
+static void CreateWindow( galaktos_thread_t *p_thread, XVisualInfo *p_vi,
+                          int i_width, int i_height, int b_fullscreen );
 
 
 typedef struct
@@ -45,20 +46,28 @@ glx_data_t;
 #define OS_DATA ((glx_data_t*)(p_thread->p_os_data))
 
 
-int galaktos_glx_init( galaktos_thread_t *p_thread, int i_width, int i_height )
+int galaktos_glx_init( galaktos_thread_t *p_thread, int i_width, int i_height,
+                       int b_fullscreen )
 {
     Display *p_display;
     int i_opcode, i_evt, i_err;
     int i_maj, i_min;
     int i_nbelem;
     GLXFBConfig *p_fbconfs, fbconf;
+    XSetWindowAttributes xattr;
     XVisualInfo *p_vi;
     GLXContext gwctx;
     int i;
     GLXPbuffer gpbuf;
+#if 1
     int p_attr[] = { GLX_RED_SIZE, 5, GLX_GREEN_SIZE, 5,
                      GLX_BLUE_SIZE, 5, GLX_DOUBLEBUFFER, True,
                      GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, 0 };
+#else
+    int p_attr[] = { GLX_RGBA, GLX_RED_SIZE, 5, GLX_GREEN_SIZE, 5,
+                     GLX_BLUE_SIZE, 5, GLX_DOUBLEBUFFER,
+                     0 };
+#endif
 
     /* Initialize OS data */
     p_thread->p_os_data = malloc( sizeof( glx_data_t ) );
@@ -89,6 +98,7 @@ int galaktos_glx_init( galaktos_thread_t *p_thread, int i_width, int i_height )
         msg_Err( p_thread, "glXQueryVersion failed" );
         return -1;
     }
+#if 1
     if( i_maj <= 0 || ((i_maj == 1) && (i_min < 3)) )
     {
         msg_Err( p_thread, "GLX 1.3 is needed" );
@@ -116,16 +126,21 @@ int galaktos_glx_init( galaktos_thread_t *p_thread, int i_width, int i_height )
         XFree( p_fbconfs );
         return -1;
     }
-
-    /* Create the window */
-    if( CreateWindow( p_thread, p_vi, i_width, i_height ) == -1 )
+#else
+    p_vi = glXChooseVisual( p_display, DefaultScreen( p_display), p_attr );
+    if(! p_vi )
     {
-        XFree( p_fbconfs );
-        XFree( p_vi );
+        msg_Err( p_thread, "Cannot get GLX 1.2 visual" );
         return -1;
     }
+#endif
+
+    /* Create the window */
+    CreateWindow( p_thread, p_vi, i_width, i_height, b_fullscreen );
+
     XFree( p_vi );
 
+#if 1
     /* Create the GLX window */
     OS_DATA->gwnd = glXCreateWindow( p_display, fbconf, OS_DATA->wnd, NULL );
     if( OS_DATA->gwnd == None )
@@ -191,10 +206,26 @@ int galaktos_glx_init( galaktos_thread_t *p_thread, int i_width, int i_height )
     }
 
     XFree( p_fbconfs );
+#else
+     /* Create an OpenGL context */
+    OS_DATA->gwctx = gwctx = glXCreateContext( p_display, p_vi, 0, True );
+    if( !gwctx )
+    {
+        msg_Err( p_thread, "Cannot create OpenGL context");
+        XFree( p_fbconfs );
+        return -1;
+    }
+    XFree( p_vi );
+#endif
 
     XMapWindow( p_display, OS_DATA->wnd );
+    if( b_fullscreen )
+    {
+        XMoveWindow( p_display, OS_DATA->wnd, 0, 0 );
+    }
     XFlush( p_display );
-    glXMakeContextCurrent( p_display, OS_DATA->gwnd, OS_DATA->gwnd, gwctx );
+//    glXMakeContextCurrent( p_display, OS_DATA->gwnd, OS_DATA->gwnd, gwctx );
+//    glXMakeCurrent( p_display, OS_DATA->wnd, OS_DATA->gwctx );
 
     return 0;
 }
@@ -229,6 +260,21 @@ int galaktos_glx_handle_events( galaktos_thread_t *p_thread )
 }
 
 
+void galaktos_glx_activate_pbuffer( galaktos_thread_t *p_thread )
+{
+    glXMakeContextCurrent( OS_DATA->p_display, OS_DATA->gpbuf, OS_DATA->gpbuf,
+                           OS_DATA->gpctx );
+}
+
+
+void galaktos_glx_activate_window( galaktos_thread_t *p_thread )
+{
+    glXMakeContextCurrent( OS_DATA->p_display, OS_DATA->gwnd, OS_DATA->gwnd,
+                           OS_DATA->gwctx );
+//    glXMakeCurrent( OS_DATA->p_display, OS_DATA->wnd, OS_DATA->gwctx );
+}
+
+
 void galaktos_glx_swap( galaktos_thread_t *p_thread )
 {
     glXSwapBuffers( OS_DATA->p_display, OS_DATA->gwnd );
@@ -249,13 +295,15 @@ void galaktos_glx_done( galaktos_thread_t *p_thread )
 }
 
 
-int CreateWindow( galaktos_thread_t *p_thread, XVisualInfo *p_vi,
-                  int i_width, int i_height )
+void CreateWindow( galaktos_thread_t *p_thread, XVisualInfo *p_vi,
+                  int i_width, int i_height, int b_fullscreen )
 {
     Display *p_display;
     XSetWindowAttributes xattr;
     Window wnd;
     XSizeHints* p_size_hints;
+    Atom prop;
+    mwmhints_t mwmhints;
 
     p_display = OS_DATA->p_display;
     /* Create the window */
@@ -269,17 +317,26 @@ int CreateWindow( galaktos_thread_t *p_thread, XVisualInfo *p_vi,
     OS_DATA->wm_delete = XInternAtom( p_display, "WM_DELETE_WINDOW", False );
     XSetWMProtocols( p_display, wnd, &OS_DATA->wm_delete, 1 );
 
-    /* Prevent the window from being resized */
-    p_size_hints = XAllocSizeHints();
-    p_size_hints->flags = PMinSize | PMaxSize;
-    p_size_hints->min_width = i_width;
-    p_size_hints->min_height = i_height;
-    p_size_hints->max_width = i_width;
-    p_size_hints->max_height = i_height;
-    XSetWMNormalHints( p_display, wnd, p_size_hints );
-    XFree( p_size_hints );
+    if( b_fullscreen )
+    {
+        mwmhints.flags = MWM_HINTS_DECORATIONS;
+        mwmhints.decorations = False;
 
+        prop = XInternAtom( p_display, "_MOTIF_WM_HINTS", False );
+        XChangeProperty( p_display, wnd, prop, prop, 32, PropModeReplace,
+                         (unsigned char *)&mwmhints, PROP_MWM_HINTS_ELEMENTS );
+    }
+    else
+    {
+        /* Prevent the window from being resized */
+        p_size_hints = XAllocSizeHints();
+        p_size_hints->flags = PMinSize | PMaxSize;
+        p_size_hints->min_width = i_width;
+        p_size_hints->min_height = i_height;
+        p_size_hints->max_width = i_width;
+        p_size_hints->max_height = i_height;
+        XSetWMNormalHints( p_display, wnd, p_size_hints );
+        XFree( p_size_hints );
+    }
     XSelectInput( p_display, wnd, KeyPressMask );
-
-    return 0;
 }
index c3f09f7dfd78444e4ec0e711c0450c8a4297a2b5..11986fa057611b96f940f59ec32f07f201a78f08 100644 (file)
 
 #include "plugin.h"
 
-int galaktos_glx_init( galaktos_thread_t *p_thread, int i_width, int i_height );
+int galaktos_glx_init( galaktos_thread_t *p_thread, int i_width, int i_height,
+                       int b_fullscreen );
 void galaktos_glx_done( galaktos_thread_t *p_thread );
 int galaktos_glx_handle_events( galaktos_thread_t *p_thread );
+void galaktos_glx_activate_pbuffer( galaktos_thread_t *p_thread );
+void galaktos_glx_activate_window( galaktos_thread_t *p_thread );
 void galaktos_glx_swap( galaktos_thread_t *p_thread );
 
+/*****************************************************************************
+ * mwmhints_t: window manager hints
+ *****************************************************************************
+ * Fullscreen needs to be able to hide the wm decorations so we provide
+ * this structure to make it easier.
+ *****************************************************************************/
+#define MWM_HINTS_DECORATIONS   (1L << 1)
+#define PROP_MWM_HINTS_ELEMENTS 5
+typedef struct mwmhints_t
+{
+    uint32_t flags;
+    uint32_t functions;
+    uint32_t decorations;
+    int32_t  input_mode;
+    uint32_t status;
+} mwmhints_t;
+
 #endif
diff --git a/modules/visualization/galaktos/idle_preset.h b/modules/visualization/galaktos/idle_preset.h
new file mode 100644 (file)
index 0000000..38294c8
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef IDLE_PRESET_H
+#include "preset_types.h"
+#define IDLE_PRESET_H
+
+#define IDLE_PRESET_STRING "[idlepreset]\n"
+
+preset_t * idle_preset;
+#endif
diff --git a/modules/visualization/galaktos/init_cond.c b/modules/visualization/galaktos/init_cond.c
new file mode 100644 (file)
index 0000000..e8d246f
--- /dev/null
@@ -0,0 +1,161 @@
+/*****************************************************************************
+ * init_cond.:
+ *****************************************************************************
+ * Copyright (C) 2004 VideoLAN
+ * $Id$
+ *
+ * Authors: Cyril Deguet <asmax@videolan.org>
+ *          code from projectM http://xmms-projectm.sourceforge.net
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ *****************************************************************************/
+
+
+
+/* Library functions to manipulate initial condition values */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "common.h"
+#include "fatal.h"
+
+#include "param_types.h"
+#include "expr_types.h"
+#include "init_cond_types.h"
+#include "init_cond.h"
+
+#include "splaytree_types.h"
+#include "splaytree.h"
+char init_cond_string_buffer[STRING_BUFFER_SIZE];
+int init_cond_string_buffer_index = 0;
+
+
+void init_cond_to_string(init_cond_t * init_cond);
+
+/* Frees initial condition structure */
+void free_init_cond(init_cond_t * init_cond) {
+  free(init_cond);
+}
+
+/* Evaluate an initial conditon */
+void eval_init_cond(init_cond_t * init_cond) {
+
+  if (init_cond == NULL)
+    return;
+  /* Parameter is of boolean type, either a 1 or 0 value integer */
+
+  /* Set matrix flag to zero. This ensures
+     its constant value will be used rather than a matrix value 
+  */
+  init_cond->param->matrix_flag = 0;
+  if (init_cond->param->type == P_TYPE_BOOL) {
+        if (INIT_COND_DEBUG) printf("init_cond: %s = %d (TYPE BOOL)\n", init_cond->param->name, init_cond->init_val.bool_val); 
+        *((int*)init_cond->param->engine_val) = init_cond->init_val.bool_val;
+     return;
+  }
+  
+  /* Parameter is an integer type, just like C */
+  
+  if (init_cond->param->type == P_TYPE_INT) {
+        if (INIT_COND_DEBUG) printf("init_cond: %s = %d (TYPE INT)\n", init_cond->param->name, init_cond->init_val.int_val);
+        *((int*)init_cond->param->engine_val) = init_cond->init_val.int_val;
+     return;
+  }
+
+  /* Parameter is of a double type, just like C */
+
+  if (init_cond->param->type == P_TYPE_DOUBLE) {
+       if (INIT_COND_DEBUG) printf("init_cond: %s = %f (TYPE DOUBLE)\n", init_cond->param->name, init_cond->init_val.double_val);
+       *((double*)init_cond->param->engine_val) = init_cond->init_val.double_val;
+    return;
+  }
+
+  /* Unknown type of parameter */
+  return;
+}
+
+/* Creates a new initial condition */
+init_cond_t * new_init_cond(param_t * param, value_t init_val) {
+
+  init_cond_t * init_cond;
+
+  init_cond = (init_cond_t*)malloc(sizeof(init_cond_t));
+   
+  if (init_cond == NULL)
+    return NULL;
+  init_cond->param = param;
+  init_cond->init_val = init_val;
+  return init_cond;
+}
+
+/* WIP */
+void init_cond_to_string(init_cond_t * init_cond) {
+       
+       int string_length;
+       char string[MAX_TOKEN_SIZE];
+       
+       if (init_cond == NULL)
+               return;
+
+       /* Create a string "param_name=val" */
+       switch (init_cond->param->type) {
+               
+               case P_TYPE_BOOL:
+                       sprintf(string, "%s=%d\n", init_cond->param->name, init_cond->init_val.bool_val);
+                       break; 
+               case P_TYPE_INT:
+                       sprintf(string, "%s=%d\n", init_cond->param->name, init_cond->init_val.int_val);
+                       break;
+               case P_TYPE_DOUBLE:
+                       sprintf(string, "%s=%f\n", init_cond->param->name, init_cond->init_val.double_val);
+                       break;
+               default:
+                       return;
+       }               
+               
+       /* Compute the length of the string */
+       string_length = strlen(string);
+       
+       /* Buffer overflow check */
+       if ((init_cond_string_buffer_index + string_length + 1)  > (STRING_BUFFER_SIZE - 1))
+               return;
+       
+       /* Copy the string into the initial condition string buffer */
+       
+       strncpy(init_cond_string_buffer + init_cond_string_buffer_index, string, string_length);
+       
+       /* Increment the string buffer, offset by one for the null terminator, which will be
+          overwritten by the next call to this function */
+       init_cond_string_buffer_index+= string_length + 1;
+               
+}
+
+
+char * create_init_cond_string_buffer(splaytree_t * init_cond_tree) {
+
+       if (init_cond_tree == NULL)
+               return NULL;
+       
+       init_cond_string_buffer_index = 0;
+       
+       splay_traverse(init_cond_to_string, init_cond_tree);
+       
+       return init_cond_string_buffer;
+               
+}
diff --git a/modules/visualization/galaktos/init_cond.h b/modules/visualization/galaktos/init_cond.h
new file mode 100644 (file)
index 0000000..34cbd30
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef INIT_COND_H
+#define INIT_COND_H
+#define INIT_COND_DEBUG 0
+#include "param_types.h"
+#include "splaytree_types.h"
+
+void eval_init_cond(init_cond_t * init_cond);
+init_cond_t * new_init_cond(param_t * param, value_t init_val);
+void free_init_cond(init_cond_t * init_cond);
+char * create_init_cond_string_buffer(splaytree_t * init_cond_tree);
+#endif
diff --git a/modules/visualization/galaktos/init_cond_types.h b/modules/visualization/galaktos/init_cond_types.h
new file mode 100644 (file)
index 0000000..d339fb1
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef INIT_COND_TYPES_H
+#define INIT_COND_TYPES_H
+
+#include "param_types.h"
+#include "expr_types.h"
+
+typedef struct INIT_COND_T {
+  struct PARAM_T * param;
+  value_t init_val;
+} init_cond_t;
+#endif
diff --git a/modules/visualization/galaktos/interface_types.h b/modules/visualization/galaktos/interface_types.h
new file mode 100644 (file)
index 0000000..f1aa496
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef INTERFACE_TYPES_H
+#define INTERFACE_TYPES_H
+typedef enum {
+
+  MENU_INTERFACE,
+  SHELL_INTERFACE,
+  EDITOR_INTERFACE,
+  DEFAULT_INTERFACE,
+  BROWSER_INTERFACE
+} interface_t;
+
+#endif
index 3d29190f312e9d004ae5eec10bb3c56361708449..dadaef41709f0200c1cd9d2c4f220ec32f169f5d 100644 (file)
@@ -5,6 +5,7 @@
  * $Id$
  *
  * Authors: Cyril Deguet <asmax@videolan.org>
+ *          Adapted from projectM (http://xmms-projectm.sourceforge.net/)
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 
 #include "glx.h"
 #include <GL/gl.h>
+#include <GL/glu.h>
 #include <unistd.h>
 #include <math.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "common.h"
+#include "preset_types.h"
+#include "preset.h"
+#include "engine_vars.h"
+#include "per_pixel_eqn_types.h"
+#include "per_pixel_eqn.h"
+#include "interface_types.h"
+#include "video_init.h"             //Video Init Routines, resizing/fullscreen, creating pbuffers
+#include "PCM.h"                    //Sound data handler (buffering, FFT, etc.)
+#include "beat_detect.h"            //beat detection routines
+#include "custom_wave_types.h"
+#include "custom_wave.h"
+#include "custom_shape_types.h"
+#include "custom_shape.h"
+//#include <dmalloc.h>
 
-int galaktos_update( galaktos_thread_t *p_thread, int16_t p_data[2][512] )
+// Forward declarations
+
+void read_cfg();
+
+void modulate_opacity_by_volume();
+void maximize_colors();
+void do_per_pixel_math();
+void do_per_frame();
+
+void render_interpolation();
+void render_texture_to_screen();
+void render_texture_to_studio();
+void draw_motion_vectors();
+void draw_borders();
+void draw_shapes();
+void draw_waveform();
+void draw_custom_waves();
+
+void reset_per_pixel_matrices();
+void init_per_pixel_matrices();
+void free_per_pixel_matrices();
+
+int noSwitch=0;
+int pcmframes=1;
+int freqframes=0;
+int totalframes=1;
+
+int studio=0;
+
+extern preset_t * active_preset;
+
+GLuint RenderTargetTextureID;
+
+double wave_o;
+
+//double gx=32;  //size of interpolation
+//double gy=24;
+
+int texsize=512;   //size of texture to do actual graphics
+int vw=512;           //runtime dimensions
+int vh=512;
+int fullscreen=0;
+
+int maxsamples=2048; //size of PCM buffer
+int numsamples; //size of new PCM info
+double *pcmdataL;     //holder for most recent pcm data
+double *pcmdataR;     //holder for most recent pcm data
+
+int avgtime=500;  //# frames per preset
+
+char *title = NULL;
+int drawtitle;
+int title_font;
+int other_font;
+
+int correction=1;
+
+double vol;
+
+//per pixel equation variables
+
+
+double **gridx;  //grid containing interpolated mesh
+double **gridy;
+double **origtheta;  //grid containing interpolated mesh reference values
+double **origrad;
+double **origx;  //original mesh
+double **origy;
+
+
+
+int galaktos_init( galaktos_thread_t *p_thread )
+{
+    init_per_pixel_matrices();
+    pcmdataL=(double *)malloc(maxsamples*sizeof(double));
+    pcmdataR=(double *)malloc(maxsamples*sizeof(double));
+
+    /* Preset loading function */
+    initPresetLoader();
+
+    /* Load default preset directory */
+ //   loadPresetDir("/home/cyril/.vlc/galaktos");
+    loadPresetDir("/etc/projectM/presets");
+
+    initPCM(maxsamples);
+    initBeatDetect();
+
+    // mutex = SDL_CreateMutex();
+    return 0;
+}
+
+
+void galaktos_done( galaktos_thread_t *p_thread )
 {
-    int j;
+    free(pcmdataL);
+    free(pcmdataR);
+
+    freeBeatDetect();
+    freePCM();
+    free_per_pixel_matrices();
+    closePresetDir();
+//    destroyPresetLoader(); XXX segfaults :(
+}
+
+
+int galaktos_update( galaktos_thread_t *p_thread )
+{
+    static int nohard=0;
+    double vdataL[512];  //holders for FFT data (spectrum)
+    double vdataR[512];
+
+    avgtime=fps*18;
+    totalframes++; //total amount of frames since startup
+
+    Time=(double)(mdate()/1000000);
+
+    frame++;  //number of frames for current preset
+    progress= frame/(double)avgtime;
+    if (progress>1.0) progress=1.0;
+    // printf("start:%d at:%d min:%d stop:%d on:%d %d\n",startframe, frame frame-startframe,avgtime,  noSwitch,progress);
+
+    if (frame>avgtime)
+    {
+        if (noSwitch==0) switchPreset(RANDOM_NEXT,0);
+    }
+
+    evalInitConditions();
+    evalPerFrameEquations();
+
+    evalCustomWaveInitConditions();
+    evalCustomShapeInitConditions();
+
+    //     printf("%f %d\n",Time,frame);
+
+    reset_per_pixel_matrices();
+
+
+    numsamples = getPCMnew(pcmdataR,1,0,fWaveSmoothing,0,0);
+    getPCMnew(pcmdataL,0,0,fWaveSmoothing,0,1);
+    getPCM(vdataL,512,0,1,0,0);
+    getPCM(vdataR,512,1,1,0,0);
+
+    bass=0;mid=0;treb=0;
+
+    getBeatVals(vdataL,vdataR,&vol);
+
+    nohard--;
+    if(vol>8.0 && nohard<0 && noSwitch==0)
+    {
+
+        switchPreset(RANDOM_NEXT, HARD_CUT);
+        nohard=100;
+    }
+
+    //BEGIN PASS 1
+    //
+    //This pass is used to render our texture
+    //the texture is drawn to a subsection of the framebuffer
+    //and then we perform our manipulations on it
+    //in pass 2 we will copy the texture into texture memory
+
+ //   galaktos_glx_activate_pbuffer( p_thread );
+
+    glPushAttrib( GL_ALL_ATTRIB_BITS ); /* Overkill, but safe */
+
+    //   if (RenderTarget) glViewport( 0, 0, RenderTarget->w, RenderTarget->h );
+    if (0) {}
+    else glViewport( 0, 0, texsize, texsize );
+
+
+    glMatrixMode( GL_MODELVIEW );
+    glPushMatrix();
+    glLoadIdentity();
+
+    glMatrixMode( GL_PROJECTION );
+    glPushMatrix();
+    glLoadIdentity();
+
+    glOrtho(0.0, texsize, 0.0,texsize,10,40);
+
+    do_per_pixel_math();
+
+    do_per_frame();               //apply per-frame effects
+    render_interpolation();       //apply per-pixel effects
+    draw_motion_vectors();        //draw motion vectors
+    draw_borders();               //draw borders
+
+    draw_waveform();
+    draw_shapes();
+    draw_custom_waves();
+
+    glMatrixMode( GL_MODELVIEW );
+    glPopMatrix();
+
+    glMatrixMode( GL_PROJECTION );
+    glPopMatrix();
+
+    glPopAttrib();
+
+    //if ( RenderTarget )        SDL_GL_UnlockRenderTarget(RenderTarget);
+        /* Copy our rendering to the fake render target texture */
+    glBindTexture( GL_TEXTURE_2D, RenderTargetTextureID );
+    glCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, 0, texsize, texsize);
+//    galaktos_glx_activate_window( p_thread );
+
+    //BEGIN PASS 2
+    //
+    //end of texture rendering
+    //now we copy the texture from the framebuffer to
+    //video texture memory and render fullscreen on a quad surface.
+    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+    glMatrixMode(GL_PROJECTION);
+    glLoadIdentity();
+
+    glFrustum(-vw*.5, vw*.5, -vh*.5,vh*.5,10,40);
+
+    glLineWidth(texsize/512.0);
+    if(studio%2)render_texture_to_studio();
+    else render_texture_to_screen();
+
+    glFinish();
+    glFlush();
+    //  printf("Flush %d\n",(SDL_GetTicks()-timestart));
+    galaktos_glx_swap( p_thread );
 
     /* Process X11 events */
     if( galaktos_glx_handle_events( p_thread ) == 1 )
@@ -36,31 +277,1302 @@ int galaktos_update( galaktos_thread_t *p_thread, int16_t p_data[2][512] )
         return 1;
     }
 
-    glClearColor( 0.0f, 0.0f, 0.0f, 1.0f );
+    return 0;
+}
+
+
+void free_per_pixel_matrices()
+{
+    int x;
+
+    for(x = 0; x < gx; x++)
+    {
+        free(gridx[x]);
+        free(gridy[x]);
+        free(origtheta[x]);
+        free(origrad[x]);
+        free(origx[x]);
+        free(origy[x]);
+        free(x_mesh[x]);
+        free(y_mesh[x]);
+        free(rad_mesh[x]);
+        free(theta_mesh[x]);
+    }
+
+    free(origx);
+    free(origy);
+    free(gridx);
+    free(gridy);
+    free(x_mesh);
+    free(y_mesh);
+    free(rad_mesh);
+    free(theta_mesh);
+}
+
+
+void init_per_pixel_matrices()
+{
+    int x,y;
+
+    gridx=(double **)malloc(gx * sizeof(double *));
+    gridy=(double **)malloc(gx * sizeof(double *));
+
+    origx=(double **)malloc(gx * sizeof(double *));
+    origy=(double **)malloc(gx * sizeof(double *));
+    origrad=(double **)malloc(gx * sizeof(double *));
+    origtheta=(double **)malloc(gx * sizeof(double *));
+
+    x_mesh=(double **)malloc(gx * sizeof(double *));
+    y_mesh=(double **)malloc(gx * sizeof(double *));
+    rad_mesh=(double **)malloc(gx * sizeof(double *));
+    theta_mesh=(double **)malloc(gx * sizeof(double *));
+
+    sx_mesh=(double **)malloc(gx * sizeof(double *));
+    sy_mesh=(double **)malloc(gx * sizeof(double *));
+    dx_mesh=(double **)malloc(gx * sizeof(double *));
+    dy_mesh=(double **)malloc(gx * sizeof(double *));
+    cx_mesh=(double **)malloc(gx * sizeof(double *));
+    cy_mesh=(double **)malloc(gx * sizeof(double *));
+    zoom_mesh=(double **)malloc(gx * sizeof(double *));
+    zoomexp_mesh=(double **)malloc(gx * sizeof(double *));
+    rot_mesh=(double **)malloc(gx * sizeof(double *));
+
+    for(x = 0; x < gx; x++)
+    {
+        gridx[x] = (double *)malloc(gy * sizeof(double));
+        gridy[x] = (double *)malloc(gy * sizeof(double));
+
+        origtheta[x] = (double *)malloc(gy * sizeof(double));
+        origrad[x] = (double *)malloc(gy * sizeof(double));
+        origx[x] = (double *)malloc(gy * sizeof(double));
+        origy[x] = (double *)malloc(gy * sizeof(double));
+
+        x_mesh[x] = (double *)malloc(gy * sizeof(double));
+        y_mesh[x] = (double *)malloc(gy * sizeof(double));
+
+        rad_mesh[x] = (double *)malloc(gy * sizeof(double));
+        theta_mesh[x] = (double *)malloc(gy * sizeof(double));
+
+        sx_mesh[x] = (double *)malloc(gy * sizeof(double));
+        sy_mesh[x] = (double *)malloc(gy * sizeof(double));
+        dx_mesh[x] = (double *)malloc(gy * sizeof(double));
+        dy_mesh[x] = (double *)malloc(gy * sizeof(double));
+        cx_mesh[x] = (double *)malloc(gy * sizeof(double));
+        cy_mesh[x] = (double *)malloc(gy * sizeof(double));
+
+        zoom_mesh[x] = (double *)malloc(gy * sizeof(double));
+        zoomexp_mesh[x] = (double *)malloc(gy * sizeof(double));
+
+        rot_mesh[x] = (double *)malloc(gy * sizeof(double));
+    }
+
+    //initialize reference grid values
+    for (x=0;x<gx;x++)
+    {
+        for(y=0;y<gy;y++)
+        {
+            origx[x][y]=x/(double)(gx-1);
+            origy[x][y]=-((y/(double)(gy-1))-1);
+            origrad[x][y]=hypot((origx[x][y]-.5)*2,(origy[x][y]-.5)*2) * .7071067;
+            origtheta[x][y]=atan2(((origy[x][y]-.5)*2),((origx[x][y]-.5)*2));
+            gridx[x][y]=origx[x][y]*texsize;
+            gridy[x][y]=origy[x][y]*texsize;
+        }
+    }
+}
+
+
+
+//calculate matrices for per_pixel
+void do_per_pixel_math()
+{
+    int x,y;
+
+    double rotx=0,roty=0;
+    evalPerPixelEqns();
+
+    if(!isPerPixelEqn(CX_OP))
+    {
+        for (x=0;x<gx;x++)
+        {
+            for(y=0;y<gy;y++){
+                cx_mesh[x][y]=cx;
+            }
+        }
+    }
+
+    if(!isPerPixelEqn(CY_OP))
+    {
+        for (x=0;x<gx;x++)
+        {
+            for(y=0;y<gy;y++)
+            {
+                cy_mesh[x][y]=cy;
+            }
+        }
+    }
+
+    if(isPerPixelEqn(ROT_OP))
+    {
+        for (x=0;x<gx;x++)
+        {
+            for(y=0;y<gy;y++)
+            {
+                x_mesh[x][y]=x_mesh[x][y]-cx_mesh[x][y];
+                y_mesh[x][y]=y_mesh[x][y]-cy_mesh[x][y];
+                rotx=(x_mesh[x][y])*cos(rot_mesh[x][y])-(y_mesh[x][y])*sin(rot_mesh[x][y]);
+                roty=(x_mesh[x][y])*sin(rot_mesh[x][y])+(y_mesh[x][y])*cos(rot_mesh[x][y]);
+                x_mesh[x][y]=rotx+cx_mesh[x][y];
+                y_mesh[x][y]=roty+cy_mesh[x][y];
+            }
+        }
+    }
+
+
+
+    if(!isPerPixelEqn(ZOOM_OP))
+    {
+        for (x=0;x<gx;x++)
+        {
+            for(y=0;y<gy;y++)
+            {
+                zoom_mesh[x][y]=zoom;
+            }
+        }
+    }
+
+    if(!isPerPixelEqn(ZOOMEXP_OP))
+    {
+        for (x=0;x<gx;x++)
+        {
+            for(y=0;y<gy;y++)
+            {
+                zoomexp_mesh[x][y]=zoomexp;
+            }
+        }
+    }
+
+
+    //DO ZOOM PER PIXEL
+    for (x=0;x<gx;x++)
+    {
+        for(y=0;y<gy;y++)
+        {
+            x_mesh[x][y]=(x_mesh[x][y]-.5)*2;
+            y_mesh[x][y]=(y_mesh[x][y]-.5)*2;
+            x_mesh[x][y]=x_mesh[x][y]/(((zoom_mesh[x][y]-1)*(pow(rad_mesh[x][y],zoomexp_mesh[x][y])/rad_mesh[x][y]))+1);
+            y_mesh[x][y]=y_mesh[x][y]/(((zoom_mesh[x][y]-1)*(pow(rad_mesh[x][y],zoomexp_mesh[x][y])/rad_mesh[x][y]))+1);
+            x_mesh[x][y]=(x_mesh[x][y]*.5)+.5;
+            y_mesh[x][y]=(y_mesh[x][y]*.5)+.5;
+        }
+    }
+
+    if(isPerPixelEqn(SX_OP))
+    {
+        for (x=0;x<gx;x++)
+        {
+            for(y=0;y<gy;y++)
+            {
+                x_mesh[x][y]=((x_mesh[x][y]-cx_mesh[x][y])/sx_mesh[x][y])+cx_mesh[x][y];
+            }
+        }
+    }
+
+    if(isPerPixelEqn(SY_OP))
+    {
+        for (x=0;x<gx;x++)
+        {
+            for(y=0;y<gy;y++)
+            {
+                y_mesh[x][y]=((y_mesh[x][y]-cy_mesh[x][y])/sy_mesh[x][y])+cy_mesh[x][y];
+            }
+        }
+    }
+
+    if(isPerPixelEqn(DX_OP))
+    {
+        for (x=0;x<gx;x++)
+        {
+            for(y=0;y<gy;y++)
+            {
+
+                x_mesh[x][y]=x_mesh[x][y]-dx_mesh[x][y];
+
+            }
+        }
+    }
+
+    if(isPerPixelEqn(DY_OP))
+    {
+        for (x=0;x<gx;x++)
+        {
+            for(y=0;y<gy;y++)
+            {
+                y_mesh[x][y]=y_mesh[x][y]-dy_mesh[x][y];
+
+            }
+        }
+    }
+
+
+}
+
+void reset_per_pixel_matrices()
+{
+    int x,y;
+
+    for (x=0;x<gx;x++)
+    {
+        for(y=0;y<gy;y++)
+        {
+            x_mesh[x][y]=origx[x][y];
+            y_mesh[x][y]=origy[x][y];
+            rad_mesh[x][y]=origrad[x][y];
+            theta_mesh[x][y]=origtheta[x][y];
+        }
+    }
+}
+
+
+
+void draw_custom_waves()
+{
+    int x;
+
+    custom_wave_t *wavecode;
+    glPointSize(texsize/512);
+    //printf("%d\n",wavecode);
+    //  more=isMoreCustomWave();
+    // printf("not inner loop\n");
+    while ((wavecode = nextCustomWave()) != NULL)
+    {
+        //printf("begin inner loop\n");
+        if(wavecode->enabled==1)
+        {
+            // nextCustomWave();
+
+            //glPushMatrix();
+
+            //if(wavecode->bUseDots==1) glEnable(GL_LINE_STIPPLE);
+            if (wavecode->bAdditive==0)  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+            else    glBlendFunc(GL_SRC_ALPHA, GL_ONE);
+            if (wavecode->bDrawThick==1)  glLineWidth(2*texsize/512);
+
+            //  xx= ((pcmdataL[x]-pcmdataL[x-1])*80*fWaveScale)*2;
+            //yy=pcmdataL[x]*80*fWaveScale,-1;
+            //glVertex3f( (wave_x*texsize)+(xx+yy)*cos(45), (wave_y*texsize)+(-yy+xx)*cos(45),-1);
+            // printf("samples: %d\n", wavecode->samples);
+
+            getPCM(wavecode->value1,wavecode->samples,0,wavecode->bSpectrum,wavecode->smoothing,0);
+            getPCM(wavecode->value2,wavecode->samples,1,wavecode->bSpectrum,wavecode->smoothing,0);
+            // printf("%f\n",pcmL[0]);
+            for(x=0;x<wavecode->samples;x++)
+            {wavecode->value1[x]=wavecode->value1[x]*wavecode->scaling;}
+
+            for(x=0;x<wavecode->samples;x++)
+            {wavecode->value2[x]=wavecode->value2[x]*wavecode->scaling;}
+
+            for(x=0;x<wavecode->samples;x++)
+            {wavecode->sample_mesh[x]=((double)x)/((double)(wavecode->samples-1));}
+
+            // printf("mid inner loop\n");
+            evalPerPointEqns();
+            /*
+               if(!isPerPointEquation("x"))
+               {for(x=0;x<wavecode->samples;x++)
+               {cw_x[x]=0;} }
+
+               if(!isPerPointEquation(Y_POINT_OP))
+               {for(x=0;x<wavecode->samples;x++)
+               {cw_y[x]=0;}}
+
+               if(!isPerPointEquation(R_POINT_OP))
+               {for(x=0;x<wavecode->samples;x++)
+               {cw_r[x]=wavecode->r;}}
+               if(!isPerPointEquation(G_POINT_OP))
+               {for(x=0;x<wavecode->samples;x++)
+               {cw_g[x]=wavecode->g;}}
+               if(!isPerPointEquation(B_POINT_OP))
+               {for(x=0;x<wavecode->samples;x++)
+               {cw_b[x]=wavecode->b;}}
+               if(!isPerPointEquation(A_POINT_OP))
+               {for(x=0;x<wavecode->samples;x++)
+               {cw_a[x]=wavecode->a;}}
+             */
+            //put drawing code here
+            if (wavecode->bUseDots==1)   glBegin(GL_POINTS);
+            else   glBegin(GL_LINE_STRIP);
+
+            for(x=0;x<wavecode->samples;x++)
+            {
+                //          printf("x:%f y:%f a:%f g:%f %f\n", wavecode->x_mesh[x], wavecode->y_mesh[x], wavecode->a_mesh[x], wavecode->g_mesh[x], wavecode->sample_mesh[x]);
+                glColor4f(wavecode->r_mesh[x],wavecode->g_mesh[x],wavecode->b_mesh[x],wavecode->a_mesh[x]);
+                glVertex3f(wavecode->x_mesh[x]*texsize,-(wavecode->y_mesh[x]-1)*texsize,-1);
+            }
+            glEnd();
+            glPointSize(texsize/512);
+            glLineWidth(texsize/512);
+            glDisable(GL_LINE_STIPPLE);
+            glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+            //  glPopMatrix();
+
+        }
+
+    }
+}
+
+
+
+void draw_shapes()
+{
+    int i;
+
+    double theta;
+    double rad2;
+
+    double pi = 3.14159265;
+    double start,inc,xval,yval;
+    custom_shape_t *shapecode;
+
+    while ((shapecode = nextCustomShape()) != NULL)
+    {
+        if(shapecode->enabled==1)
+        {
+            // printf("drawing shape %f\n",shapecode->ang);
+            shapecode->y=-((shapecode->y)-1);
+            rad2=.5;
+            shapecode->rad=shapecode->rad*(texsize*.707*.707*.707*1.04);
+            //Additive Drawing or Overwrite
+            if (shapecode->additive==0)  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+            else    glBlendFunc(GL_SRC_ALPHA, GL_ONE);
+
+            glMatrixMode(GL_MODELVIEW);
+            glPushMatrix();
+            if(correction)
+            {
+                glTranslatef(texsize*.5,texsize*.5, 0);
+                glScalef(1.0,vw/(double)vh,1.0);
+                glTranslatef((-texsize*.5) ,(-texsize*.5),0);
+            }
+
+            start=.78539+shapecode->ang;
+            inc=(pi*2)/(double)shapecode->sides;
+            xval=shapecode->x*texsize;
+            yval=shapecode->y*texsize;
+
+            if (shapecode->textured)
+            {
+                glMatrixMode(GL_TEXTURE);
+                glPushMatrix();
+                glLoadIdentity();
+
+                glTranslatef(.5,.5, 0);
+                if (correction) glScalef(1,vw/(double)vh,1);
+
+                glRotatef((shapecode->tex_ang*360/6.280), 0, 0, 1);
+
+                glScalef(1/(shapecode->tex_zoom),1/(shapecode->tex_zoom),1);
+
+                // glScalef(1,vh/(double)vw,1);
+                glTranslatef((-.5) ,(-.5),0);
+                // glScalef(1,vw/(double)vh,1);
+                glEnable(GL_TEXTURE_2D);
+
+
+                glBegin(GL_TRIANGLE_FAN);
+
+                glColor4f(shapecode->r,shapecode->g,shapecode->b,shapecode->a);
+                theta=start;
+                glTexCoord2f(.5,.5);
+                glVertex3f(xval,yval,-1);
+                glColor4f(shapecode->r2,shapecode->g2,shapecode->b2,shapecode->a2);
+
+                for ( i=0;i<shapecode->sides+1;i++)
+                {
+
+                    theta+=inc;
+                    //  glColor4f(shapecode->r2,shapecode->g2,shapecode->b2,shapecode->a2);
+                    glTexCoord2f(rad2*cos(theta)+.5 ,rad2*sin(theta)+.5 );
+                    glVertex3f(shapecode->rad*cos(theta)+xval,shapecode->rad*sin(theta)+yval,-1);
+                }
+                glEnd();
+
+
+
+
+                glDisable(GL_TEXTURE_2D);
+                glPopMatrix();
+                glMatrixMode(GL_MODELVIEW);
+            }
+            else
+            {//Untextured (use color values)
+                //printf("untextured %f %f %f @:%f,%f %f %f\n",shapecode->a2,shapecode->a,shapecode->border_a, shapecode->x,shapecode->y,shapecode->rad,shapecode->ang);
+                //draw first n-1 triangular pieces
+                glBegin(GL_TRIANGLE_FAN);
+
+                glColor4f(shapecode->r,shapecode->g,shapecode->b,shapecode->a);
+                theta=start;
+                // glTexCoord2f(.5,.5);
+                glVertex3f(xval,yval,-1);
+                glColor4f(shapecode->r2,shapecode->g2,shapecode->b2,shapecode->a2);
+
+                for ( i=0;i<shapecode->sides+1;i++)
+                {
+
+                    theta+=inc;
+                    //  glColor4f(shapecode->r2,shapecode->g2,shapecode->b2,shapecode->a2);
+                    //  glTexCoord2f(rad2*cos(theta)+.5 ,rad2*sin(theta)+.5 );
+                    glVertex3f(shapecode->rad*cos(theta)+xval,shapecode->rad*sin(theta)+yval,-1);
+                }
+                glEnd();
+
+
+            }
+            if (bWaveThick==1)  glLineWidth(2*texsize/512);
+            glBegin(GL_LINE_LOOP);
+            glColor4f(shapecode->border_r,shapecode->border_g,shapecode->border_b,shapecode->border_a);
+            for ( i=0;i<shapecode->sides;i++)
+            {
+                theta+=inc;
+                glVertex3f(shapecode->rad*cos(theta)+xval,shapecode->rad*sin(theta)+yval,-1);
+            }
+            glEnd();
+            if (bWaveThick==1)  glLineWidth(texsize/512);
+
+            glPopMatrix();
+        }
+    }
+
+}
+
+
+void draw_waveform()
+{
+
+    int x;
+
+    double r,theta;
+
+    double offset,scale,dy2_adj;
+
+    double co;
+
+    double wave_x_temp=0;
+    double wave_y_temp=0;
+
+    modulate_opacity_by_volume();
+    maximize_colors();
+
+    if(bWaveDots==1) glEnable(GL_LINE_STIPPLE);
+
+    offset=(wave_x-.5)*texsize;
+    scale=texsize/505.0;
+
+    //Thick wave drawing
+    if (bWaveThick==1)  glLineWidth(2*texsize/512);
+
+    //Additive wave drawing (vice overwrite)
+    if (bAdditiveWaves==0)  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+    else    glBlendFunc(GL_SRC_ALPHA, GL_ONE);
+
+    switch(nWaveMode)
+    {
+        case 8://monitor
+
+            glPushMatrix();
+
+            glTranslatef(texsize*.5,texsize*.5, 0);
+            glRotated(-wave_mystery*90,0,0,1);
+
+            glTranslatef(-texsize*.5,-texsize*.825, 0);
+
+            /*
+               for (x=0;x<16;x++)
+               {
+               glBegin(GL_LINE_STRIP);
+               glColor4f(1.0-(x/15.0),.5,x/15.0,1.0);
+               glVertex3f((totalframes%256)*2*scale, -beat_val[x]*fWaveScale+texsize*wave_y,-1);
+               glColor4f(.5,.5,.5,1.0);
+               glVertex3f((totalframes%256)*2*scale, texsize*wave_y,-1);
+               glColor4f(1.0,1.0,0,1.0);
+            //glVertex3f((totalframes%256)*scale*2, beat_val_att[x]*fWaveScale+texsize*wave_y,-1);
+            glEnd();
+
+            glTranslatef(0,texsize*(1/36.0), 0);
+            }
+             */
+
+            glTranslatef(0,texsize*(1/18.0), 0);
+
+
+            glBegin(GL_LINE_STRIP);
+            glColor4f(1.0,1.0,0.5,1.0);
+            glVertex3f((totalframes%256)*2*scale, treb_att*5*fWaveScale+texsize*wave_y,-1);
+            glColor4f(.2,.2,.2,1.0);
+            glVertex3f((totalframes%256)*2*scale, texsize*wave_y,-1);
+            glColor4f(1.0,1.0,0,1.0);
+            glVertex3f((totalframes%256)*scale*2, treb*-5*fWaveScale+texsize*wave_y,-1);
+            glEnd();
+
+            glTranslatef(0,texsize*.075, 0);
+            glBegin(GL_LINE_STRIP);
+            glColor4f(0,1.0,0.0,1.0);
+            glVertex3f((totalframes%256)*2*scale, mid_att*5*fWaveScale+texsize*wave_y,-1);
+            glColor4f(.2,.2,.2,1.0);
+            glVertex3f((totalframes%256)*2*scale, texsize*wave_y,-1);
+            glColor4f(.5,1.0,.5,1.0);
+            glVertex3f((totalframes%256)*scale*2, mid*-5*fWaveScale+texsize*wave_y,-1);
+            glEnd();
+
+
+            glTranslatef(0,texsize*.075, 0);
+            glBegin(GL_LINE_STRIP);
+            glColor4f(1.0,0,0,1.0);
+            glVertex3f((totalframes%256)*2*scale, bass_att*5*fWaveScale+texsize*wave_y,-1);
+            glColor4f(.2,.2,.2,1.0);
+            glVertex3f((totalframes%256)*2*scale, texsize*wave_y,-1);
+            glColor4f(1.0,.5,.5,1.0);
+            glVertex3f((totalframes%256)*scale*2, bass*-5*fWaveScale+texsize*wave_y,-1);
+            glEnd();
+
+
+            glPopMatrix();
+            break;
+
+        case 0://circular waveforms
+            //  double co;
+            glPushMatrix();
+
+            glTranslatef(texsize*.5,texsize*.5, 0);
+            glScalef(1.0,vw/(double)vh,1.0);
+            glTranslatef((-texsize*.5) ,(-texsize*.5),0);
+
+            wave_y=-1*(wave_y-1.0);
+
+            glBegin(GL_LINE_STRIP);
+
+            for ( x=0;x<numsamples;x++)
+            {
+                co= -(abs(x-((numsamples*.5)-1))/numsamples)+1;
+                // printf("%d %f\n",x,co);
+                theta=x*(6.28/numsamples);
+                r= ((1+2*wave_mystery)*(texsize/5.0)+
+                    ( co*pcmdataL[x]+ (1-co)*pcmdataL[-(x-(numsamples-1))])
+                    *25*fWaveScale);
+
+                glVertex3f(r*cos(theta)+(wave_x*texsize),r*sin(theta)+(wave_y*texsize),-1);
+            }
+
+            r= ( (1+2*wave_mystery)*(texsize/5.0)+
+                 (0.5*pcmdataL[0]+ 0.5*pcmdataL[numsamples-1])
+                 *20*fWaveScale);
+
+            glVertex3f(r*cos(0)+(wave_x*texsize),r*sin(0)+(wave_y*texsize),-1);
+
+            glEnd();
+            /*
+               glBegin(GL_LINE_LOOP);
+
+               for ( x=0;x<(512/pcmbreak);x++)
+               {
+               theta=(blockstart+x)*((6.28*pcmbreak)/512.0);
+               r= ((1+2*wave_mystery)*(texsize/5.0)+fdata_buffer[fbuffer][0][blockstart+x]*.0025*fWaveScale);
+
+               glVertex3f(r*cos(theta)+(wave_x*texsize),r*sin(theta)+(wave_y*texsize),-1);
+               }
+               glEnd();
+             */
+            glPopMatrix();
+
+            break;
+
+        case 1://circularly moving waveform
+            //  double co;
+            glPushMatrix();
+
+            glTranslatef(texsize*.5,texsize*.5, 0);
+            glScalef(1.0,vw/(double)vh,1.0);
+            glTranslatef((-texsize*.5) ,(-texsize*.5),0);
+
+            wave_y=-1*(wave_y-1.0);
+
+            glBegin(GL_LINE_STRIP);
+            //theta=(frame%512)*(6.28/512.0);
+
+            for ( x=1;x<512;x++)
+            {
+                co= -(abs(x-255)/512.0)+1;
+                // printf("%d %f\n",x,co);
+                theta=((frame%256)*(2*6.28/512.0))+pcmdataL[x]*.2*fWaveScale;
+                r= ((1+2*wave_mystery)*(texsize/5.0)+
+                    (pcmdataL[x]-pcmdataL[x-1])*80*fWaveScale);
+
+                glVertex3f(r*cos(theta)+(wave_x*texsize),r*sin(theta)+(wave_y*texsize),-1);
+            }
+
+            glEnd();
+
+            glPopMatrix();
+
+            break;
+
+        case 2://EXPERIMENTAL
+            wave_y=-1*(wave_y-1.0);
+            glPushMatrix();
+            glBegin(GL_LINE_STRIP);
+            double xx,yy;
+            // double xr= (wave_x*texsize), yr=(wave_y*texsize);
+            xx=0;
+            for ( x=1;x<512;x++)
+            {
+                //xx = ((pcmdataL[x]-pcmdataL[x-1])*80*fWaveScale)*2;
+                xx += (pcmdataL[x]*fWaveScale);
+                yy= pcmdataL[x]*80*fWaveScale;
+                //  glVertex3f( (wave_x*texsize)+(xx+yy)*2, (wave_y*texsize)+(xx-yy)*2,-1);
+                glVertex3f( (wave_x*texsize)+(xx)*2, (wave_y*texsize)+(yy)*2,-1);
+
+
+                //   xr+=fdata_buffer[fbuffer][0][x] *.0005* fWaveScale;
+                //yr=(fdata_buffer[fbuffer][0][x]-fdata_buffer[fbuffer][0][x-1])*.05*fWaveScale+(wave_y*texsize);
+                //glVertex3f(xr,yr,-1);
+
+            }
+            glEnd();
+            glPopMatrix();
+            break;
+
+        case 3://EXPERIMENTAL
+            glPushMatrix();
+            wave_y=-1*(wave_y-1.0);
+            glBegin(GL_LINE_STRIP);
+
+
+            for ( x=1;x<512;x++)
+            {
+                xx= ((pcmdataL[x]-pcmdataL[x-1])*80*fWaveScale)*2;
+                yy=pcmdataL[x]*80*fWaveScale,-1;
+                glVertex3f( (wave_x*texsize)+(xx+yy)*cos(45), (wave_y*texsize)+(-yy+xx)*cos(45),-1);
+            }
+            glEnd();
+            glPopMatrix();
+            break;
+
+        case 4://single x-axis derivative waveform
+            glPushMatrix();
+            wave_y=-1*(wave_y-1.0);
+            glTranslatef(texsize*.5,texsize*.5, 0);
+            glRotated(-wave_mystery*90,0,0,1);
+            glTranslatef(-texsize*.5,-texsize*.5, 0);
+            wave_x=(wave_x*.75)+.125;      wave_x=-(wave_x-1);
+            glBegin(GL_LINE_STRIP);
+
+            double dy_adj;
+            for ( x=1;x<512;x++)
+            {
+                dy_adj=  pcmdataL[x]*20*fWaveScale-pcmdataL[x-1]*20*fWaveScale;
+                glVertex3f((x*scale)+dy_adj, pcmdataL[x]*20*fWaveScale+texsize*wave_x,-1);
+            }
+            glEnd();
+            glPopMatrix();
+            break;
+
+        case 5://EXPERIMENTAL
+            glPushMatrix();
+
+
+            wave_y=-1*(wave_y-1.0);
+            wave_x_temp=(wave_x*.75)+.125;
+            wave_x_temp=-(wave_x_temp-1);
+            glBegin(GL_LINE_STRIP);
+
+            for ( x=1;x<(512);x++)
+            {
+                dy2_adj=  (pcmdataL[x]-pcmdataL[x-1])*20*fWaveScale;
+                glVertex3f((wave_x_temp*texsize)+dy2_adj*2, pcmdataL[x]*20*fWaveScale+texsize*wave_y,-1);
+            }
+            glEnd();
+            glPopMatrix();
+            break;
+
+        case 6://single waveform
+
+
+
+
+            glTranslatef(0,0, -1);
+
+            //glMatrixMode(GL_MODELVIEW);
+            glPushMatrix();
+            //            glLoadIdentity();
+
+            glTranslatef(texsize*.5,texsize*.5, 0);
+            glRotated(-wave_mystery*90,0,0,1);
+
+            wave_x_temp=-2*0.4142*(abs(abs(wave_mystery)-.5)-.5);
+            glScalef(1.0+wave_x_temp,1.0,1.0);
+            glTranslatef(-texsize*.5,-texsize*.5, 0);
+            wave_x_temp=-1*(wave_x-1.0);
+
+            glBegin(GL_LINE_STRIP);
+            //      wave_x_temp=(wave_x*.75)+.125;
+            //      wave_x_temp=-(wave_x_temp-1);
+            for ( x=0;x<numsamples;x++)
+            {
+
+                //glVertex3f(x*scale, fdata_buffer[fbuffer][0][blockstart+x]*.0012*fWaveScale+texsize*wave_x_temp,-1);
+                glVertex3f(x*texsize/(double)numsamples, pcmdataR[x]*20*fWaveScale+texsize*wave_x_temp,-1);
+
+                //glVertex3f(x*scale, texsize*wave_y_temp,-1);
+            }
+            //      printf("%f %f\n",texsize*wave_y_temp,wave_y_temp);
+            glEnd();
+            glPopMatrix();
+            break;
+
+        case 7://dual waveforms
+
+            glPushMatrix();
+
+            glTranslatef(texsize*.5,texsize*.5, 0);
+            glRotated(-wave_mystery*90,0,0,1);
+
+            wave_x_temp=-2*0.4142*(abs(abs(wave_mystery)-.5)-.5);
+            glScalef(1.0+wave_x_temp,1.0,1.0);
+            glTranslatef(-texsize*.5,-texsize*.5, 0);
+
+            wave_y_temp=-1*(wave_x-1);
+
+            glBegin(GL_LINE_STRIP);
+
+            for ( x=0;x<numsamples;x++)
+            {
+
+                glVertex3f((x*texsize)/(double)numsamples, pcmdataL[x]*20*fWaveScale+texsize*(wave_y_temp+(wave_y*wave_y*.5)),-1);
+            }
+            glEnd();
+
+            glBegin(GL_LINE_STRIP);
+
+
+            for ( x=0;x<numsamples;x++)
+            {
+
+                glVertex3f((x*texsize)/(double)numsamples, pcmdataR[x]*20*fWaveScale+texsize*(wave_y_temp-(wave_y*wave_y*.5)),-1);
+            }
+            glEnd();
+            glPopMatrix();
+            break;
+
+        default:
+            glBegin(GL_LINE_LOOP);
+
+            for ( x=0;x<512;x++)
+            {
+                theta=(x)*(6.28/512.0);
+                r= (texsize/5.0+pcmdataL[x]*.002);
+
+                glVertex3f(r*cos(theta)+(wave_x*texsize),r*sin(theta)+(wave_y*texsize),-1);
+            }
+            glEnd();
+
+            glBegin(GL_LINE_STRIP);
+
+            for ( x=0;x<512;x++)
+            {
+                glVertex3f(x*scale, pcmdataL[x]*20*fWaveScale+(texsize*(wave_x+.1)),-1);
+            }
+            glEnd();
+
+            glBegin(GL_LINE_STRIP);
+
+            for ( x=0;x<512;x++)
+            {
+                glVertex3f(x*scale, pcmdataR[x]*20*fWaveScale+(texsize*(wave_x-.1)),-1);
+
+            }
+            glEnd();
+            break;
+            if (bWaveThick==1)  glLineWidth(2*texsize/512);
+    }
+    glLineWidth(texsize/512);
+    glDisable(GL_LINE_STIPPLE);
+}
+
+
+void maximize_colors()
+{
+    float wave_r_switch=0,wave_g_switch=0,wave_b_switch=0;
+    //wave color brightening
+    //
+    //forces max color value to 1.0 and scales
+    // the rest accordingly
+
+    if (bMaximizeWaveColor==1)
+    {
+        if(wave_r>=wave_g && wave_r>=wave_b)   //red brightest
+        {
+            wave_b_switch=wave_b*(1/wave_r);
+            wave_g_switch=wave_g*(1/wave_r);
+            wave_r_switch=1.0;
+        }
+        else if   (wave_b>=wave_g && wave_b>=wave_r)         //blue brightest
+        {
+            wave_r_switch=wave_r*(1/wave_b);
+            wave_g_switch=wave_g*(1/wave_b);
+            wave_b_switch=1.0;
+
+        }
+
+        else  if (wave_g>=wave_b && wave_g>=wave_r)         //green brightest
+        {
+            wave_b_switch=wave_b*(1/wave_g);
+            wave_r_switch=wave_r*(1/wave_g);
+            wave_g_switch=1.0;
+        }
+        glColor4f(wave_r_switch, wave_g_switch, wave_b_switch, wave_o);
+    }
+    else
+    {
+        glColor4f(wave_r, wave_g, wave_b, wave_o);
+    }
+
+}
+
+
+void modulate_opacity_by_volume()
+
+{
+    //modulate volume by opacity
+    //
+    //set an upper and lower bound and linearly
+    //calculate the opacity from 0=lower to 1=upper
+    //based on current volume
+
+    if (bModWaveAlphaByVolume==1)
+    {if (vol<=fModWaveAlphaStart)  wave_o=0.0;
+        else if (vol>=fModWaveAlphaEnd) wave_o=fWaveAlpha;
+        else wave_o=fWaveAlpha*((vol-fModWaveAlphaStart)/(fModWaveAlphaEnd-fModWaveAlphaStart));}
+    else wave_o=fWaveAlpha;
+}
+
+
+void draw_motion_vectors()
+{
+    int x,y;
+
+    double offsetx=mv_dx*texsize, intervalx=texsize/(double)mv_x;
+    double offsety=mv_dy*texsize, intervaly=texsize/(double)mv_y;
+
+    glPointSize(mv_l);
+    glColor4f(mv_r, mv_g, mv_b, mv_a);
+    glBegin(GL_POINTS);
+    for (x=0;x<mv_x;x++){
+        for(y=0;y<mv_y;y++){
+            glVertex3f(offsetx+x*intervalx,offsety+y*intervaly,-1);
+        }}
+
+    glEnd();
+}
+
+
+void draw_borders()
+{
+    //no additive drawing for borders
+    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+    glTranslatef(0,0,-1);
+    //Draw Borders
+    double of=texsize*ob_size*.5;
+    double iff=(texsize*ib_size*.5);
+    double texof=texsize-of;
+
+    glColor4d(ob_r,ob_g,ob_b,ob_a);
+
+    glRectd(0,0,of,texsize);
+    glRectd(of,0,texof,of);
+    glRectd(texof,0,texsize,texsize);
+    glRectd(of,texsize,texof,texof);
+    glColor4d(ib_r,ib_g,ib_b,ib_a);
+    glRectd(of,of,of+iff,texof);
+    glRectd(of+iff,of,texof-iff,of+iff);
+    glRectd(texof-iff,of,texof,texof);
+    glRectd(of+iff,texof,texof-iff,texof-iff);
+}
+
+
+//Here we render the interpolated mesh, and then apply the texture to it.
+//Well, we actually do the inverse, but its all the same.
+void render_interpolation()
+{
+
+    int x,y;
+
+    glMatrixMode(GL_MODELVIEW);
+    glLoadIdentity();
+    glTranslated(0, 0, -9);
+
+    glColor4f(0.0, 0.0, 0.0,decay);
+
+    glEnable(GL_TEXTURE_2D);
+
+    for (x=0;x<gx-1;x++)
+    {
+        glBegin(GL_TRIANGLE_STRIP);
+        for(y=0;y<gy;y++)
+        {
+            glTexCoord4f(x_mesh[x][y], y_mesh[x][y],-1,1); glVertex4f(gridx[x][y], gridy[x][y],-1,1);
+            glTexCoord4f(x_mesh[x+1][y], y_mesh[x+1][y],-1,1); glVertex4f(gridx[x+1][y], gridy[x+1][y],-1,1);
+        }
+        glEnd();
+    }
+    glDisable(GL_TEXTURE_2D);
+}
+
+
+void do_per_frame()
+{
+    //Texture wrapping( clamp vs. wrap)
+    if (bTexWrap==0)
+    {
+        glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+        glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
+    }
+    else
+    {
+        glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+        glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+    }
+
+
+    //      glRasterPos2i(0,0);
+    //      glClear(GL_COLOR_BUFFER_BIT);
+    //      glColor4d(0.0, 0.0, 0.0,1.0);
+
+    //      glMatrixMode(GL_TEXTURE);
+    //  glLoadIdentity();
+
+    glRasterPos2i(0,0);
     glClear(GL_COLOR_BUFFER_BIT);
+    glColor4d(0.0, 0.0, 0.0,1.0);
+
+    glMatrixMode(GL_TEXTURE);
+    glLoadIdentity();
 
-    glBegin(GL_TRIANGLE_STRIP);
-        glColor3f( 0.5f, 0.0f, 0.0f);
-        glVertex2f(  -1.0f,  1.0f);
-        glColor3f( 0.2f, 0.2f, 0.0f);
-        glVertex2f(  1.0f,  1.0f);
-        glColor3f( 0.0f, 0.2f, 0.2f);
-        glVertex2f(  -1.0f,  -1.0f);
-        glColor3f( 0.0f, 0.0f, 0.5f);
-        glVertex2f(  1.0f,  -1.0f);
+    glTranslatef(cx,cy, 0);
+    if(correction)  glScalef(1,vw/(double)vh,1);
+
+    if(!isPerPixelEqn(ROT_OP))
+    {
+        //    printf("ROTATING: rot = %f\n", rot);
+        glRotatef(rot*90, 0, 0, 1);
+    }
+    if(!isPerPixelEqn(SX_OP)) glScalef(1/sx,1,1);
+    if(!isPerPixelEqn(SY_OP)) glScalef(1,1/sy,1);
+
+    if(correction) glScalef(1,vh/(double)vw,1);
+    glTranslatef((-cx) ,(-cy),0);
+
+    if(!isPerPixelEqn(DX_OP)) glTranslatef(-dx,0,0);
+    if(!isPerPixelEqn(DY_OP)) glTranslatef(0 ,-dy,0);
+
+}
+
+
+//Actually draws the texture to the screen
+//
+//The Video Echo effect is also applied here
+void render_texture_to_screen()
+{
+    glMatrixMode(GL_TEXTURE);
+    glLoadIdentity();
+
+    glMatrixMode(GL_MODELVIEW);
+    glLoadIdentity();
+    glTranslatef(0, 0, -9);
+
+    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+
+    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,  GL_DECAL);
+    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
+
+    //       glClear(GL_ACCUM_BUFFER_BIT);
+    glColor4d(0.0, 0.0, 0.0,1.0f);
+
+    glBegin(GL_QUADS);
+    glVertex4d(-vw*.5,-vh*.5,-1,1);
+    glVertex4d(-vw*.5,  vh*.5,-1,1);
+    glVertex4d(vw*.5,  vh*.5,-1,1);
+    glVertex4d(vw*.5, -vh*.5,-1,1);
     glEnd();
-    glBegin(GL_LINE_STRIP);
-        glColor3f( 1.0f, 1.0f, 1.0f);
-        glVertex2f( -1.0f, 0.0f);
-        for(j=0; j<512; j++)
+
+    //      glBindTexture( GL_TEXTURE_2D, tex2 );
+    glEnable(GL_TEXTURE_2D);
+
+    // glAccum(GL_LOAD,0);
+    // if (bDarken==1)  glBlendFunc(GL_SRC_COLOR,GL_ZERO);
+
+    //Draw giant rectangle and texture it with our texture!
+    glBegin(GL_QUADS);
+    glTexCoord4d(0, 1,0,1); glVertex4d(-vw*.5,-vh*.5,-1,1);
+    glTexCoord4d(0, 0,0,1); glVertex4d(-vw*.5,  vh*.5,-1,1);
+    glTexCoord4d(1, 0,0,1); glVertex4d(vw*.5,  vh*.5,-1,1);
+    glTexCoord4d(1, 1,0,1); glVertex4d(vw*.5, -vh*.5,-1,1);
+    glEnd();
+
+    glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+
+    //  if (bDarken==1)  glBlendFunc(GL_SRC_COLOR,GL_ONE_MINUS_SRC_ALPHA);
+
+    // if (bDarken==1) { glAccum(GL_ACCUM,1-fVideoEchoAlpha); glBlendFunc(GL_SRC_COLOR,GL_ZERO); }
+
+    glMatrixMode(GL_TEXTURE);
+
+    //draw video echo
+    glColor4f(0.0, 0.0, 0.0,fVideoEchoAlpha);
+    glTranslated(.5,.5,0);
+    glScaled(1/fVideoEchoZoom,1/fVideoEchoZoom,1);
+    glTranslated(-.5,-.5,0);
+
+    int flipx=1,flipy=1;
+    switch (((int)nVideoEchoOrientation))
+    {
+        case 0: flipx=1;flipy=1;break;
+        case 1: flipx=-1;flipy=1;break;
+        case 2: flipx=1;flipy=-1;break;
+        case 3: flipx=-1;flipy=-1;break;
+        default: flipx=1;flipy=1; break;
+    }
+    glBegin(GL_QUADS);
+    glTexCoord4d(0, 1,0,1); glVertex4f(-vw*.5*flipx,-vh*.5*flipy,-1,1);
+    glTexCoord4d(0, 0,0,1); glVertex4f(-vw*.5*flipx,  vh*.5*flipy,-1,1);
+    glTexCoord4d(1, 0,0,1); glVertex4f(vw*.5*flipx,  vh*.5*flipy,-1,1);
+    glTexCoord4d(1, 1,0,1); glVertex4f(vw*.5*flipx, -vh*.5*flipy,-1,1);
+    glEnd();
+
+
+    glDisable(GL_TEXTURE_2D);
+    glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+
+    // if (bDarken==1) { glAccum(GL_ACCUM,fVideoEchoAlpha); glAccum(GL_RETURN,1);}
+
+    if (bInvert==1)
+    {
+        glColor4f(1.0, 1.0, 1.0,1.0);
+        glBlendFunc(GL_ONE_MINUS_DST_COLOR,GL_ZERO);
+        glBegin(GL_QUADS);
+        glVertex4f(-vw*.5*flipx,-vh*.5*flipy,-1,1);
+        glVertex4f(-vw*.5*flipx,  vh*.5*flipy,-1,1);
+        glVertex4f(vw*.5*flipx,  vh*.5*flipy,-1,1);
+        glVertex4f(vw*.5*flipx, -vh*.5*flipy,-1,1);
+        glEnd();
+        glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+    }
+}
+
+
+void render_texture_to_studio()
+{
+    glMatrixMode(GL_TEXTURE);
+    glLoadIdentity();
+
+    glMatrixMode(GL_MODELVIEW);
+    glLoadIdentity();
+    glTranslatef(0, 0, -9);
+
+    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+
+    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,  GL_DECAL);
+    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
+
+    //       glClear(GL_ACCUM_BUFFER_BIT);
+    glColor4f(0.0, 0.0, 0.0,0.04);
+
+    glVertex4d(-vw*.5,-vh*.5,-1,1);
+    glVertex4d(-vw*.5,  vh*.5,-1,1);
+    glVertex4d(vw*.5,  vh*.5,-1,1);
+    glVertex4d(vw*.5, -vh*.5,-1,1);
+    glEnd();
+
+    glColor4f(0.0, 0.0, 0.0,1.0);
+
+    glBegin(GL_QUADS);
+    glVertex4d(-vw*.5,0,-1,1);
+    glVertex4d(-vw*.5,  vh*.5,-1,1);
+    glVertex4d(vw*.5,  vh*.5,-1,1);
+    glVertex4d(vw*.5, 0,-1,1);
+    glEnd();
+
+    glBegin(GL_QUADS);
+    glVertex4d(0,-vh*.5,-1,1);
+    glVertex4d(0,  vh*.5,-1,1);
+    glVertex4d(vw*.5,  vh*.5,-1,1);
+    glVertex4d(vw*.5, -vh*.5,-1,1);
+    glEnd();
+
+    glPushMatrix();
+    glTranslatef(.25*vw, .25*vh, 0);
+    glScalef(.5,.5,1);
+
+    //      glBindTexture( GL_TEXTURE_2D, tex2 );
+    glEnable(GL_TEXTURE_2D);
+
+    // glAccum(GL_LOAD,0);
+    // if (bDarken==1)  glBlendFunc(GL_SRC_COLOR,GL_ZERO);
+
+    //Draw giant rectangle and texture it with our texture!
+    glBegin(GL_QUADS);
+    glTexCoord4d(0, 1,0,1); glVertex4d(-vw*.5,-vh*.5,-1,1);
+    glTexCoord4d(0, 0,0,1); glVertex4d(-vw*.5,  vh*.5,-1,1);
+    glTexCoord4d(1, 0,0,1); glVertex4d(vw*.5,  vh*.5,-1,1);
+    glTexCoord4d(1, 1,0,1); glVertex4d(vw*.5, -vh*.5,-1,1);
+    glEnd();
+
+    glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+
+    //  if (bDarken==1)  glBlendFunc(GL_SRC_COLOR,GL_ONE_MINUS_SRC_ALPHA);
+
+    // if (bDarken==1) { glAccum(GL_ACCUM,1-fVideoEchoAlpha); glBlendFunc(GL_SRC_COLOR,GL_ZERO); }
+
+    glMatrixMode(GL_TEXTURE);
+
+    //draw video echo
+    glColor4f(0.0, 0.0, 0.0,fVideoEchoAlpha);
+    glTranslated(.5,.5,0);
+    glScaled(1/fVideoEchoZoom,1/fVideoEchoZoom,1);
+    glTranslated(-.5,-.5,0);
+
+    int flipx=1,flipy=1;
+    switch (((int)nVideoEchoOrientation))
+    {
+        case 0: flipx=1;flipy=1;break;
+        case 1: flipx=-1;flipy=1;break;
+        case 2: flipx=1;flipy=-1;break;
+        case 3: flipx=-1;flipy=-1;break;
+        default: flipx=1;flipy=1; break;
+    }
+    glBegin(GL_QUADS);
+    glTexCoord4d(0, 1,0,1); glVertex4f(-vw*.5*flipx,-vh*.5*flipy,-1,1);
+    glTexCoord4d(0, 0,0,1); glVertex4f(-vw*.5*flipx,  vh*.5*flipy,-1,1);
+    glTexCoord4d(1, 0,0,1); glVertex4f(vw*.5*flipx,  vh*.5*flipy,-1,1);
+    glTexCoord4d(1, 1,0,1); glVertex4f(vw*.5*flipx, -vh*.5*flipy,-1,1);
+    glEnd();
+
+    glDisable(GL_TEXTURE_2D);
+    glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+
+    // if (bDarken==1) { glAccum(GL_ACCUM,fVideoEchoAlpha); glAccum(GL_RETURN,1);}
+
+
+    if (bInvert==1)
+    {
+        glColor4f(1.0, 1.0, 1.0,1.0);
+        glBlendFunc(GL_ONE_MINUS_DST_COLOR,GL_ZERO);
+        glBegin(GL_QUADS);
+        glVertex4f(-vw*.5*flipx,-vh*.5*flipy,-1,1);
+        glVertex4f(-vw*.5*flipx,  vh*.5*flipy,-1,1);
+        glVertex4f(vw*.5*flipx,  vh*.5*flipy,-1,1);
+        glVertex4f(vw*.5*flipx, -vh*.5*flipy,-1,1);
+        glEnd();
+        glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+    }
+
+    //  glTranslated(.5,.5,0);
+    //  glScaled(1/fVideoEchoZoom,1/fVideoEchoZoom,1);
+    //   glTranslated(-.5,-.5,0);
+    //glTranslatef(0,.5*vh,0);
+
+    //per_pixel monitor
+    //glBlendFunc(GL_ONE_MINUS_DST_COLOR,GL_ZERO);
+    int x,y;
+    glMatrixMode(GL_MODELVIEW);
+    glPopMatrix();
+    glPushMatrix();
+    glTranslatef(.25*vw, -.25*vh, 0);
+    glScalef(.5,.5,1);
+    glColor4f(1,1,1,.6);
+
+    for (x=0;x<gx;x++)
+    {
+        glBegin(GL_LINE_STRIP);
+        for(y=0;y<gy;y++)
+        {
+            glVertex4f((x_mesh[x][y]-.5)* vw, (y_mesh[x][y]-.5)*vh,-1,1);
+            //glVertex4f((origx[x+1][y]-.5) * vw, (origy[x+1][y]-.5) *vh ,-1,1);
+        }
+        glEnd();
+    }
+
+    for (y=0;y<gy;y++)
+    {
+        glBegin(GL_LINE_STRIP);
+        for(x=0;x<gx;x++)
         {
-            glVertex2f( (float)j/256-1.0f, (float)p_data[0][j]/32000);
+            glVertex4f((x_mesh[x][y]-.5)* vw, (y_mesh[x][y]-.5)*vh,-1,1);
+            //glVertex4f((origx[x+1][y]-.5) * vw, (origy[x+1][y]-.5) *vh ,-1,1);
         }
+        glEnd();
+    }
+
+    /*
+       for (x=0;x<gx-1;x++){
+       glBegin(GL_POINTS);
+       for(y=0;y<gy;y++){
+       glVertex4f((origx[x][y]-.5)* vw, (origy[x][y]-.5)*vh,-1,1);
+       glVertex4f((origx[x+1][y]-.5) * vw, (origy[x+1][y]-.5) *vh ,-1,1);
+       }
+       glEnd();
+       }
+     */
+    // glTranslated(-.5,-.5,0);     glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+    glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
+    glMatrixMode(GL_MODELVIEW);
+    glPopMatrix();
+    glPushMatrix();
+    glTranslatef(-.5*vw,0, 0);
+
+
+    glTranslatef(0,-vh*.10, 0);
+    glBegin(GL_LINE_STRIP);
+    glColor4f(0,1.0,1.0,1.0);
+    glVertex3f((((totalframes%256)/551.0))*vw, treb_att*-7,-1);
+    glColor4f(1.0,1.0,1.0,1.0);
+    glVertex3f((((totalframes%256)/551.0))*vw,0 ,-1);
+    glColor4f(.5,1.0,1.0,1.0);
+    glVertex3f((((totalframes%256)/551.0))*vw, treb*7,-1);
     glEnd();
 
-    galaktos_glx_swap( p_thread );
+    glTranslatef(0,-vh*.13, 0);
+    glBegin(GL_LINE_STRIP);
+    glColor4f(0,1.0,0.0,1.0);
+    glVertex3f((((totalframes%256)/551.0))*vw, mid_att*-7,-1);
+    glColor4f(1.0,1.0,1.0,1.0);
+    glVertex3f((((totalframes%256)/551.0))*vw,0 ,-1);
+    glColor4f(.5,1.0,0.0,0.5);
+    glVertex3f((((totalframes%256)/551.0))*vw, mid*7,-1);
+    glEnd();
 
-    return 0;
+    glTranslatef(0,-vh*.13, 0);
+    glBegin(GL_LINE_STRIP);
+    glColor4f(1.0,0.0,0.0,1.0);
+    glVertex3f((((totalframes%256)/551.0))*vw, bass_att*-7,-1);
+    glColor4f(1.0,1.0,1.0,1.0);
+    glVertex3f((((totalframes%256)/551.0))*vw,0 ,-1);
+    glColor4f(.7,0.2,0.2,1.0);
+    glVertex3f((((totalframes%256)/551.0))*vw, bass*7,-1);
+    glEnd();
+
+    glTranslatef(0,-vh*.13, 0);
+    glBegin(GL_LINES);
+
+    glColor4f(1.0,1.0,1.0,1.0);
+    glVertex3f((((totalframes%256)/551.0))*vw,0 ,-1);
+    glColor4f(1.0,0.6,1.0,1.0);
+    glVertex3f((((totalframes%256)/551.0))*vw, vol*7,-1);
+    glEnd();
+
+    glPopMatrix();
 }
 
 
index de7eb88bc0c24ca9f3a482dd0bf473aa3ffef296..6d197421e3a16cd01d0a27911d100a287b431d2a 100644 (file)
@@ -24,6 +24,8 @@
 #ifndef _GALAKTOS_MAIN_H_
 #define _GALAKTOS_MAIN_H_
 
-int galaktos_update( galaktos_thread_t *p_thread, int16_t p_data[2][512] );
+int galaktos_init( galaktos_thread_t *p_thread );
+void galaktos_done( galaktos_thread_t *p_thread );
+int galaktos_update( galaktos_thread_t *p_thread );
 
 #endif
diff --git a/modules/visualization/galaktos/param.c b/modules/visualization/galaktos/param.c
new file mode 100644 (file)
index 0000000..bf8f0e4
--- /dev/null
@@ -0,0 +1,721 @@
+/*****************************************************************************
+ * param.c:
+ *****************************************************************************
+ * Copyright (C) 2004 VideoLAN
+ * $Id$
+ *
+ * Authors: Cyril Deguet <asmax@videolan.org>
+ *          code from projectM http://xmms-projectm.sourceforge.net
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ *****************************************************************************/
+
+
+
+/* Basic Parameter Functions */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+#include "fatal.h"
+#include "common.h"
+
+#include "splaytree_types.h"
+#include "splaytree.h"
+#include "tree_types.h"
+
+#include "param_types.h"
+#include "param.h"
+
+#include "expr_types.h"
+#include "eval.h"
+
+#include "engine_vars.h" 
+
+void reset_param(param_t * param);
+
+int is_valid_param_string(char * string); /* true if string is valid variable or function name */
+
+
+/* A splay tree of builtin parameters */
+splaytree_t * builtin_param_tree = NULL;
+
+int insert_param_alt_name(param_t * param, char * alt_name);
+
+int insert_builtin_param(param_t * param);
+
+/* Private function prototypes */
+int compare_param(char * name, char * name2);
+
+int load_builtin_param_double(char * name, void * engine_val, void * matrix, short int flags, 
+                                                               double init_val, double upper_bound, double lower_bound, char * alt_name);
+
+int load_builtin_param_int(char * name, void * engine_val, short int flags, 
+                                                               int init_val, int upper_bound, int lower_bound, char * alt_name);
+                                                               
+int load_builtin_param_bool(char * name, void * engine_val, short int flags, 
+                                                               int init_val, char * alt_name);
+                                                               
+                                                               
+                                                               
+param_t * create_param (char * name, short int type, short int flags, void * engine_val, void * matrix,
+                                                       value_t default_init_val, value_t upper_bound, value_t lower_bound) {
+
+  param_t * param = NULL;
+
+  param = (param_t*)malloc(sizeof(param_t));
+  if (param == NULL) {
+       printf("create_param: out of memory!!!\n");
+       return NULL;
+  }
+  
+  /* Clear name space, think the strncpy statement makes this redundant */
+  //memset(param->name, 0, MAX_TOKEN_SIZE);
+
+  /* Copy given name into parameter structure */
+  strncpy(param->name, name, MAX_TOKEN_SIZE-1); 
+  
+  /* Assign other entries in a constructor like fashion */
+  param->type = type;
+  param->flags = flags;
+  param->matrix_flag = 0;
+  param->matrix = matrix;
+  param->engine_val = engine_val;
+  param->default_init_val = default_init_val;
+  //*param->init_val = default_init_val;
+  param->upper_bound = upper_bound;
+  param->lower_bound = lower_bound;
+  
+  /* Return instantiated parameter */
+  return param;
+
+}
+
+/* Creates a user defined parameter */
+param_t * create_user_param(char * name) {
+
+  param_t * param;
+  value_t iv;
+  value_t ub;
+  value_t lb;
+  double * engine_val;
+  
+  /* Set initial values to default */
+  iv.double_val = DEFAULT_DOUBLE_IV;
+  ub.double_val = DEFAULT_DOUBLE_UB;
+  lb.double_val = DEFAULT_DOUBLE_LB;
+
+  /* Argument checks */
+  if (name == NULL)
+    return NULL;
+
+  /* Allocate space for the engine variable */
+  if ((engine_val = (double*)malloc(sizeof(double))) == NULL)
+    return NULL;
+
+  (*engine_val) = iv.double_val; /* set some default init value */
+  
+  /* Create the new user parameter */
+  if ((param = create_param(name, P_TYPE_DOUBLE, P_FLAG_USERDEF, engine_val, NULL, iv, ub, lb)) == NULL) {
+    free(engine_val);
+    return NULL;
+  }
+  if (PARAM_DEBUG) printf("create_param: \"%s\" initialized\n", param->name);
+  /* Return the instantiated parameter */
+  return param;
+}
+
+/* Initialize the builtin parameter database.
+   Should only be necessary once */
+int init_builtin_param_db() {
+       
+  /* Create the builtin parameter splay tree (go Sleator...) */
+  if ((builtin_param_tree = create_splaytree(compare_string, copy_string, free_string)) == NULL) {
+         if (PARAM_DEBUG) printf("init_builtin_param_db: failed to initialize database (FATAL)\n");  
+         return OUTOFMEM_ERROR;
+  } 
+
+  if (PARAM_DEBUG) {
+         printf("init_builtin_param: loading database...");
+         fflush(stdout);
+  }
+  
+  /* Loads all builtin parameters into the database */
+  if (load_all_builtin_param() < 0) {
+       if (PARAM_DEBUG) printf("failed loading builtin parameters (FATAL)\n");
+    return ERROR;
+  }
+  
+  if (PARAM_DEBUG) printf("success!\n");
+         
+  /* Finished, no errors */
+  return SUCCESS;
+}
+
+/* Destroy the builtin parameter database.
+   Generally, do this on projectm exit */
+int destroy_builtin_param_db() {
+  
+  splay_traverse(free_param, builtin_param_tree);
+  destroy_splaytree(builtin_param_tree);
+  builtin_param_tree = NULL;
+  return SUCCESS;      
+
+}
+
+
+/* Insert a parameter into the database with an alternate name */
+int insert_param_alt_name(param_t * param, char * alt_name) {
+  
+  if (param == NULL)
+    return ERROR;
+  if (alt_name == NULL)
+         return ERROR;
+       
+  splay_insert_link(alt_name, param->name, builtin_param_tree);
+
+  return SUCCESS;
+}
+
+
+param_t * find_builtin_param(char * name) {
+
+  /* Null argument checks */
+  if (name == NULL)
+         return NULL;
+    
+  return splay_find(name, builtin_param_tree);
+
+}
+
+/* Find a parameter given its name, will create one if not found */
+param_t * find_param(char * name, preset_t * preset, int flags) {
+
+  param_t * param = NULL;
+
+  /* Null argument checks */
+  if (name == NULL)
+         return NULL;
+  if (preset == NULL)
+         return NULL;
+  
+  /* First look in the builtin database */
+  param = (param_t *)splay_find(name, builtin_param_tree);
+
+  /* If the search failed, check the user database */
+  if (param == NULL) {
+    param = (param_t*)splay_find(name, preset->user_param_tree);
+  }
+  /* If it doesn't exist in the user (or builtin) database and 
+         create_flag is set, then make it and insert into the database 
+  */
+  
+  if ((param == NULL) && (flags & P_CREATE)) {
+       
+       /* Check if string is valid */
+    if (!is_valid_param_string(name)) {
+      if (PARAM_DEBUG) printf("find_param: invalid parameter name:\"%s\"\n", name);
+      return NULL;
+    }
+    /* Now, create the user defined parameter given the passed name */
+    if ((param = create_user_param(name)) == NULL) {
+      if (PARAM_DEBUG) printf("find_param: failed to create a new user parameter!\n");
+      return NULL;
+    }
+    /* Finally, insert the new parameter into this preset's proper splaytree */
+    if (splay_insert(param, param->name, preset->user_param_tree) < 0) {
+      if (PARAM_DEBUG) printf("PARAM \"%s\" already exists in user parameter tree!\n", param->name);
+      free_param(param);
+      return NULL;
+    }   
+    
+  }      
+  
+  /* Return the found (or created) parameter. Note that if P_CREATE is not set, this could be null */
+  return param;
+  
+}
+
+/* Compare string name with parameter name */
+int compare_param(char * name, char * name2) {
+
+  int cmpval;
+  printf("am i used\n");
+  /* Uses string comparison function */
+  cmpval = strncmp(name, name2, MAX_TOKEN_SIZE-1);
+  
+  return cmpval;
+}
+
+/* Loads all builtin parameters, limits are also defined here */
+int load_all_builtin_param() {
+
+  load_builtin_param_double("fRating", (void*)&fRating, NULL, P_FLAG_NONE, 0.0 , 5.0, 0.0, NULL);
+  load_builtin_param_double("fWaveScale", (void*)&fWaveScale, NULL, P_FLAG_NONE, 0.0, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, NULL);
+  load_builtin_param_double("gamma", (void*)&fGammaAdj, NULL, P_FLAG_NONE, 0.0, MAX_DOUBLE_SIZE, 0, "fGammaAdj");
+  load_builtin_param_double("echo_zoom", (void*)&fVideoEchoZoom, NULL, P_FLAG_NONE, 0.0, MAX_DOUBLE_SIZE, 0, "fVideoEchoZoom");
+  load_builtin_param_double("echo_alpha", (void*)&fVideoEchoAlpha, NULL, P_FLAG_NONE, 0.0, MAX_DOUBLE_SIZE, 0, "fVideoEchoAlpha");
+  load_builtin_param_double("wave_a", (void*)&fWaveAlpha, NULL, P_FLAG_NONE, 0.0, 1.0, 0, "fWaveAlpha");
+  load_builtin_param_double("fWaveSmoothing", (void*)&fWaveSmoothing, NULL, P_FLAG_NONE, 0.0, 1.0, -1.0, NULL);  
+  load_builtin_param_double("fModWaveAlphaStart", (void*)&fModWaveAlphaStart, NULL, P_FLAG_NONE, 0.0, 1.0, -1.0, NULL);
+  load_builtin_param_double("fModWaveAlphaEnd", (void*)&fModWaveAlphaEnd, NULL, P_FLAG_NONE, 0.0, 1.0, -1.0, NULL);
+  load_builtin_param_double("fWarpAnimSpeed",  (void*)&fWarpAnimSpeed, NULL, P_FLAG_NONE, 0.0, 1.0, -1.0, NULL);
+  //  load_builtin_param_double("warp", (void*)&warp, warp_mesh, P_FLAG_NONE, 0.0, MAX_DOUBLE_SIZE, 0, NULL);
+       
+  load_builtin_param_double("fShader", (void*)&fShader, NULL, P_FLAG_NONE, 0.0, 1.0, -1.0, NULL);
+  load_builtin_param_double("decay", (void*)&decay, NULL, P_FLAG_NONE, 0.0, 1.0, 0, "fDecay");
+
+  load_builtin_param_int("echo_orient", (void*)&nVideoEchoOrientation, P_FLAG_NONE, 0, 3, 0, "nVideoEchoOrientation");
+  load_builtin_param_int("wave_mode", (void*)&nWaveMode, P_FLAG_NONE, 0, 7, 0, "nWaveMode");
+  
+  load_builtin_param_bool("wave_additive", (void*)&bAdditiveWaves, P_FLAG_NONE, FALSE, "bAdditiveWaves");
+  load_builtin_param_bool("bModWaveAlphaByVolume", (void*)&bModWaveAlphaByVolume, P_FLAG_NONE, FALSE, NULL);
+  load_builtin_param_bool("wave_brighten", (void*)&bMaximizeWaveColor, P_FLAG_NONE, FALSE, "bMaximizeWaveColor");
+  load_builtin_param_bool("wrap", (void*)&bTexWrap, P_FLAG_NONE, FALSE, "bTexWrap");
+  load_builtin_param_bool("darken_center", (void*)&bDarkenCenter, P_FLAG_NONE, FALSE, "bDarkenCenter");
+  load_builtin_param_bool("bRedBlueStereo", (void*)&bRedBlueStereo, P_FLAG_NONE, FALSE, NULL);
+  load_builtin_param_bool("brighten", (void*)&bBrighten, P_FLAG_NONE, FALSE, "bBrighten");
+  load_builtin_param_bool("darken", (void*)&bDarken, P_FLAG_NONE, FALSE, "bDarken");
+  load_builtin_param_bool("solarize", (void*)&bSolarize, P_FLAG_NONE, FALSE, "bSolarize");
+  load_builtin_param_bool("invert", (void*)&bInvert, P_FLAG_NONE, FALSE, "bInvert");
+  load_builtin_param_bool("bMotionVectorsOn", (void*)&bMotionVectorsOn, P_FLAG_NONE, FALSE, NULL);
+  load_builtin_param_bool("wave_dots", (void*)&bWaveDots, P_FLAG_NONE, FALSE, "bWaveDots");
+  load_builtin_param_bool("wave_thick", (void*)&bWaveThick, P_FLAG_NONE, FALSE, "bWaveThick");
+  
+  
+  load_builtin_param_double("zoom", (void*)&zoom, zoom_mesh,  P_FLAG_PER_PIXEL |P_FLAG_DONT_FREE_MATRIX, 0.0, MAX_DOUBLE_SIZE, 0, NULL);
+  load_builtin_param_double("rot", (void*)&rot, rot_mesh,  P_FLAG_PER_PIXEL |P_FLAG_DONT_FREE_MATRIX, 0.0, MAX_DOUBLE_SIZE, MIN_DOUBLE_SIZE, NULL);
+  load_builtin_param_double("zoomexp", (void*)&zoomexp, zoomexp_mesh,  P_FLAG_PER_PIXEL |P_FLAG_NONE, 0.0, MAX_DOUBLE_SIZE, 0, "fZoomExponent");
+  load_builtin_param_double("cx", (void*)&cx, cx_mesh, P_FLAG_PER_PIXEL | P_FLAG_DONT_FREE_MATRIX, 0.0, 1.0, 0, NULL);
+  load_builtin_param_double("cy", (void*)&cy, cy_mesh, P_FLAG_PER_PIXEL | P_FLAG_DONT_FREE_MATRIX, 0.0, 1.0, 0, NULL);
+  load_builtin_param_double("dx", (void*)&dx, dx_mesh,  P_FLAG_PER_PIXEL | P_FLAG_DONT_FREE_MATRIX, 0.0, MAX_DOUBLE_SIZE, MIN_DOUBLE_SIZE, NULL);
+  load_builtin_param_double("dy", (void*)&dy, dy_mesh,  P_FLAG_PER_PIXEL |P_FLAG_DONT_FREE_MATRIX, 0.0, MAX_DOUBLE_SIZE, MIN_DOUBLE_SIZE, NULL);
+  load_builtin_param_double("sx", (void*)&sx, sx_mesh,  P_FLAG_PER_PIXEL |P_FLAG_DONT_FREE_MATRIX, 0.0, MAX_DOUBLE_SIZE, 0, NULL);
+  load_builtin_param_double("sy", (void*)&sy, sy_mesh,  P_FLAG_PER_PIXEL |P_FLAG_DONT_FREE_MATRIX, 0.0, MAX_DOUBLE_SIZE, 0, NULL);
+
+  load_builtin_param_double("wave_r", (void*)&wave_r, NULL, P_FLAG_NONE, 0.0, 1.0, 0.0, NULL);
+  load_builtin_param_double("wave_g", (void*)&wave_g, NULL, P_FLAG_NONE, 0.0, 1.0, 0.0, NULL);
+  load_builtin_param_double("wave_b", (void*)&wave_b, NULL, P_FLAG_NONE, 0.0, 1.0, 0.0, NULL);
+  load_builtin_param_double("wave_x", (void*)&wave_x, NULL, P_FLAG_NONE, 0.0, 1.0, 0.0, NULL);
+  load_builtin_param_double("wave_y", (void*)&wave_y, NULL, P_FLAG_NONE, 0.0, 1.0, 0.0, NULL);
+  load_builtin_param_double("wave_mystery", (void*)&wave_mystery, NULL, P_FLAG_NONE, 0.0, 1.0, -1.0, "fWaveParam");
+  
+  load_builtin_param_double("ob_size", (void*)&ob_size, NULL, P_FLAG_NONE, 0.0, 0.5, 0, NULL);
+  load_builtin_param_double("ob_r", (void*)&ob_r, NULL, P_FLAG_NONE, 0.0, 1.0, 0.0, NULL);
+  load_builtin_param_double("ob_g", (void*)&ob_g, NULL, P_FLAG_NONE, 0.0, 1.0, 0.0, NULL);
+  load_builtin_param_double("ob_b", (void*)&ob_b, NULL, P_FLAG_NONE, 0.0, 1.0, 0.0, NULL);
+  load_builtin_param_double("ob_a", (void*)&ob_a, NULL, P_FLAG_NONE, 0.0, 1.0, 0.0, NULL);
+
+  load_builtin_param_double("ib_size", (void*)&ib_size,  NULL,P_FLAG_NONE, 0.0, .5, 0.0, NULL);
+  load_builtin_param_double("ib_r", (void*)&ib_r,  NULL,P_FLAG_NONE, 0.0, 1.0, 0.0, NULL);
+  load_builtin_param_double("ib_g", (void*)&ib_g,  NULL,P_FLAG_NONE, 0.0, 1.0, 0.0, NULL);
+  load_builtin_param_double("ib_b", (void*)&ib_b,  NULL,P_FLAG_NONE, 0.0, 1.0, 0.0, NULL);
+  load_builtin_param_double("ib_a", (void*)&ib_a,  NULL,P_FLAG_NONE, 0.0, 1.0, 0.0, NULL);
+
+  load_builtin_param_double("mv_r", (void*)&mv_r,  NULL,P_FLAG_NONE, 0.0, 1.0, 0.0, NULL);
+  load_builtin_param_double("mv_g", (void*)&mv_g,  NULL,P_FLAG_NONE, 0.0, 1.0, 0.0, NULL);
+  load_builtin_param_double("mv_b", (void*)&mv_b,  NULL,P_FLAG_NONE, 0.0, 1.0, 0.0, NULL);
+  load_builtin_param_double("mv_x", (void*)&mv_x,  NULL,P_FLAG_NONE, 0.0, 64.0, 0.0, "nMotionVectorsX");
+  load_builtin_param_double("mv_y", (void*)&mv_y,  NULL,P_FLAG_NONE, 0.0, 48.0, 0.0, "nMotionVectorsY");
+  load_builtin_param_double("mv_l", (void*)&mv_l,  NULL,P_FLAG_NONE, 0.0, 5.0, 0.0, NULL);
+  load_builtin_param_double("mv_dy", (void*)&mv_dy, NULL, P_FLAG_NONE, 0.0, 1.0, -1.0, NULL);
+  load_builtin_param_double("mv_dx", (void*)&mv_dx,  NULL,P_FLAG_NONE, 0.0, 1.0, -1.0, NULL);
+  load_builtin_param_double("mv_a", (void*)&mv_a,  NULL,P_FLAG_NONE, 0.0, 1.0, 0.0, NULL);
+
+  load_builtin_param_double("time", (void*)&Time,  NULL,P_FLAG_READONLY, 0.0, MAX_DOUBLE_SIZE, 0.0, NULL);        
+  load_builtin_param_double("bass", (void*)&bass,  NULL,P_FLAG_READONLY, 0.0, MAX_DOUBLE_SIZE, 0.0, NULL);
+  load_builtin_param_double("mid", (void*)&mid,  NULL,P_FLAG_READONLY, 0.0, MAX_DOUBLE_SIZE, 0, NULL);      
+  load_builtin_param_double("bass_att", (void*)&bass_att,  NULL,P_FLAG_READONLY, 0.0, MAX_DOUBLE_SIZE, 0, NULL);
+  load_builtin_param_double("mid_att", (void*)&mid_att,  NULL,P_FLAG_READONLY, 0.0, MAX_DOUBLE_SIZE, 0, NULL);
+  load_builtin_param_double("treb_att", (void*)&treb_att,  NULL,P_FLAG_READONLY, 0.0, MAX_DOUBLE_SIZE, 0, NULL);
+  load_builtin_param_int("frame", (void*)&frame, P_FLAG_READONLY, 0, MAX_INT_SIZE, 0, NULL);
+  load_builtin_param_double("progress", (void*)&progress,  NULL,P_FLAG_READONLY, 0.0, 1, 0, NULL);
+  load_builtin_param_int("fps", (void*)&fps, P_FLAG_NONE, 15, MAX_INT_SIZE, 0, NULL);
+
+
+
+  load_builtin_param_double("x", (void*)&x_per_pixel, x_mesh,  P_FLAG_PER_PIXEL |P_FLAG_ALWAYS_MATRIX | P_FLAG_READONLY | P_FLAG_DONT_FREE_MATRIX, 
+                           0, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, NULL);
+  load_builtin_param_double("y", (void*)&y_per_pixel, y_mesh,  P_FLAG_PER_PIXEL |P_FLAG_ALWAYS_MATRIX |P_FLAG_READONLY | P_FLAG_DONT_FREE_MATRIX, 
+                           0, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, NULL);
+  load_builtin_param_double("ang", (void*)&ang_per_pixel, theta_mesh,  P_FLAG_PER_PIXEL |P_FLAG_ALWAYS_MATRIX | P_FLAG_READONLY | P_FLAG_DONT_FREE_MATRIX, 
+                           0, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, NULL);      
+  load_builtin_param_double("rad", (void*)&rad_per_pixel, rad_mesh,  P_FLAG_PER_PIXEL |P_FLAG_ALWAYS_MATRIX | P_FLAG_READONLY | P_FLAG_DONT_FREE_MATRIX, 
+                           0, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, NULL);
+
+
+  load_builtin_param_double("q1", (void*)&q1,  NULL, P_FLAG_PER_PIXEL |P_FLAG_QVAR, 0, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, NULL);
+  load_builtin_param_double("q2", (void*)&q2,  NULL, P_FLAG_PER_PIXEL |P_FLAG_QVAR, 0, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, NULL);
+  load_builtin_param_double("q3", (void*)&q3,  NULL, P_FLAG_PER_PIXEL |P_FLAG_QVAR, 0, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, NULL);
+  load_builtin_param_double("q4", (void*)&q4,  NULL, P_FLAG_PER_PIXEL |P_FLAG_QVAR, 0, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, NULL);
+  load_builtin_param_double("q5", (void*)&q5,  NULL, P_FLAG_PER_PIXEL |P_FLAG_QVAR, 0, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, NULL);
+  load_builtin_param_double("q6", (void*)&q6,  NULL, P_FLAG_PER_PIXEL |P_FLAG_QVAR, 0, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, NULL);
+  load_builtin_param_double("q7", (void*)&q7,  NULL, P_FLAG_PER_PIXEL |P_FLAG_QVAR, 0, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, NULL);
+  load_builtin_param_double("q8", (void*)&q8,  NULL, P_FLAG_PER_PIXEL |P_FLAG_QVAR, 0, MAX_DOUBLE_SIZE, -MAX_DOUBLE_SIZE, NULL);
+
+
+
+  /* variables added in 1.04 */
+  load_builtin_param_int("meshx", (void*)&gx, P_FLAG_READONLY, 32, 96, 8, NULL);
+  load_builtin_param_int("meshy", (void*)&gy, P_FLAG_READONLY, 24, 72, 6, NULL);
+
+  return SUCCESS;  
+  
+}
+
+/* Free's a parameter type */
+void free_param(param_t * param) {
+  int x;
+  if (param == NULL)
+       return;
+  
+  if (param->flags & P_FLAG_USERDEF) {
+    free(param->engine_val);
+
+  }
+
+  if (!(param->flags & P_FLAG_DONT_FREE_MATRIX)) {
+
+    if (param->flags & P_FLAG_PER_POINT)
+      free(param->matrix);
+
+    else if (param->flags & P_FLAG_PER_PIXEL) {
+       for(x = 0; x < gx; x++) 
+          free(((double**)param->matrix)[x]);
+       free(param->matrix);
+      }
+  }
+
+  if (PARAM_DEBUG) printf("free_param: freeing \"%s\".\n", param->name);
+  free(param);
+
+}
+
+/* Loads a double parameter into the builtin database */
+int load_builtin_param_double(char * name, void * engine_val, void * matrix, short int flags, 
+                                               double init_val, double upper_bound, double lower_bound, char * alt_name) {
+
+  param_t * param = NULL;
+  value_t iv, ub, lb;
+
+  iv.double_val = init_val;
+  ub.double_val = upper_bound;
+  lb.double_val = lower_bound;
+                                                       
+  /* Create new parameter of type double */
+  if (PARAM_DEBUG == 2) {
+         printf("load_builtin_param_double: (name \"%s\") (alt_name = \"%s\") ", name, alt_name);
+         fflush(stdout);
+  }  
+  
+ if ((param = create_param(name, P_TYPE_DOUBLE, flags, engine_val, matrix, iv, ub, lb)) == NULL) {
+    return OUTOFMEM_ERROR;
+  }
+  
+  if (PARAM_DEBUG == 2) {
+       printf("created...");
+       fflush(stdout);
+   }     
+   
+  /* Insert the paremeter into the database */
+
+  if (insert_builtin_param(param) < 0) {
+       free_param(param);
+    return ERROR;
+  }
+
+  if (PARAM_DEBUG == 2) {
+         printf("inserted...");
+         fflush(stdout);
+  }  
+  
+  /* If this parameter has an alternate name, insert it into the database as link */
+  
+  if (alt_name != NULL) {
+       insert_param_alt_name(param, alt_name); 
+
+  if (PARAM_DEBUG == 2) {
+         printf("alt_name inserted...");
+         fflush(stdout);
+       }
+  
+       
+  }      
+
+  if (PARAM_DEBUG == 2) printf("finished\n");    
+  /* Finished, return success */
+  return SUCCESS;
+}
+
+
+
+/* Loads a double parameter into the builtin database */
+param_t * new_param_double(char * name, short int flags, void * engine_val, void * matrix,
+                                               double upper_bound, double lower_bound, double init_val) {
+
+  param_t * param;
+  value_t iv, ub, lb;
+
+  iv.double_val = init_val;
+  ub.double_val = upper_bound;
+  lb.double_val = lower_bound;
+                                               
+  if ((param = create_param(name, P_TYPE_DOUBLE, flags, engine_val, matrix,iv, ub, lb)) == NULL) 
+    return NULL;
+  
+  
+  /* Finished, return success */
+  return param;
+}
+
+
+/* Creates a new parameter of type int */
+param_t * new_param_int(char * name, short int flags, void * engine_val,
+                                               int upper_bound, int lower_bound, int init_val) {
+
+  param_t * param;
+  value_t iv, ub, lb;
+
+  iv.int_val = init_val;
+  ub.int_val = upper_bound;
+  lb.int_val = lower_bound;
+                                                       
+  if ((param = create_param(name, P_TYPE_INT, flags, engine_val, NULL, iv, ub, lb)) == NULL) 
+    return NULL;
+  
+  /* Finished, return success */
+  return param;
+}
+
+/* Creates a new parameter of type bool */
+param_t * new_param_bool(char * name, short int flags, void * engine_val,
+                                               int upper_bound, int lower_bound, int init_val) {
+
+  param_t * param;
+  value_t iv, ub, lb;
+
+  iv.bool_val = init_val;
+  ub.bool_val = upper_bound;
+  lb.bool_val = lower_bound;
+                                                       
+  if ((param = create_param(name, P_TYPE_BOOL, flags, engine_val, NULL, iv, ub, lb)) == NULL)
+    return NULL;
+  
+  /* Finished, return success */
+  return param;
+}
+
+
+/* Loads a integer parameter into the builtin database */
+int load_builtin_param_int(char * name, void * engine_val, short int flags,
+                                               int init_val, int upper_bound, int lower_bound, char * alt_name) {
+
+  param_t * param;
+  value_t iv, ub, lb;
+
+  iv.int_val = init_val;
+  ub.int_val = upper_bound;
+  lb.int_val = lower_bound;    
+                                                       
+  param = create_param(name, P_TYPE_INT, flags, engine_val, NULL, iv, ub, lb);
+
+  if (param == NULL) {
+    return OUTOFMEM_ERROR;
+  }
+
+  if (insert_builtin_param(param) < 0) {
+       free_param(param);
+    return ERROR;
+  }
+  
+  if (alt_name != NULL) {
+       insert_param_alt_name(param, alt_name);          
+  }  
+  
+  return SUCCESS;
+
+}                                                      
+                                                       
+/* Loads a boolean parameter */
+int load_builtin_param_bool(char * name, void * engine_val, short int flags, 
+                                                               int init_val, char * alt_name) {
+
+  param_t * param;
+  value_t iv, ub, lb;
+
+  iv.int_val = init_val;
+  ub.int_val = TRUE;
+  lb.int_val = FALSE;  
+                                                                                                                               
+  param = create_param(name, P_TYPE_BOOL, flags, engine_val, NULL, iv, ub, lb);
+
+  if (param == NULL) {
+    return OUTOFMEM_ERROR;
+  }
+
+  if (insert_builtin_param(param) < 0) {
+       free_param(param);
+    return ERROR;
+  }
+  
+  if (alt_name != NULL) {
+       insert_param_alt_name(param, alt_name);          
+  }  
+  
+  return SUCCESS;
+
+}
+
+
+       
+
+/* Returns nonzero if the string is valid parameter name */
+int is_valid_param_string(char * string) {
+  
+  if (string == NULL)
+    return FALSE;
+  
+  /* This ensures the first character is non numeric */
+  if( ((*string) >= 48) && ((*string) <= 57))
+    return FALSE; 
+
+  /* These probably should never happen */
+  if (*string == '.')
+       return FALSE;
+  
+  if (*string == '+')
+       return FALSE;
+  
+  if (*string == '-')
+       return FALSE;
+  
+  /* Could also add checks for other symbols. May do later */
+  
+  return TRUE;
+   
+}
+
+/* Inserts a parameter into the builtin database */
+int insert_builtin_param(param_t * param) {
+
+       if (param == NULL)
+               return FAILURE;
+       
+       return splay_insert(param, param->name, builtin_param_tree);    
+}
+
+/* Inserts a parameter into the builtin database */
+int insert_param(param_t * param, splaytree_t * database) {
+
+       if (param == NULL)
+         return FAILURE;
+       if (database == NULL)
+         return FAILURE;
+
+       return splay_insert(param, param->name, database);      
+}
+
+
+/* Sets the parameter engine value to value val.
+       clipping occurs if necessary */
+void set_param(param_t * param, double val) {
+
+       switch (param->type) {
+               
+       case P_TYPE_BOOL:
+               if (val < 0)
+                       *((int*)param->engine_val) = 0;
+               else if (val > 0)
+                       *((int*)param->engine_val) = 1;
+               else
+                       *((int*)param->engine_val) = 0;
+               break;
+       case P_TYPE_INT:
+               /* Make sure value is an integer */
+               val = floor(val);
+               if (val < param->lower_bound.int_val)
+                               *((int*)param->engine_val) = param->lower_bound.int_val;
+               else if (val > param->upper_bound.int_val)
+                               *((int*)param->engine_val) = param->upper_bound.int_val;
+               else
+                               *((int*)param->engine_val) = val;
+               break;
+       case P_TYPE_DOUBLE:
+         /* Make sure value is an integer */   
+
+        
+         if (val < param->lower_bound.double_val) 
+           *((double*)param->engine_val) = param->lower_bound.double_val;        
+         else if (val > param->upper_bound.double_val)
+           *((double*)param->engine_val) = param->upper_bound.double_val;
+         else
+           *((double*)param->engine_val) = val;
+         break;
+       default:
+         break;
+
+       }
+       
+       return;
+}
+
+
+
+
+/* Search for parameter 'name' in 'database', if create_flag is true, then generate the parameter 
+   and insert it into 'database' */
+param_t * find_param_db(char * name, splaytree_t * database, int create_flag) {
+
+  param_t * param = NULL;
+
+  /* Null argument checks */
+  if (name == NULL)
+    return NULL;
+  if (database == NULL)
+    return NULL;
+  
+  /* First look in the builtin database */
+  param = (param_t *)splay_find(name, database);
+
+  
+  if (((param = (param_t *)splay_find(name, database)) == NULL) && (create_flag == TRUE)) {
+       
+       /* Check if string is valid */
+       if (!is_valid_param_string(name))
+               return NULL;
+       
+       /* Now, create the user defined parameter given the passed name */
+       if ((param = create_user_param(name)) == NULL)
+               return NULL;
+       
+       /* Finally, insert the new parameter into this preset's proper splaytree */
+       if (splay_insert(param, param->name, database) < 0) {
+               free_param(param);
+               return NULL;
+       }        
+       
+  }      
+  
+  /* Return the found (or created) parameter. Note that this could be null */
+  return param;
+
+}
+
diff --git a/modules/visualization/galaktos/param.h b/modules/visualization/galaktos/param.h
new file mode 100644 (file)
index 0000000..1fc6713
--- /dev/null
@@ -0,0 +1,36 @@
+#ifndef PARAM_H
+#define PARAM_H
+#include "preset_types.h"
+#include "splaytree_types.h"
+/* Debug level, zero for none */
+#define PARAM_DEBUG 0
+
+/* Used to store a number of decidable type */
+
+/* Function prototypes */
+param_t * create_param (char * name, short int type, short int flags, void * eqn_val, void * matrix,
+                                                       value_t default_init_val, value_t upper_bound, value_t lower_bound);
+param_t * create_user_param(char * name);
+int init_builtin_param_db();
+int init_user_param_db();
+int destroy_user_param_db();
+int destroy_builtin_param_db();
+void set_param(param_t * param, double val);
+int remove_param(param_t * param);
+param_t * find_param(char * name, struct PRESET_T * preset, int flags);
+void free_param(param_t * param);
+int load_all_builtin_param();
+int insert_param(param_t * param, splaytree_t * database);
+param_t * find_builtin_param(char * name);
+param_t * new_param_double(char * name, short int flags, void * engine_val, void * matrix,
+                       double upper_bound, double lower_bound, double init_val);
+
+param_t * new_param_int(char * name, short int flags, void * engine_val,
+                       int upper_bound, int lower_bound, int init_val);
+
+param_t * new_param_bool(char * name, short int flags, void * engine_val,
+                        int upper_bound, int lower_bound, int init_val);
+
+param_t * find_param_db(char * name, splaytree_t * database, int create_flag);
+
+#endif
diff --git a/modules/visualization/galaktos/param_types.h b/modules/visualization/galaktos/param_types.h
new file mode 100644 (file)
index 0000000..aae00cf
--- /dev/null
@@ -0,0 +1,39 @@
+#ifndef PARAM_TYPES_H
+#define PARAM_TYPES_H
+#include "expr_types.h"
+#define P_CREATE 1
+#define P_NONE 0
+
+#define P_TYPE_BOOL 0
+#define P_TYPE_INT 1
+#define P_TYPE_DOUBLE 2
+
+#define P_FLAG_NONE 0
+#define P_FLAG_READONLY 1
+#define P_FLAG_USERDEF (1 << 1)
+#define P_FLAG_QVAR (1 << 2)
+#define P_FLAG_TVAR (1 << 3)
+#define P_FLAG_ALWAYS_MATRIX (1 << 4)
+#define P_FLAG_DONT_FREE_MATRIX (1 << 5)
+#define P_FLAG_PER_PIXEL (1 << 6)
+#define P_FLAG_PER_POINT (1 << 7)
+
+typedef union VALUE_T {
+  int bool_val;
+  int int_val;
+  double double_val;   
+} value_t;
+
+/* Parameter Type */
+typedef struct PARAM_T {
+  char name[MAX_TOKEN_SIZE]; /* name of the parameter, not necessary but useful neverthless */
+  short int type; /* parameter number type (int, bool, or double) */   
+  short int flags; /* read, write, user defined, etc */        
+  short int matrix_flag; /* for optimization purposes */
+  void * engine_val; /* pointer to the engine variable */
+  void * matrix; /* per pixel / per point matrix for this variable */
+  value_t default_init_val; /* a default initial condition value */
+  value_t upper_bound; /* this parameter's upper bound */
+  value_t lower_bound; /* this parameter's lower bound */
+} param_t;
+#endif
diff --git a/modules/visualization/galaktos/parser.c b/modules/visualization/galaktos/parser.c
new file mode 100644 (file)
index 0000000..e79afbb
--- /dev/null
@@ -0,0 +1,2117 @@
+/*****************************************************************************
+ * parser.c:
+ *****************************************************************************
+ * Copyright (C) 2004 VideoLAN
+ * $Id$
+ *
+ * Authors: Cyril Deguet <asmax@videolan.org>
+ *          code from projectM http://xmms-projectm.sourceforge.net
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ *****************************************************************************/
+
+
+
+/* parser.c */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "common.h"
+#include "fatal.h"
+
+#include "splaytree_types.h"
+#include "splaytree.h"
+#include "tree_types.h"
+
+#include "expr_types.h"
+#include "eval.h"
+
+#include "param_types.h"
+#include "param.h"
+
+#include "func_types.h"
+#include "func.h"
+
+#include "preset_types.h"
+#include "builtin_funcs.h"
+
+#include "per_pixel_eqn_types.h"
+#include "per_pixel_eqn.h"
+
+#include "init_cond_types.h"
+#include "init_cond.h"
+
+#include "per_frame_eqn_types.h"
+#include "per_frame_eqn.h"
+
+#include "parser.h"
+#include "engine_vars.h"
+
+#include "custom_wave_types.h"
+#include "custom_wave.h"
+
+#include "custom_shape_types.h"
+#include "custom_shape.h"
+
+/* Strings that prefix (and denote the type of) equations */
+
+
+#define PER_FRAME_STRING "per_frame_"
+#define PER_FRAME_STRING_LENGTH 10
+
+#define PER_PIXEL_STRING "per_pixel_"
+#define PER_PIXEL_STRING_LENGTH 10
+
+#define PER_FRAME_INIT_STRING "per_frame_init_"
+#define PER_FRAME_INIT_STRING_LENGTH 15
+
+#define WAVECODE_STRING "wavecode_"
+#define WAVECODE_STRING_LENGTH 9
+
+#define WAVE_STRING "wave_"
+#define WAVE_STRING_LENGTH 5
+
+#define PER_POINT_STRING "per_point"
+#define PER_POINT_STRING_LENGTH 9
+
+#define PER_FRAME_STRING_NO_UNDERSCORE "per_frame"
+#define PER_FRAME_STRING_NO_UNDERSCORE_LENGTH 9
+
+#define SHAPECODE_STRING "shapecode_"
+#define SHAPECODE_STRING_LENGTH 10
+
+#define SHAPE_STRING "shape_"
+#define SHAPE_STRING_LENGTH 6
+
+#define SHAPE_INIT_STRING "init"
+#define SHAPE_INIT_STRING_LENGTH 4
+
+#define WAVE_INIT_STRING "init"
+#define WAVE_INIT_STRING_LENGTH 4
+
+/* Stores a line of a file as its being parsed */
+char string_line_buffer[STRING_LINE_SIZE]; 
+
+/* The current position of the string line buffer (see above) */
+int string_line_buffer_index = 0;
+
+/* All infix operators (except '=') are prototyped here */
+extern infix_op_t * infix_add, * infix_minus, * infix_div, * infix_mult,
+  * infix_or, * infix_and, * infix_mod, * infix_positive, * infix_negative;
+
+/* If the parser reads a line with a custom wave, this pointer is set to
+   the custom wave of concern */
+custom_wave_t * current_wave = NULL;
+custom_shape_t * current_shape = NULL;
+/* Counts the number of lines parsed */
+unsigned int line_count = 1;
+int per_frame_eqn_count  = 0;
+int per_frame_init_eqn_count = 0;
+
+typedef enum {
+  NORMAL_LINE_MODE,
+  PER_FRAME_LINE_MODE,
+  PER_PIXEL_LINE_MODE,
+  INIT_COND_LINE_MODE,
+  CUSTOM_WAVE_PER_POINT_LINE_MODE,
+  CUSTOM_WAVE_PER_FRAME_LINE_MODE,
+  CUSTOM_WAVE_WAVECODE_LINE_MODE,
+  CUSTOM_SHAPE_SHAPECODE_LINE_MODE,
+} line_mode_t;
+
+line_mode_t line_mode = NORMAL_LINE_MODE;
+
+/* Token enumeration type */
+typedef enum {
+
+  tEOL,   /* end of a line, usually a '/n' or '/r' */
+  tEOF,   /* end of file */
+  tLPr,   /* ( */
+  tRPr,   /* ) */
+  tLBr,   /* [ */
+  tRBr,   /* ] */
+  tEq,    /* = */
+  tPlus,  /* + */
+  tMinus, /* - */
+  tMult,  /* * */
+  tMod,   /* % */
+  tDiv,   /* / */
+  tOr,    /* | */
+  tAnd,   /* & */
+  tComma, /* , */
+  tPositive, /* + as a prefix operator */
+  tNegative, /* - as a prefix operator */
+  tSemiColon, /* ; */
+  tStringTooLong, /* special token to indicate an invalid string length */
+  tStringBufferFilled /* the string buffer for this line is maxed out */
+} token_t;
+
+
+int get_string_prefix_len(char * string);
+tree_expr_t * insert_gen_expr(gen_expr_t * gen_expr, tree_expr_t ** root);
+tree_expr_t * insert_infix_op(infix_op_t * infix_op, tree_expr_t ** root);
+token_t parseToken(FILE * fs, char * string);
+gen_expr_t ** parse_prefix_args(FILE * fs, int num_args, struct PRESET_T * preset);
+gen_expr_t * parse_infix_op(FILE * fs, token_t token, tree_expr_t * tree_expr, struct PRESET_T * preset);
+gen_expr_t * parse_sign_arg(FILE * fs);
+int parse_float(FILE * fs, double * float_ptr);
+int parse_int(FILE * fs, int * int_ptr);
+int insert_gen_rec(gen_expr_t * gen_expr, tree_expr_t * root);
+int insert_infix_rec(infix_op_t * infix_op, tree_expr_t * root);
+gen_expr_t * parse_gen_expr(FILE * fs, tree_expr_t * tree_expr, struct PRESET_T * preset);
+per_frame_eqn_t * parse_implicit_per_frame_eqn(FILE * fs, char * param_string, int index, struct PRESET_T * preset);
+init_cond_t * parse_per_frame_init_eqn(FILE * fs, struct PRESET_T * preset, splaytree_t * database);
+int parse_wavecode_prefix(char * token, int * id, char ** var_string);
+int parse_wavecode(char * token, FILE * fs, preset_t * preset);
+int parse_wave_prefix(char * token, int * id, char ** eqn_string);
+
+int parse_shapecode(char * eqn_string, FILE * fs, preset_t * preset);
+int parse_shapecode_prefix(char * token, int * id, char ** var_string);
+
+int parse_wave(char * eqn_string, FILE * fs, preset_t * preset);
+int parse_shape(char * eqn_string, FILE * fs, preset_t * preset);
+int parse_shape_prefix(char * token, int * id, char ** eqn_string);
+
+int update_string_buffer(char * buffer, int * index);
+int string_to_float(char * string, double * float_ptr);
+
+/* Grabs the next token from the file. The second argument points
+   to the raw string */
+
+token_t parseToken(FILE * fs, char * string) {
+  
+  char c;
+  int i;
+  
+  if (string != NULL)
+    memset(string, 0, MAX_TOKEN_SIZE);
+  
+  /* Loop until a delimiter is found, or the maximum string size is found */
+  for (i = 0; i < MAX_TOKEN_SIZE;i++) {
+    c = fgetc(fs);
+    
+    /* If the string line buffer is full, quit */
+    if (string_line_buffer_index == (STRING_LINE_SIZE - 1))
+      return tStringBufferFilled;
+    
+    /* Otherwise add this character to the string line buffer */
+    string_line_buffer[string_line_buffer_index++] = c;
+    /* Now interpret the character */
+    switch (c) {
+      
+    case '+':
+      return tPlus; 
+    case '-':
+      return tMinus;
+    case '%':
+      return tMod;
+    case '/':
+      
+      /* check for line comment here */
+      if ((c = fgetc(fs)) == '/') {
+       while(1) {
+         c = fgetc(fs);
+         if (c == EOF) {
+           line_mode = NORMAL_LINE_MODE;
+           return tEOF;                                
+         }
+         if (c == '\n') {
+           line_mode = NORMAL_LINE_MODE;
+           return tEOL;
+         }
+       }
+       
+      }
+      
+      /* Otherwise, just a regular division operator */
+      ungetc(c, fs);
+      return tDiv;
+      
+    case '*':
+      return tMult;
+    case '|':
+      return tOr;
+    case '&':
+      return tAnd;
+    case '(': 
+      return tLPr;
+    case ')':
+      return tRPr;
+    case '[': 
+      return tLBr;
+    case ']':
+      return tRBr;
+    case '=': 
+      return tEq;
+      //    case '\r':
+      //break;
+    case '\n':
+      line_count++;
+      line_mode = NORMAL_LINE_MODE;
+      return tEOL;
+    case ',':
+      return tComma;
+    case ';':
+      return tSemiColon;
+    case ' ': /* space, skip the character */
+      i--;
+      break;
+    case EOF:
+      line_count = 1;
+      line_mode = NORMAL_LINE_MODE;
+      return tEOF;
+      
+    default: 
+      if (string != NULL)
+       string[i] = c;
+    } 
+    
+  }
+  
+ /* String reached maximum length, return special token error */ 
+  return tStringTooLong;
+  
+}
+
+/* Parse input in the form of "exp, exp, exp, ...)" 
+   Returns a general expression list */
+
+gen_expr_t ** parse_prefix_args(FILE * fs, int num_args, struct PRESET_T * preset) {
+
+  int i, j;
+  gen_expr_t ** expr_list; /* List of arguments to function */
+  gen_expr_t * gen_expr;
+  
+  /* Malloc the expression list */
+  expr_list =  (gen_expr_t**)malloc(sizeof(gen_expr_t*)*num_args);
+  
+  /* Malloc failed */
+  if (expr_list == NULL)
+    return NULL;
+  
+  
+  i = 0;
+
+  while (i < num_args) {
+    //if (PARSE_DEBUG) printf("parse_prefix_args: parsing argument %d...\n", i+1);
+    /* Parse the ith expression in the list */
+    if ((gen_expr = parse_gen_expr(fs, NULL, preset)) == NULL) {
+      //if (PARSE_DEBUG) printf("parse_prefix_args: failed to get parameter # %d for function (LINE %d)\n", i+1, line_count);
+      for (j = 0; j < i; j++) 
+       free_gen_expr(expr_list[j]);
+      free(expr_list);
+      return NULL;
+    }
+    /* Assign entry in expression list */
+    expr_list[i++] = gen_expr;
+  }
+  
+  //if (PARSE_DEBUG) printf("parse_prefix_args: finished parsing %d arguments (LINE %d)\n", num_args, line_count);     
+  /* Finally, return the resulting expression list */
+  return expr_list;
+  
+}
+
+/* Parses a comment at the top of the file. Stops when left bracket is found */
+int parse_top_comment(FILE * fs) {
+
+  char string[MAX_TOKEN_SIZE];
+  token_t token;
+         
+  /* Process tokens until left bracket is found */
+  while ((token = parseToken(fs, string)) != tLBr) {
+    if (token == tEOF) 
+      return PARSE_ERROR;
+  }
+
+ /* Done, return success */
+ return SUCCESS; 
+}      
+
+/* Right Bracket is parsed by this function.
+   puts a new string into name */
+int parse_preset_name(FILE * fs, char * name) {
+
+  token_t token;
+
+  if (name == NULL)
+       return FAILURE;
+
+  if ((token = parseToken(fs, name)) != tRBr)
+    return PARSE_ERROR;
+       
+  //if (PARSE_DEBUG) printf("parse_preset_name: parsed preset (name = \"%s\")\n", name);
+  
+  return SUCCESS;
+}
+
+
+/* Parses per pixel equations */
+int parse_per_pixel_eqn(FILE * fs, preset_t * preset) {
+
+
+  char string[MAX_TOKEN_SIZE];
+  gen_expr_t * gen_expr;
+
+  if (PARSE_DEBUG) printf("parse_per_pixel: per_pixel equation parsing start...(LINE %d)\n", line_count);
+
+  if (parseToken(fs, string) != tEq) { /* parse per pixel operator  name */
+    if (PARSE_DEBUG) printf("parse_per_pixel: equal operator expected after per pixel operator \"%s\", but not found (LINE %d)\n", 
+                           string, line_count);
+    return PARSE_ERROR;
+  }
+  
+  /* Parse right side of equation as an expression */
+  if ((gen_expr = parse_gen_expr(fs, NULL, preset)) == NULL) {
+    if (PARSE_DEBUG) printf("parse_per_pixel: equation evaluated to null? (LINE %d)\n", line_count);
+    return PARSE_ERROR;
+  }
+  
+  /* Add the per pixel equation */
+  if (add_per_pixel_eqn(string, gen_expr, preset) < 0) {
+    free_gen_expr(gen_expr);
+    return PARSE_ERROR;
+  }
+
+  return SUCCESS;
+}
+
+/* Parses an equation line, this function is way too big, should add some helper functions */
+int parse_line(FILE * fs, struct PRESET_T * preset) {
+
+  char eqn_string[MAX_TOKEN_SIZE];
+  token_t token;
+  init_cond_t * init_cond;
+  per_frame_eqn_t * per_frame_eqn;
+  
+  /* Clear the string line buffer */
+  memset(string_line_buffer, 0, STRING_LINE_SIZE);
+  string_line_buffer_index = 0;
+  
+  
+  switch (token = parseToken(fs, eqn_string)) {
+    
+    /* Invalid Cases */
+  case tRBr:
+  case tLPr:
+  case tRPr:
+  case tComma:
+  case tLBr:
+  case tPlus:
+  case tMinus:
+  case tMod:
+  case tMult:
+  case tOr:
+  case tAnd:
+  case tDiv:
+    
+    //    if (PARSE_DEBUG) printf("parse_line: invalid token found at start of line (LINE %d)\n", line_count);
+    /* Invalid token found, return a parse error */
+    return PARSE_ERROR;
+    
+    
+  case tEOL:  /* Empty line */
+    line_mode = NORMAL_LINE_MODE;
+    return SUCCESS;
+    
+  case tEOF: /* End of File */
+    line_mode = NORMAL_LINE_MODE;
+    line_count = 1;
+    return EOF;
+    
+  case tSemiColon: /* Indicates end of expression */
+    return SUCCESS;
+    
+    /* Valid Case, either an initial condition or equation should follow */
+  case tEq:
+    
+    /* CASE: PER FRAME INIT EQUATION */            
+    if (!strncmp(eqn_string, PER_FRAME_INIT_STRING, PER_FRAME_INIT_STRING_LENGTH)) {
+      
+      //if (PARSE_DEBUG) printf("parse_line: per frame init equation found...(LINE %d)\n", line_count);
+      
+      /* Set the line mode to normal */
+      line_mode = NORMAL_LINE_MODE;
+      
+      /* Parse the per frame equation */
+      if ((init_cond = parse_per_frame_init_eqn(fs, preset, NULL)) == NULL) {
+       //if (PARSE_DEBUG) printf("parse_line: per frame init equation parsing failed (LINE %d)\n", line_count);
+       return PARSE_ERROR;
+      }        
+      
+      /* Insert the equation in the per frame equation tree */
+      if (splay_insert(init_cond, init_cond->param->name, preset->per_frame_init_eqn_tree) < 0) {
+       //if (PARSE_DEBUG) printf("parse_line: failed to add a perframe equation (ERROR)\n");
+       free_init_cond(init_cond); /* will free the gen expr too */             
+       return ERROR;
+      }
+      
+     
+      if (update_string_buffer(preset->per_frame_init_eqn_string_buffer, 
+                              &preset->per_frame_init_eqn_string_index) < 0)
+       {       return FAILURE;}
+      
+      return SUCCESS;
+      
+    }
+
+    /* Per frame equation case */          
+    if (!strncmp(eqn_string, PER_FRAME_STRING, PER_FRAME_STRING_LENGTH)) {
+      
+      /* Sometimes per frame equations are implicitly defined without the
+        per_frame_ prefix. This informs the parser that one could follow */
+      line_mode = PER_FRAME_LINE_MODE;
+      
+      //if (PARSE_DEBUG) printf("parse_line: per frame equation found...(LINE %d)\n", line_count);
+      
+      /* Parse the per frame equation */
+      if ((per_frame_eqn = parse_per_frame_eqn(fs, ++per_frame_eqn_count, preset)) == NULL) {
+       if (PARSE_DEBUG) printf("parse_line: per frame equation parsing failed (LINE %d)\n", line_count);
+       return PARSE_ERROR;
+      }        
+      
+      /* Insert the equation in the per frame equation tree */
+      if (splay_insert(per_frame_eqn, &per_frame_eqn_count, preset->per_frame_eqn_tree) < 0) {
+       if (PARSE_DEBUG) printf("parse_line: failed to add a perframe equation (ERROR)\n");
+       free_per_frame_eqn(per_frame_eqn); /* will free the gen expr too */             
+       return ERROR;
+      }
+    
+      if (update_string_buffer(preset->per_frame_eqn_string_buffer, 
+                              &preset->per_frame_eqn_string_index) < 0)
+       return FAILURE;
+      
+      
+      
+      return SUCCESS;
+      
+    }
+    
+    /* Wavecode initial condition case */
+    if (!strncmp(eqn_string, WAVECODE_STRING, WAVECODE_STRING_LENGTH)) {
+      
+          line_mode = CUSTOM_WAVE_WAVECODE_LINE_MODE;
+
+      //if (PARSE_DEBUG) 
+      //      printf("parse_line: wavecode prefix found: \"%s\"\n", eqn_string);
+
+         //      printf("string:%d\n", 5);
+
+         //SUPER MYSTERIO-BUG - Don't Remove
+         printf("");
+         
+      return parse_wavecode(eqn_string, fs, preset);
+    }
+    
+    /* Custom Wave Prefix */
+    if ((!strncmp(eqn_string, WAVE_STRING, WAVE_STRING_LENGTH)) && 
+       ((eqn_string[5] >= 48) && (eqn_string[5] <= 57))) {
+      
+      //    if (PARSE_DEBUG) printf("parse_line wave prefix found: \"%s\"\n", eqn_string);
+      
+      return parse_wave(eqn_string, fs, preset);
+      
+    }
+    
+    
+    /* Shapecode initial condition case */
+    if (!strncmp(eqn_string, SHAPECODE_STRING, SHAPECODE_STRING_LENGTH)) {
+      
+      line_mode = CUSTOM_SHAPE_SHAPECODE_LINE_MODE;
+      
+      if (PARSE_DEBUG) printf("parse_line: shapecode prefix found: \"%s\"\n", eqn_string);
+      
+      return parse_shapecode(eqn_string, fs, preset);
+    }
+    
+    /* Custom Shape Prefix */
+    if ((!strncmp(eqn_string, SHAPE_STRING, SHAPE_STRING_LENGTH)) && 
+       ((eqn_string[6] >= 48) && (eqn_string[6] <= 57))) {
+      
+      if (PARSE_DEBUG) printf("parse_line shape prefix found: \"%s\"\n", eqn_string);
+      return parse_shape(eqn_string, fs, preset);
+      
+    }
+    
+    /* Per pixel equation case */
+    if (!strncmp(eqn_string, PER_PIXEL_STRING, PER_PIXEL_STRING_LENGTH)) {
+      line_mode = PER_PIXEL_LINE_MODE;
+      
+      if (parse_per_pixel_eqn(fs, preset) < 0)
+       return PARSE_ERROR;
+      
+      
+      if (update_string_buffer(preset->per_pixel_eqn_string_buffer, 
+                              &preset->per_pixel_eqn_string_index) < 0)
+       return FAILURE;
+      
+      if (PARSE_DEBUG) printf("parse_line: finished parsing per pixel equation (LINE %d)\n", line_count);
+      return SUCCESS;
+    } 
+    
+    /* Sometimes equations are written implicitly in milkdrop files, in the form
+       
+    per_frame_1 = p1 = eqn1; p2 = eqn2; p3 = eqn3;..; 
+    
+    which is analagous to:
+    
+    per_frame_1 = p1 = eqn1; per_frame_2 = p2 = eqn2; per_frame_3 = p3 = eqn3; ...;
+    
+    The following line mode hack allows such implicit declaration of the 
+    prefix that specifies the equation type. An alternative method
+    may be to associate each equation line as list of equations separated
+    by semicolons (and a new line ends the list). Instead, however, a global
+    variable called "line_mode" specifies the last type of equation found,
+    and bases any implicitly typed input on this fact
+    
+    Note added by Carmelo Piccione (cep@andrew.cmu.edu) 10/19/03
+    */
+    
+    /* Per frame line mode previously, try to parse the equation implicitly */
+    if (line_mode == PER_FRAME_LINE_MODE) {
+      if ((per_frame_eqn = parse_implicit_per_frame_eqn(fs, eqn_string, ++per_frame_eqn_count, preset)) == NULL)
+       return PARSE_ERROR;
+      
+      /* Insert the equation in the per frame equation tree */
+      if (splay_insert(per_frame_eqn, &per_frame_eqn_count, preset->per_frame_eqn_tree) < 0) {
+       if (PARSE_DEBUG) printf("parse_line: failed to add a perframe equation (ERROR)\n");
+       free_per_frame_eqn(per_frame_eqn); /* will free the gen expr too */             
+       return ERROR;
+      }
+      
+      
+      if (update_string_buffer(preset->per_frame_eqn_string_buffer, 
+                              &preset->per_frame_eqn_string_index) < 0)
+       return FAILURE;
+      
+      
+      
+      return SUCCESS;
+    }
+    
+    //if (PARSE_DEBUG) printf("parse_line: found initial condition: name = \"%s\" (LINE %d)\n", eqn_string, line_count);
+    
+    /* Evaluate the initial condition */
+    if ((init_cond = parse_init_cond(fs, eqn_string, preset)) == NULL) {
+       if (PARSE_DEBUG) printf("parse_line: failed to parse initial condition (LINE %d)\n", line_count);
+      return PARSE_ERROR; 
+    }  
+    
+    /* Add equation to initial condition tree */
+    if (splay_insert(init_cond, init_cond->param->name, preset->init_cond_tree) < 0) {
+      if (PARSE_DEBUG) printf("parse_line: failed to add initial condition \"%s\" to equation tree (LINE %d)\n", 
+                     init_cond->param->name, line_count);
+      free_init_cond(init_cond);
+      return FAILURE;
+    }
+    
+    /* Finished with initial condition line */
+    //    if (PARSE_DEBUG) printf("parse_line: initial condition parsed successfully\n");
+    
+    return SUCCESS;
+    
+    /* END INITIAL CONDITIONING PARSING */
+    
+    
+  default: /* an uncaught type or an error has occurred */
+    if (PARSE_DEBUG) printf("parse_line: uncaught case, token val = %d\n", token); 
+    return PARSE_ERROR;
+  }
+  
+  /* Because of the default in the case statement, 
+     control flow should never actually reach here */ 
+  return PARSE_ERROR;
+}
+
+
+
+/* Parses a general expression, this function is the meat of the parser */
+gen_expr_t * parse_gen_expr (FILE * fs, tree_expr_t * tree_expr, struct PRESET_T * preset) {
+  
+  int i;
+  char string[MAX_TOKEN_SIZE];
+  token_t token;
+  gen_expr_t * gen_expr;
+  double val;
+  param_t * param = NULL;
+  func_t * func;
+  gen_expr_t ** expr_list;
+
+  switch (token = parseToken(fs,string)) {
+  /* Left Parentice Case */
+  case tLPr:
+    
+    /* CASE 1 (Left Parentice): See if the previous string before this parentice is a function name */
+    if ((func = find_func(string)) != NULL) {
+        if (PARSE_DEBUG) printf("parse_gen_expr: found prefix function (name = %s) (LINE %d)\n", func->name, line_count);
+      
+      /* Parse the functions arguments */
+      if ((expr_list = parse_prefix_args(fs, func->num_args, preset)) == NULL) {
+       if (PARSE_DEBUG) printf("parse_prefix_args: failed to generate an expresion list! (LINE %d) \n", line_count);
+       free_tree_expr(tree_expr);
+       return NULL;
+      }
+      
+      /* Convert function to expression */
+      if ((gen_expr = prefun_to_expr((void*)func->func_ptr, expr_list, func->num_args)) == NULL)  {    
+         if (PARSE_DEBUG) printf("parse_prefix_args: failed to convert prefix function to general expression (LINE %d) \n", 
+                                       line_count);
+       free_tree_expr(tree_expr);
+       for (i = 0; i < func->num_args;i++)
+         free_gen_expr(expr_list[i]);
+       free(expr_list);
+       return NULL;
+      }
+    
+      
+      
+      token = parseToken(fs, string);
+
+      if (*string != 0) {
+       if (PARSE_DEBUG) printf("parse_prefix_args: empty string expected, but not found...(LINE %d)\n", line_count);
+       /* continue anyway for now, could be implicit multiplication */                         
+      }                
+      
+      return parse_infix_op(fs, token, insert_gen_expr(gen_expr, &tree_expr), preset);
+    }
+     
+    
+    /* Case 2: (Left Parentice), a string coupled with a left parentice. Either an error or implicit 
+       multiplication operator. For now treat it as an error */
+    if (*string != 0) {
+      if (PARSE_DEBUG) printf("parse_gen_expr: implicit multiplication case unimplemented!\n");
+      free_tree_expr(tree_expr);
+      return NULL;
+    }
+    
+    /* CASE 3 (Left Parentice): the following is enclosed parentices to change order
+       of operations. So we create a new expression tree */
+    
+    if ((gen_expr = parse_gen_expr(fs, NULL, preset)) == NULL) {
+      //if (PARSE_DEBUG) printf("parse_gen_expr:  found left parentice, but failed to create new expression tree \n");
+      free_tree_expr(tree_expr);
+      return NULL;
+    }
+    
+    if (PARSE_DEBUG) printf("parse_gen_expr: finished enclosed expression tree...\n"); 
+    token = parseToken(fs, string);
+    return parse_infix_op(fs, token, insert_gen_expr(gen_expr, &tree_expr), preset);
+
+    /* Plus is a prefix operator check */
+  case tPlus:
+    if (*string == 0) {
+      
+      //if (PARSE_DEBUG) printf("parse_gen_expr: plus used as prefix (LINE %d)\n", line_count);
+
+         /* Treat prefix plus as implict 0 preceding operator */
+      gen_expr = const_to_expr(0);
+
+      return parse_infix_op(fs, tPositive, insert_gen_expr(gen_expr, &tree_expr), preset);     
+    }
+    
+    /* Minus is a prefix operator check */
+  case tMinus:
+    if (*string == 0) {
+     
+      /* Use the negative infix operator, but first add an implicit zero to the operator tree */
+      gen_expr = const_to_expr(0);
+      //return parse_gen_expr(fs, insert_gen_expr(gen_expr, &tree_expr), preset);
+               return parse_infix_op(fs, tNegative, insert_gen_expr(gen_expr, &tree_expr), preset);
+    }
+    
+    /* All the following cases are strings followed by an infix operator or terminal */
+  case tRPr:
+  case tEOL: 
+  case tEOF:
+  case tSemiColon:
+  case tComma:
+    
+    /* CASE 1 (terminal): string is empty, but not null. Not sure if this will actually happen
+       any more. */
+    if (*string == 0) {
+      //if (PARSE_DEBUG) printf("parse_gen_expr: empty string coupled with terminal (LINE %d) \n", line_count);
+      return parse_infix_op(fs, token, tree_expr, preset);
+      
+    }
+    
+  default:  
+
+    /* CASE 0: Empty string, parse error */
+    if (*string == 0) {
+      if (PARSE_DEBUG) printf("parse_gen_expr: empty string coupled with infix op (ERROR!) (LINE %d) \n", line_count);
+      free_tree_expr(tree_expr);
+      return NULL;
+    }
+
+    /* CASE 1: Check if string is a just a floating point number */
+    if (string_to_float(string, &val) != PARSE_ERROR) {
+      if ((gen_expr = const_to_expr(val)) == NULL) {
+       free_tree_expr(tree_expr);
+       return NULL;
+      }
+      
+      /* Parse the rest of the line */
+      return parse_infix_op(fs, token, insert_gen_expr(gen_expr, &tree_expr), preset);          
+    
+    }
+
+      
+    /* CASE 4: custom shape variable */
+    if (current_shape != NULL) {
+      if ((param = find_param_db(string, current_shape->param_tree, FALSE)) == NULL) {
+       if ((param = find_builtin_param(string)) == NULL)
+         if ((param = find_param_db(string, current_shape->param_tree, TRUE)) == NULL) {
+           free_tree_expr(tree_expr);
+           return NULL;
+         }
+      }
+      
+      if (PARSE_DEBUG) {
+       printf("parse_gen_expr: custom shape parameter (name = %s)... ", param->name);
+       fflush(stdout);
+      }  
+      
+      /* Convert parameter to an expression */
+      if ((gen_expr = param_to_expr(param)) == NULL) {
+       free_tree_expr(tree_expr);
+       return NULL;
+      }
+      
+      //if (PARSE_DEBUG) printf("converted to expression (LINE %d)\n", line_count);
+      
+      /* Parse the rest of the line */
+      return parse_infix_op(fs, token, insert_gen_expr(gen_expr, &tree_expr), preset);
+    }
+    
+    /* CASE 5: custom wave variable */
+    if (current_wave != NULL) {
+      if ((param = find_param_db(string, current_wave->param_tree, FALSE)) == NULL) {
+       if ((param = find_builtin_param(string)) == NULL) 
+         if ((param = find_param_db(string, current_wave->param_tree, TRUE)) == NULL) {
+           free_tree_expr(tree_expr);
+           return NULL;
+         }
+        
+      }
+
+      if (PARSE_DEBUG) {
+       printf("parse_gen_expr: custom wave parameter (name = %s)... ", param->name);
+       fflush(stdout);
+      }
+       
+       /* Convert parameter to an expression */
+       if ((gen_expr = param_to_expr(param)) == NULL) {
+         free_tree_expr(tree_expr);
+         return NULL;
+       }
+       
+       if (PARSE_DEBUG) printf("converted to expression (LINE %d)\n", line_count);
+       
+       /* Parse the rest of the line */
+       return parse_infix_op(fs, token, insert_gen_expr(gen_expr, &tree_expr), preset);
+      
+    }
+
+    /* CASE 6: regular parameter. Will be created if necessary and the string has no invalid characters */
+    if ((param = find_param(string, preset, P_CREATE)) != NULL) {
+      
+      if (PARSE_DEBUG) {
+       printf("parse_gen_expr: parameter (name = %s)... ", param->name);
+       fflush(stdout);
+      }  
+    
+               /* Convert parameter to an expression */
+      if ((gen_expr = param_to_expr(param)) == NULL) {
+       free_tree_expr(tree_expr);
+       return NULL;
+      }
+      
+      if (PARSE_DEBUG) printf("converted to expression (LINE %d)\n", line_count);
+      
+      /* Parse the rest of the line */
+      return parse_infix_op(fs, token, insert_gen_expr(gen_expr, &tree_expr), preset);
+          
+    }
+   
+    /* CASE 7: Bad string, give up */
+    if (PARSE_DEBUG) printf("parse_gen_expr: syntax error [string = \"%s\"] (LINE %d)\n", string, line_count);
+    free_tree_expr(tree_expr);
+    return NULL;
+  }
+}
+  
+
+
+/* Inserts expressions into tree according to operator precedence.
+   If root is null, a new tree is created, with gen_expr as only element */
+
+tree_expr_t * insert_infix_op(infix_op_t * infix_op, tree_expr_t **root) {
+
+  tree_expr_t * new_root;
+  
+  /* Sanity check */
+  if (infix_op == NULL)
+    return NULL;
+  
+  /* The root is null, so make this operator
+     the new root */
+  
+  if (*root == NULL) {
+    new_root = new_tree_expr(infix_op, NULL, NULL, NULL);
+    *root = new_root;
+    return new_root;           
+  }
+  
+  /* The root node is not an infix function,
+     so we make this infix operator the new root  */ 
+  
+  if ((*root)->infix_op == NULL) {
+    new_root = new_tree_expr(infix_op, NULL, *root, NULL);
+    (*root) = new_root;
+    return new_root;
+  }
+  
+  /* The root is an infix function. If the precedence
+     of the item to be inserted is greater than the root's
+     precedence, then make gen_expr the root */
+  
+  if (infix_op->precedence > (*root)->infix_op->precedence) {
+    new_root = new_tree_expr(infix_op, NULL, *root, NULL);
+    (*root) = new_root;
+      return new_root;
+  }
+  
+  /* If control flow reaches here, use a recursive helper
+     with the knowledge that the root is higher precedence
+     than the item to be inserted */
+  
+  insert_infix_rec(infix_op, *root);
+  return *root;
+  
+}
+
+
+tree_expr_t * insert_gen_expr(gen_expr_t * gen_expr, tree_expr_t ** root) {
+
+  tree_expr_t * new_root;
+  
+  /* If someone foolishly passes a null
+     pointer to insert, return the original tree */
+  
+  if (gen_expr == NULL) {
+    return *root;
+  }
+
+  /* If the root is null, generate a new expression tree,
+     using the passed expression as the root element */
+  
+  if (*root == NULL) {
+    new_root = new_tree_expr(NULL, gen_expr, NULL, NULL);
+    *root = new_root;
+    return new_root;
+  }
+  
+  
+  /* Otherwise. the new element definitely will not replace the current root.
+     Use a recursive helper function to do insertion */
+
+  insert_gen_rec(gen_expr, *root);
+  return *root;
+}
+
+/* A recursive helper function to insert general expression elements into the operator tree */
+int insert_gen_rec(gen_expr_t * gen_expr, tree_expr_t * root) {
+  
+  /* Trivial Case: root is null */
+  
+  if (root == NULL) {
+    ////if (PARSE_DEBUG) printf("insert_gen_rec: root is null, returning failure\n");
+    return FAILURE;
+  }
+  
+  
+  /* The current node's left pointer is null, and this
+     current node is an infix operator, so insert the
+     general expression at the left pointer */
+  
+  if ((root->left == NULL) && (root->infix_op != NULL)) {
+    root->left = new_tree_expr(NULL, gen_expr, NULL, NULL);
+    return SUCCESS;
+  }
+  
+  /* The current node's right pointer is null, and this
+     current node is an infix operator, so insert the
+     general expression at the right pointer */
+  
+  if ((root->right == NULL) && (root->infix_op != NULL)) {
+    root->right = new_tree_expr(NULL, gen_expr, NULL, NULL);
+    return SUCCESS;
+  }
+  
+  /* Otherwise recurse down to the left. If
+     this succeeds then return. If it fails, try
+     recursing down to the right */
+  
+  if (insert_gen_rec(gen_expr, root->left) == FAILURE) 
+    return insert_gen_rec(gen_expr, root->right);
+
+  /* Impossible for control flow to reach here, but in
+     the world of C programming, who knows... */
+  //if (PARSE_DEBUG) printf("insert_gen_rec: should never reach here!\n");  
+  return FAILURE;      
+}      
+
+
+/* A recursive helper function to insert infix arguments by operator precedence */
+int insert_infix_rec(infix_op_t * infix_op, tree_expr_t * root) {
+
+  /* Shouldn't happen, implies a parse error */
+
+  if (root == NULL)
+    return FAILURE;
+  
+  /* Also shouldn't happen, also implies a (different) parse error */
+
+  if (root->infix_op == NULL)
+    return FAILURE;
+
+  /* Left tree is empty, attach this operator to it. 
+     I don't think this will ever happen */
+  if (root->left == NULL) {
+    root->left = new_tree_expr(infix_op, NULL, root->left, NULL);
+    return SUCCESS;
+  }
+  /* Right tree is empty, attach this operator to it */
+  if (root->right == NULL) {
+    root->right = new_tree_expr(infix_op, NULL, root->right, NULL);
+    return SUCCESS;
+  }
+
+  /* The left element can now be ignored, since there is no way for this
+     operator to use those expressions */
+
+  /* If the right element is not an infix operator,
+     then insert the expression here, attaching the old right branch
+     to the left of the new expression */
+
+  if (root->right->infix_op == NULL) {
+    root->right = new_tree_expr(infix_op, NULL, root->right, NULL);
+    return SUCCESS;
+  }
+  
+  /* Traverse deeper if the inserting operator precedence is less than the
+     the root's right operator precedence */
+  if (infix_op->precedence < root->right->infix_op->precedence) 
+    return insert_infix_rec(infix_op, root->right);
+
+  /* Otherwise, insert the operator here */
+  
+  root->right = new_tree_expr(infix_op, NULL, root->right, NULL);
+  return SUCCESS;
+
+}
+
+/* Parses an infix operator */
+gen_expr_t * parse_infix_op(FILE * fs, token_t token, tree_expr_t * tree_expr, struct PRESET_T * preset) {
+       
+  gen_expr_t * gen_expr;
+
+  switch (token) {
+       /* All the infix operators */
+  case tPlus:
+    //if (PARSE_DEBUG) printf("parse_infix_op: found addition operator (LINE %d)\n", line_count);
+    return parse_gen_expr(fs, insert_infix_op(infix_add, &tree_expr), preset);
+  case tMinus:
+    //if (PARSE_DEBUG) printf("parse_infix_op: found subtraction operator (LINE %d)\n", line_count);
+    return parse_gen_expr(fs, insert_infix_op(infix_minus, &tree_expr), preset);
+  case tMult:
+    //if (PARSE_DEBUG) printf("parse_infix_op: found multiplication operator (LINE %d)\n", line_count);
+    return parse_gen_expr(fs, insert_infix_op(infix_mult, &tree_expr), preset);
+  case tDiv:
+    //if (PARSE_DEBUG) printf("parse_infix_op: found division operator (LINE %d)\n", line_count);  
+    return parse_gen_expr(fs, insert_infix_op(infix_div, &tree_expr), preset);
+  case tMod:
+    //if (PARSE_DEBUG) printf("parse_infix_op: found modulo operator (LINE %d)\n", line_count);  
+    return parse_gen_expr(fs, insert_infix_op(infix_mod, &tree_expr), preset);
+  case tOr:  
+    //if (PARSE_DEBUG) printf("parse_infix_op: found bitwise or operator (LINE %d)\n", line_count);      
+    return parse_gen_expr(fs, insert_infix_op(infix_or, &tree_expr), preset);
+  case tAnd:     
+    //if (PARSE_DEBUG) printf("parse_infix_op: found bitwise and operator (LINE %d)\n", line_count);     
+    return parse_gen_expr(fs, insert_infix_op(infix_and, &tree_expr), preset);
+  case tPositive:
+    //if (PARSE_DEBUG) printf("parse_infix_op: found positive operator (LINE %d)\n", line_count);        
+    return parse_gen_expr(fs, insert_infix_op(infix_positive, &tree_expr), preset);
+  case tNegative:
+    //if (PARSE_DEBUG) printf("parse_infix_op: found negative operator (LINE %d)\n", line_count);        
+    return parse_gen_expr(fs, insert_infix_op(infix_negative, &tree_expr), preset);
+
+  case tEOL:
+  case tEOF:
+  case tSemiColon:
+  case tRPr:
+  case tComma:   
+       //if (PARSE_DEBUG) printf("parse_infix_op: terminal found (LINE %d)\n", line_count);
+       gen_expr = new_gen_expr(TREE_T, (void*)tree_expr);
+       return gen_expr;
+  default:
+    //if (PARSE_DEBUG) printf("parse_infix_op: operator or terminal expected, but not found (LINE %d)\n", line_count);
+    free_tree_expr(tree_expr);
+    return NULL;
+  }  
+
+  /* Will never happen */
+  return NULL;
+  
+}
+
+/* Parses an integer, checks for +/- prefix */
+int parse_int(FILE * fs, int * int_ptr) {
+
+char string[MAX_TOKEN_SIZE];
+  token_t token;
+  int sign;
+  char * end_ptr = " ";
+       
+  token = parseToken(fs, string);
+
+  switch (token) {
+  case tMinus:
+    sign = -1;
+    token = parseToken(fs, string); 
+    break;
+  case tPlus:
+    sign = 1;
+    token = parseToken(fs, string);
+    break;
+  default: 
+    sign = 1;
+    break;
+  }
+
+  if (string[0] == 0) 
+    return PARSE_ERROR;
+  
+  /* Convert the string to an integer. *end_ptr
+     should end up pointing to null terminator of 'string' 
+     if the conversion was successful. */
+  //  printf("STRING: \"%s\"\n", string);
+
+  (*int_ptr) = sign*strtol(string, &end_ptr, 10);
+
+  /* If end pointer is a return character or null terminator, all is well */
+  if ((*end_ptr == '\r') || (*end_ptr == '\0')) 
+    return SUCCESS;
+
+    return PARSE_ERROR;
+  
+}
+/* Parses a floating point number */
+int string_to_float(char * string, double * float_ptr) {
+
+  char ** error_ptr;
+
+  if (*string == 0)
+    return PARSE_ERROR;
+
+  error_ptr = malloc(sizeof(char**));
+  
+  (*float_ptr) = strtod(string, error_ptr);
+  /* These imply a succesful parse of the string */
+  if ((**error_ptr == '\0') || (**error_ptr == '\r')) {
+    free(error_ptr);
+    return SUCCESS;
+  }
+    
+  (*float_ptr) = 0;
+  free(error_ptr);
+  return PARSE_ERROR;  
+}
+
+/* Parses a floating point number */
+int parse_float(FILE * fs, double * float_ptr) {
+
+  char string[MAX_TOKEN_SIZE];
+  char ** error_ptr;
+  token_t token;
+  int sign;
+  
+  error_ptr = malloc(sizeof(char**));
+
+  token = parseToken(fs, string);
+
+  switch (token) {
+  case tMinus:
+  sign = -1;
+  token = parseToken(fs, string); 
+  break;
+  case tPlus:
+  sign = 1;
+  token = parseToken(fs, string);
+  break;
+  default: 
+    sign = 1;  
+  }
+  if (string[0] == 0) {
+    free(error_ptr);
+    return PARSE_ERROR;
+  }
+
+  (*float_ptr) = sign*strtod(string, error_ptr);
+  /* No conversion was performed */
+  if ((**error_ptr == '\0') || (**error_ptr == '\r')) {
+    free(error_ptr);
+    return SUCCESS;
+  }
+    
+  //if (PARSE_DEBUG) printf("parse_float: double conversion failed for string \"%s\"\n", string);
+
+  (*float_ptr) = 0;
+  free(error_ptr);
+  return PARSE_ERROR;
+  
+
+  
+}
+
+/* Parses a per frame equation. That is, interprets a stream of data as a per frame equation */
+per_frame_eqn_t * parse_per_frame_eqn(FILE * fs, int index, struct PRESET_T * preset) {
+  
+  char string[MAX_TOKEN_SIZE];
+  param_t * param;
+  per_frame_eqn_t * per_frame_eqn;
+  gen_expr_t * gen_expr;
+  
+  if (parseToken(fs, string) != tEq) {
+    //if (PARSE_DEBUG) printf("parse_per_frame_eqn: no equal sign after string \"%s\" (LINE %d)\n", string, line_count);
+    return NULL;                       
+  }
+  
+  /* Find the parameter associated with the string, create one if necessary */
+  if ((param = find_param(string, preset, P_CREATE)) == NULL) { 
+    return NULL;       
+  }
+  
+  /* Make sure parameter is writable */
+  if (param->flags & P_FLAG_READONLY) {
+      //if (PARSE_DEBUG) printf("parse_per_frame_eqn: parameter %s is marked as read only (LINE %d)\n", param->name, line_count);  
+      return NULL;
+  }
+  
+  /* Parse right side of equation as an expression */
+  if ((gen_expr = parse_gen_expr(fs, NULL, preset)) == NULL) {
+    //if (PARSE_DEBUG) printf("parse_per_frame_eqn: equation evaluated to null (LINE %d)\n", line_count);
+    return NULL;
+  }
+  
+  //if (PARSE_DEBUG) printf("parse_per_frame_eqn: finished per frame equation evaluation (LINE %d)\n", line_count);
+  
+  /* Create a new per frame equation */
+  if ((per_frame_eqn = new_per_frame_eqn(index, param, gen_expr)) == NULL) {
+    //if (PARSE_DEBUG) printf("parse_per_frame_eqn: failed to create a new per frame eqn, out of memory?\n");
+    free_gen_expr(gen_expr);
+    return NULL;
+  }
+  
+  //if (PARSE_DEBUG) printf("parse_per_frame_eqn: per_frame eqn parsed succesfully\n");
+  
+  return per_frame_eqn;
+}
+
+/* Parses an 'implicit' per frame equation. That is, interprets a stream of data as a per frame equation without a prefix */
+per_frame_eqn_t * parse_implicit_per_frame_eqn(FILE * fs, char * param_string, int index, struct PRESET_T * preset) {
+  
+  param_t * param;
+  per_frame_eqn_t * per_frame_eqn;
+  gen_expr_t * gen_expr;
+  
+  if (fs == NULL)
+    return NULL;
+  if (param_string == NULL)
+    return NULL;
+  if (preset == NULL)
+    return NULL;
+
+  //rintf("param string: %s\n", param_string);
+  /* Find the parameter associated with the string, create one if necessary */
+  if ((param = find_param(param_string, preset, P_CREATE)) == NULL) { 
+    return NULL;       
+  }
+  
+  //printf("parse_implicit_per_frame_eqn: param is %s\n", param->name);
+
+  /* Make sure parameter is writable */
+  if (param->flags & P_FLAG_READONLY) {
+    //if (PARSE_DEBUG) printf("parse_implicit_per_frame_eqn: parameter %s is marked as read only (LINE %d)\n", param->name, line_count);  
+    return NULL;
+  }
+  
+  /* Parse right side of equation as an expression */
+  if ((gen_expr = parse_gen_expr(fs, NULL, preset)) == NULL) {
+    //if (PARSE_DEBUG) printf("parse_implicit_per_frame_eqn: equation evaluated to null (LINE %d)\n", line_count);
+    return NULL;
+  }
+  
+  //if (PARSE_DEBUG) printf("parse_implicit_per_frame_eqn: finished per frame equation evaluation (LINE %d)\n", line_count);
+  
+  /* Create a new per frame equation */
+  if ((per_frame_eqn = new_per_frame_eqn(index, param, gen_expr)) == NULL) {
+    //if (PARSE_DEBUG) printf("parse_implicit_per_frame_eqn: failed to create a new per frame eqn, out of memory?\n");
+    free_gen_expr(gen_expr);
+    return NULL;
+  }
+  
+  //if (PARSE_DEBUG) printf("parse_implicit_per_frame_eqn: per_frame eqn parsed succesfully\n");
+  
+  return per_frame_eqn;
+}
+
+/* Parses an initial condition */
+init_cond_t * parse_init_cond(FILE * fs, char * name, struct PRESET_T * preset) {
+
+  param_t * param;
+  value_t init_val;
+  init_cond_t * init_cond;
+       
+  if (name == NULL)
+    return NULL;
+  if (preset == NULL)
+    return NULL;
+  
+  /* Search for the paramater in the database, creating it if necessary */
+  if ((param = find_param(name, preset, P_CREATE)) == NULL) {
+    return NULL;
+  }
+  
+  //if (PARSE_DEBUG) printf("parse_init_cond: parameter = \"%s\" (LINE %d)\n", param->name, line_count);
+  
+  if (param->flags & P_FLAG_READONLY) {
+    //if (PARSE_DEBUG) printf("parse_init_cond: builtin parameter \"%s\" marked as read only!\n", param->name);
+    return NULL;
+  }            
+  
+  /* At this point, a parameter has been created or was found
+     in the database. */
+  
+  //if (PARSE_DEBUG) printf("parse_init_cond: parsing initial condition value... (LINE %d)\n", line_count);
+  
+  /* integer value (boolean is an integer in C) */
+  if ((param->type == P_TYPE_INT) || (param->type == P_TYPE_BOOL)) {
+    if ((parse_int(fs, (int*)&init_val.int_val)) == PARSE_ERROR) {     
+      //if (PARSE_DEBUG) printf("parse_init_cond: error parsing integer!\n");
+      return NULL;
+    }
+  }
+  
+  /* double value */
+  else if (param->type == P_TYPE_DOUBLE) {
+    if ((parse_float(fs, (double*)&init_val.double_val)) == PARSE_ERROR) {
+      //if (PARSE_DEBUG) printf("parse_init_cond: error parsing double!\n");
+      return NULL;
+    }
+  }
+  
+  /* Unknown value */
+  else {
+    //if (PARSE_DEBUG) printf("parse_init_cond: unknown parameter type!\n");
+    return NULL;
+  }
+  
+  /* Create new initial condition */
+  if ((init_cond = new_init_cond(param, init_val)) == NULL) {
+      //if (PARSE_DEBUG) printf("parse_init_cond: new_init_cond failed!\n");
+      return NULL;
+  }
+  
+  /* Finished */
+  return init_cond;
+}
+
+/* Parses a per frame init equation, not sure if this works right now */
+init_cond_t * parse_per_frame_init_eqn(FILE * fs, struct PRESET_T * preset, splaytree_t * database) {
+  
+  char name[MAX_TOKEN_SIZE];
+  param_t * param = NULL;
+  value_t init_val;
+  init_cond_t * init_cond;
+  gen_expr_t * gen_expr;
+  double val;
+  token_t token;
+
+
+  if (preset == NULL)
+    return NULL;
+  if (fs == NULL)
+    return NULL;
+
+  if ((token = parseToken(fs, name)) != tEq)
+    return NULL;
+  
+
+  /* If a database was specified,then use find_param_db instead */
+  if ((database != NULL) && ((param = find_param_db(name, database, TRUE)) == NULL)) {
+    return NULL;
+  }
+
+  /* Otherwise use the builtin parameter and user databases. This is confusing. Sorry. */
+  if ((param == NULL) && ((param = find_param(name, preset, P_CREATE)) == NULL)) {
+    return NULL;
+  }
+  
+  //if (PARSE_DEBUG) printf("parse_per_frame_init_eqn: parameter = \"%s\" (LINE %d)\n", param->name, line_count);
+  
+  if (param->flags & P_FLAG_READONLY) {
+    //if (PARSE_DEBUG) printf("pars_per_frame_init_eqn: builtin parameter \"%s\" marked as read only!\n", param->name);
+    return NULL;
+  }            
+  
+  /* At this point, a parameter has been created or was found
+     in the database. */
+  
+  //if (PARSE_DEBUG) printf("parse_per_frame_init_eqn: parsing right hand side of per frame init equation.. (LINE %d)\n", line_count);
+  
+  if ((gen_expr = parse_gen_expr(fs, NULL, preset)) == NULL) {
+    //if (PARSE_DEBUG) printf("parse_per_frame_init_eqn: failed to parse general expresion!\n");
+    return NULL;
+  }
+  /* Compute initial condition value */
+  val = eval_gen_expr(gen_expr);
+  
+  /* Free the general expression now that we are done with it */
+  free_gen_expr(gen_expr);
+
+  /* integer value (boolean is an integer in C) */
+  if ((param->type == P_TYPE_INT) || (param->type == P_TYPE_BOOL)) {
+    init_val.int_val = (int)val;
+  }
+  
+  /* double value */
+  else if (param->type == P_TYPE_DOUBLE) {
+    init_val.double_val = val;
+  }
+  
+  /* Unknown value */
+  else {
+    //if (PARSE_DEBUG) printf("parse_per_frame_init_eqn: unknown parameter type!\n");
+    return NULL;
+  }
+  
+
+  /* Create new initial condition */
+  if ((init_cond = new_init_cond(param, init_val)) == NULL) {
+      //if (PARSE_DEBUG) printf("parse_per_frame_init_eqn: new_init_cond failed!\n");
+      return NULL;
+  }
+
+
+  /* Finished */
+  return init_cond;
+}
+
+int parse_wavecode(char * token, FILE * fs, preset_t * preset) {
+
+  char * var_string;
+  init_cond_t * init_cond;
+  custom_wave_t * custom_wave;
+  int id;
+  value_t init_val;
+  param_t * param;
+
+  /* Null argument checks */
+  if (preset == NULL)
+    return FAILURE;
+  if (fs == NULL)
+    return FAILURE;
+  if (token == NULL)
+    return FAILURE;
+
+  /* token should be in the form wavecode_N_var, such as wavecode_1_samples */
+  
+  /* Get id and variable name from token string */
+  if (parse_wavecode_prefix(token, &id, &var_string) < 0)   
+    return PARSE_ERROR;
+  
+  //if (PARSE_DEBUG) printf("parse_wavecode: wavecode id = %d, parameter = \"%s\"\n", id, var_string);
+
+  /* Retrieve custom wave information from preset. The 3rd argument
+     if true creates a custom wave if one does not exist */
+  if ((custom_wave = find_custom_wave(id, preset, TRUE)) == NULL) {
+    //if (PARSE_DEBUG) printf("parse_wavecode: failed to load (or create) custom wave (id = %d)!\n", id);
+    return FAILURE;
+  }
+  //if (PARSE_DEBUG) printf("parse_wavecode: custom wave found (id = %d)\n", custom_wave->id);
+
+  /* Retrieve parameter from this custom waves parameter db */
+  if ((param = find_param_db(var_string, custom_wave->param_tree, TRUE)) == NULL)
+    return FAILURE;
+
+  //if (PARSE_DEBUG) printf("parse_wavecode: custom wave parameter found (name = %s)\n", param->name);
+
+  /* integer value (boolean is an integer in C) */
+  if ((param->type == P_TYPE_INT) || (param->type == P_TYPE_BOOL)) {
+    if ((parse_int(fs, (int*)&init_val.int_val)) == PARSE_ERROR) {     
+      //if (PARSE_DEBUG) printf("parse_wavecode: error parsing integer!\n");
+      return PARSE_ERROR;
+    }
+  }
+  
+  /* double value */
+  else if (param->type == P_TYPE_DOUBLE) {
+    if ((parse_float(fs, (double*)&init_val.double_val)) == PARSE_ERROR) {
+      //if (PARSE_DEBUG) printf("parse_wavecode: error parsing double!\n");
+      return PARSE_ERROR;
+    }
+  }
+  
+  /* Unknown value */
+  else {
+    //if (PARSE_DEBUG) printf("parse_wavecode: unknown parameter type!\n");
+    return PARSE_ERROR;
+  }
+  
+  /* Create new initial condition */
+  if ((init_cond = new_init_cond(param, init_val)) == NULL) {
+      //if (PARSE_DEBUG) printf("parse_wavecode: new_init_cond failed!\n");
+      return FAILURE;
+  }
+  
+  if (splay_insert(init_cond, param->name, custom_wave->init_cond_tree) < 0) {
+    free_init_cond(init_cond);
+    return PARSE_ERROR;
+  }
+
+  //if (PARSE_DEBUG) printf("parse_wavecode: [success]\n");
+  return SUCCESS;
+}
+
+int parse_shapecode(char * token, FILE * fs, preset_t * preset) {
+
+  char * var_string;
+  init_cond_t * init_cond;
+  custom_shape_t * custom_shape;
+  int id;
+  value_t init_val;
+  param_t * param;
+
+  /* Null argument checks */
+  if (preset == NULL)
+    return FAILURE;
+  if (fs == NULL)
+    return FAILURE;
+  if (token == NULL)
+    return FAILURE;
+
+  /* token should be in the form shapecode_N_var, such as shapecode_1_samples */
+  
+  /* Get id and variable name from token string */
+  if (parse_shapecode_prefix(token, &id, &var_string) < 0)   
+    return PARSE_ERROR;
+  
+  //if (PARSE_DEBUG) printf("parse_shapecode: shapecode id = %d, parameter = \"%s\"\n", id, var_string);
+
+  /* Retrieve custom shape information from preset. The 3rd argument
+     if true creates a custom shape if one does not exist */
+  if ((custom_shape = find_custom_shape(id, preset, TRUE)) == NULL) {
+    //if (PARSE_DEBUG) printf("parse_shapecode: failed to load (or create) custom shape (id = %d)!\n", id);
+    return FAILURE;
+  }
+  //if (PARSE_DEBUG) printf("parse_shapecode: custom shape found (id = %d)\n", custom_shape->id);
+
+  /* Retrieve parameter from this custom shapes parameter db */
+  if ((param = find_param_db(var_string, custom_shape->param_tree, TRUE)) == NULL) {
+    //if (PARSE_DEBUG) printf("parse_shapecode: failed to create parameter.\n");
+    return FAILURE;
+  }
+  //if (PARSE_DEBUG) printf("parse_shapecode: custom shape parameter found (name = %s)\n", param->name);
+
+  /* integer value (boolean is an integer in C) */
+  if ((param->type == P_TYPE_INT) || (param->type == P_TYPE_BOOL)) {
+    if ((parse_int(fs, (int*)&init_val.int_val)) == PARSE_ERROR) {     
+      //if (PARSE_DEBUG) printf("parse_shapecode: error parsing integer!\n");
+      return PARSE_ERROR;
+    }
+  }
+  
+  /* double value */
+  else if (param->type == P_TYPE_DOUBLE) {
+    if ((parse_float(fs, (double*)&init_val.double_val)) == PARSE_ERROR) {
+      //if (PARSE_DEBUG) printf("parse_shapecode: error parsing double!\n");
+      return PARSE_ERROR;
+    }
+  }
+  
+  /* Unknown value */
+  else {
+    //if (PARSE_DEBUG) printf("parse_shapecode: unknown parameter type!\n");
+    return PARSE_ERROR;
+  }
+  
+  /* Create new initial condition */
+  if ((init_cond = new_init_cond(param, init_val)) == NULL) {
+      //if (PARSE_DEBUG) printf("parse_shapecode: new_init_cond failed!\n");
+      return FAILURE;
+  }
+  if (splay_insert(init_cond, param->name, custom_shape->init_cond_tree) < 0) {
+    free_init_cond(init_cond);
+    //if (PARSE_DEBUG) printf("parse_shapecode: initial condition already set, not reinserting it (param = \"%s\")\n", param->name);
+    return PARSE_ERROR;
+  }
+
+  //if (PARSE_DEBUG) printf("parse_shapecode: [success]\n");
+  return SUCCESS;
+}
+
+
+int parse_wavecode_prefix(char * token, int * id, char ** var_string) {
+
+  int len, i, j;
+  
+  if (token == NULL)
+    return FAILURE;
+  if (*var_string == NULL)
+    return FAILURE;
+  if (id == NULL)
+    return FAILURE;
+  
+  len = strlen(token);
+
+  /* Move pointer passed "wavecode_" prefix */
+  if (len <= WAVECODE_STRING_LENGTH)
+    return FAILURE;
+  i = WAVECODE_STRING_LENGTH;
+  j = 0;
+  (*id) = 0;
+  
+  /* This loop grabs the integer id for this custom wave */
+  while ((i < len) && (token[i] >=  48) && (token[i] <= 57)) {
+    if (j >= MAX_TOKEN_SIZE)
+      return FAILURE;
+    
+    (*id) = 10*(*id) + (token[i]-48);
+    j++;
+    i++;
+  }
+
+  if (i > (len - 2))
+    return FAILURE;
+  
+  *var_string = token + i + 1;
+  return SUCCESS;
+
+}
+
+
+int parse_shapecode_prefix(char * token, int * id, char ** var_string) {
+
+  int len, i, j;
+  
+  if (token == NULL)
+    return FAILURE;
+  if (*var_string == NULL)
+    return FAILURE;
+  if (id == NULL)
+    return FAILURE;
+  
+  len = strlen(token);
+
+  /* Move pointer passed "shapecode_" prefix */
+  if (len <= SHAPECODE_STRING_LENGTH)
+    return FAILURE;
+  i = SHAPECODE_STRING_LENGTH;
+  j = 0;
+  (*id) = 0;
+  
+  /* This loop grabs the integer id for this custom shape */
+  while ((i < len) && (token[i] >=  48) && (token[i] <= 57)) {
+    if (j >= MAX_TOKEN_SIZE)
+      return FAILURE;
+    
+    (*id) = 10*(*id) + (token[i]-48);
+    j++;
+    i++;
+  }
+
+  if (i > (len - 2))
+    return FAILURE;
+  
+  *var_string = token + i + 1;
+  return SUCCESS;
+
+}
+
+int parse_wave_prefix(char * token, int * id, char ** eqn_string) {
+
+  int len, i, j;
+  
+  if (token == NULL)
+    return FAILURE;
+  if (eqn_string == NULL)
+    return FAILURE;
+  if (id == NULL)
+    return FAILURE;
+  
+  len = strlen(token);
+  if (len <= WAVE_STRING_LENGTH)
+    return FAILURE;
+
+
+  i = WAVE_STRING_LENGTH;
+  j = 0;
+  (*id) = 0;
+  
+  /* This loop grabs the integer id for this custom wave */
+  while ((i < len) && (token[i] >=  48) && (token[i] <= 57)) {
+    if (j >= MAX_TOKEN_SIZE)
+      return FAILURE;
+    
+    (*id) = 10*(*id) + (token[i]-48);
+    j++;
+    i++;
+  }
+
+  if (i > (len - 2))
+    return FAILURE;
+  *eqn_string = token + i + 1;
+  return SUCCESS;
+
+}
+
+int parse_shape_prefix(char * token, int * id, char ** eqn_string) {
+
+  int len, i, j;
+  
+  if (token == NULL)
+    return FAILURE;
+  if (eqn_string == NULL)
+    return FAILURE;
+  if (id == NULL)
+    return FAILURE;
+  
+  len = strlen(token);
+  if (len <= SHAPE_STRING_LENGTH)
+    return FAILURE;
+
+
+  i = SHAPE_STRING_LENGTH;
+  j = 0;
+  (*id) = 0;
+  
+  /* This loop grabs the integer id for this custom wave */
+  while ((i < len) && (token[i] >=  48) && (token[i] <= 57)) {
+    if (j >= MAX_TOKEN_SIZE)
+      return FAILURE;
+    
+    (*id) = 10*(*id) + (token[i]-48);
+    j++;
+    i++;
+  }
+
+  if (i > (len - 2))
+    return FAILURE;
+  *eqn_string = token + i + 1;
+  return SUCCESS;
+
+}
+
+/* Parses custom wave equations */
+int parse_wave(char * token, FILE * fs, preset_t * preset) {
+  
+  int id;
+  char * eqn_type;
+  char string[MAX_TOKEN_SIZE];
+  param_t * param;
+  per_frame_eqn_t * per_frame_eqn;
+  gen_expr_t * gen_expr;
+  custom_wave_t * custom_wave;
+  init_cond_t * init_cond;
+
+  if (token == NULL)
+    return FAILURE;
+  if (fs == NULL)
+    return FAILURE;
+  if (preset == NULL)
+    return FAILURE;
+  
+  /* Grab custom wave id and equation type (per frame or per point) from string token */
+  if (parse_wave_prefix(token, &id, &eqn_type) < 0) {
+    //if (PARSE_DEBUG) printf("parse_wave: syntax error in custom wave prefix!\n");
+    return FAILURE;
+  }
+  /* Retrieve custom wave associated with this id */
+  if ((custom_wave = find_custom_wave(id, preset, TRUE)) == NULL)
+    return FAILURE;
+
+
+  /* per frame init equation case */       
+  if (!strncmp(eqn_type, WAVE_INIT_STRING, WAVE_INIT_STRING_LENGTH)) {
+
+    //if (PARSE_DEBUG) printf("parse_wave (per frame init): [begin] (LINE %d)\n", line_count);
+
+    /* Parse the per frame equation */
+    if ((init_cond = parse_per_frame_init_eqn(fs, preset, custom_wave->param_tree)) == NULL) {
+      //if (PARSE_DEBUG) printf("parse_wave (per frame init): equation parsing failed (LINE %d)\n", line_count);
+      return PARSE_ERROR;
+    }  
+
+    /* Insert the equation in the per frame equation tree */
+    if (splay_insert(init_cond, init_cond->param->name, custom_wave->per_frame_init_eqn_tree) < 0) {
+      //if (PARSE_DEBUG) printf("parse_wave (per frame init): failed to add equation (ERROR)\n");
+       free_init_cond(init_cond); /* will free the gen expr too */             
+      return FAILURE;
+    }
+   
+    if (update_string_buffer(custom_wave->per_frame_init_eqn_string_buffer, 
+                            &custom_wave->per_frame_init_eqn_string_index) < 0)
+      return FAILURE;
+       
+    return SUCCESS;
+  
+  }
+
+  /* per frame equation case */
+  if (!strncmp(eqn_type, PER_FRAME_STRING_NO_UNDERSCORE, PER_FRAME_STRING_NO_UNDERSCORE_LENGTH)) {
+
+    //if (PARSE_DEBUG) printf("parse_wave (per_frame): [start] (custom wave id = %d)\n", custom_wave->id);
+    
+    if (parseToken(fs, string) != tEq) {
+      //if (PARSE_DEBUG) printf("parse_wave (per_frame): no equal sign after string \"%s\" (LINE %d)\n", string, line_count);
+      return PARSE_ERROR;                      
+    }
+  
+    /* Find the parameter associated with the string in the custom wave database */
+    if ((param = find_param_db(string, custom_wave->param_tree, TRUE)) == NULL) { 
+      //if (PARSE_DEBUG) printf("parse_wave (per_frame): parameter \"%s\" not found or cannot be malloc'ed!!\n", string);
+      return FAILURE;  
+    }
+  
+    
+    /* Make sure parameter is writable */
+    if (param->flags & P_FLAG_READONLY) {
+      //if (PARSE_DEBUG) printf("parse_wave (per_frame): parameter %s is marked as read only (LINE %d)\n", param->name, line_count);  
+      return FAILURE;
+    }
+  
+    /* Parse right side of equation as an expression */
+
+    current_wave = custom_wave;
+    if ((gen_expr = parse_gen_expr(fs, NULL, preset)) == NULL) {
+      //if (PARSE_DEBUG) printf("parse_wave (per_frame): equation evaluated to null (LINE %d)\n", line_count);
+      current_wave = NULL;
+      return PARSE_ERROR;
+
+    }
+    current_wave = NULL;
+
+    //if (PARSE_DEBUG) printf("parse_wave (per_frame): [finished parsing equation] (LINE %d)\n", line_count);
+  
+    /* Create a new per frame equation */
+    if ((per_frame_eqn = new_per_frame_eqn(custom_wave->per_frame_count++, param, gen_expr)) == NULL) {
+      //if (PARSE_DEBUG) printf("parse_wave (per_frame): failed to create a new per frame eqn, out of memory?\n");
+      free_gen_expr(gen_expr);
+      return FAILURE;
+    }
+    if (splay_insert(per_frame_eqn, &per_frame_eqn->index, custom_wave->per_frame_eqn_tree) < 0) {
+      free_per_frame_eqn(per_frame_eqn);
+      return FAILURE;
+    }
+       
+    //if (PARSE_DEBUG) printf("parse_wave (per_frame): equation %d associated with custom wave %d [success]\n", 
+    //                     per_frame_eqn->index, custom_wave->id);
+
+    
+    /* Need to add stuff to string buffer so the editor can read the equations. 
+       Why not make a nice little helper function for this? - here it is: */
+
+   
+    if (update_string_buffer(custom_wave->per_frame_eqn_string_buffer, &custom_wave->per_frame_eqn_string_index) < 0)
+      return FAILURE;
+
+    return SUCCESS;
+  }
+
+
+  /* per point equation case */
+  if (!strncmp(eqn_type, PER_POINT_STRING, PER_POINT_STRING_LENGTH)) {
+
+    //if (PARSE_DEBUG) printf("parse_wave (per_point): per_pixel equation parsing start...(LINE %d)\n", line_count);
+
+    if (parseToken(fs, string) != tEq) { /* parse per pixel operator  name */
+      //if (PARSE_DEBUG) printf("parse_wave (per_point): equal operator missing after per pixel operator! (LINE %d)\n", line_count);
+      return PARSE_ERROR;
+    }
+    
+    /* Parse right side of equation as an expression */
+    current_wave = custom_wave;
+    if ((gen_expr = parse_gen_expr(fs, NULL, preset)) == NULL) {
+      //if (PARSE_DEBUG) printf("parse_wave (per_point): equation evaluated to null? (LINE %d)\n", line_count);
+      return PARSE_ERROR;
+    }
+    current_wave = NULL;
+
+    /* Add the per point equation */
+    if (add_per_point_eqn(string, gen_expr, custom_wave) < 0) {
+      free_gen_expr(gen_expr);
+      return PARSE_ERROR;
+    }
+
+   
+    if (update_string_buffer(custom_wave->per_point_eqn_string_buffer, &custom_wave->per_point_eqn_string_index) < 0)
+      return FAILURE;
+
+    //if (PARSE_DEBUG) printf("parse_wave (per_point): [finished] (custom wave id = %d)\n", custom_wave->id);
+    return SUCCESS;
+  }
+
+
+  /* Syntax error, return parse error */
+  return PARSE_ERROR;
+}
+
+
+
+/* Parses custom shape equations */
+int parse_shape(char * token, FILE * fs, preset_t * preset) {
+  
+  int id;
+  char * eqn_type;
+  char string[MAX_TOKEN_SIZE];
+  param_t * param;
+  per_frame_eqn_t * per_frame_eqn;
+  gen_expr_t * gen_expr;
+  custom_shape_t * custom_shape;
+  init_cond_t * init_cond;
+
+  if (token == NULL)
+
+    return FAILURE;
+  if (fs == NULL)
+    return FAILURE;
+  if (preset == NULL)
+    return FAILURE;
+  
+  /* Grab custom shape id and equation type (per frame or per point) from string token */
+  if (parse_shape_prefix(token, &id, &eqn_type) < 0) {
+    //if (PARSE_DEBUG) printf("parse_shape: syntax error in custom shape prefix!\n");
+    return PARSE_ERROR;
+  }
+  /* Retrieve custom shape associated with this id */
+  if ((custom_shape = find_custom_shape(id, preset, TRUE)) == NULL)
+    return FAILURE;
+
+
+  /* per frame init equation case */       
+  if (!strncmp(eqn_type, SHAPE_INIT_STRING, SHAPE_INIT_STRING_LENGTH)) {
+
+    //if (PARSE_DEBUG) printf("parse_shape (per frame init): [begin] (LINE %d)\n", line_count);
+
+    /* Parse the per frame equation */
+    if ((init_cond = parse_per_frame_init_eqn(fs, preset, custom_shape->param_tree)) == NULL) {
+      //if (PARSE_DEBUG) printf("parse_shape (per frame init): equation parsing failed (LINE %d)\n", line_count);
+      return PARSE_ERROR;
+    }  
+    
+    /* Insert the equation in the per frame equation tree */
+    if (splay_insert(init_cond, init_cond->param->name, custom_shape->per_frame_init_eqn_tree) < 0) {
+      //if (PARSE_DEBUG) printf("parse_shape (per frame init): failed to add equation (ERROR)\n");
+      free_init_cond(init_cond); /* will free the gen expr too */              
+      return ERROR;
+    }
+
+    if (update_string_buffer(custom_shape->per_frame_init_eqn_string_buffer, 
+                            &custom_shape->per_frame_init_eqn_string_index) < 0)
+      return FAILURE;
+       
+    return SUCCESS;
+  
+  }
+
+  /* per frame equation case */
+  if (!strncmp(eqn_type, PER_FRAME_STRING_NO_UNDERSCORE, PER_FRAME_STRING_NO_UNDERSCORE_LENGTH)) {
+
+    //if (PARSE_DEBUG) printf("parse_shape (per_frame): [start] (custom shape id = %d)\n", custom_shape->id);
+    
+    if (parseToken(fs, string) != tEq) {
+      //if (PARSE_DEBUG) printf("parse_shape (per_frame): no equal sign after string \"%s\" (LINE %d)\n", string, line_count);
+      return PARSE_ERROR;                      
+    }
+  
+    /* Find the parameter associated with the string in the custom shape database */
+    if ((param = find_param_db(string, custom_shape->param_tree, TRUE)) == NULL) { 
+      //if (PARSE_DEBUG) printf("parse_shape (per_frame): parameter \"%s\" not found or cannot be malloc'ed!!\n", string);
+      return FAILURE;  
+    }
+  
+    
+    /* Make sure parameter is writable */
+    if (param->flags & P_FLAG_READONLY) {
+      //if (PARSE_DEBUG) printf("parse_shape (per_frame): parameter %s is marked as read only (LINE %d)\n", param->name, line_count);  
+      return FAILURE;
+    }
+  
+    /* Parse right side of equation as an expression */
+
+    current_shape = custom_shape;
+    if ((gen_expr = parse_gen_expr(fs, NULL, preset)) == NULL) {
+      //if (PARSE_DEBUG) printf("parse_shape (per_frame): equation evaluated to null (LINE %d)\n", line_count);
+      current_shape = NULL;
+      return PARSE_ERROR;
+    }
+
+    current_shape = NULL;
+
+    //if (PARSE_DEBUG) printf("parse_shape (per_frame): [finished parsing equation] (LINE %d)\n", line_count);
+  
+    /* Create a new per frame equation */
+    if ((per_frame_eqn = new_per_frame_eqn(custom_shape->per_frame_count++, param, gen_expr)) == NULL) {
+      //if (PARSE_DEBUG) printf("parse_shape (per_frame): failed to create a new per frame eqn, out of memory?\n");
+      free_gen_expr(gen_expr);
+      return FAILURE;
+    }
+    if (splay_insert(per_frame_eqn, &per_frame_eqn->index, custom_shape->per_frame_eqn_tree) < 0) {
+      free_per_frame_eqn(per_frame_eqn);
+      return FAILURE;
+    }
+       
+    //if (PARSE_DEBUG) printf("parse_shape (per_frame): equation %d associated with custom shape %d [success]\n", 
+    //                     per_frame_eqn->index, custom_shape->id);
+
+    
+    /* Need to add stuff to string buffer so the editor can read the equations.
+       Why not make a nice little helper function for this? - here it is: */
+    
+    if (update_string_buffer(custom_shape->per_frame_eqn_string_buffer, &custom_shape->per_frame_eqn_string_index) < 0)
+      return FAILURE;
+
+    return SUCCESS;
+  }
+
+
+  /* Syntax error, return parse error */
+  return PARSE_ERROR;
+}
+
+/* Helper function to update the string buffers used by the editor */
+int update_string_buffer(char * buffer, int * index) {
+
+  int string_length;
+  int skip_size;
+
+  if (!buffer)
+    return FAILURE;
+  if (!index)
+    return FAILURE;
+
+  
+  /* If the string line buffer used by the parser is already full then quit */
+  if (string_line_buffer_index == (STRING_LINE_SIZE-1))
+    return FAILURE;
+
+  if ((skip_size = get_string_prefix_len(string_line_buffer)) == FAILURE)
+    return FAILURE;
+
+  string_line_buffer[string_line_buffer_index++] = '\n';
+
+  //  string_length = strlen(string_line_buffer + strlen(eqn_string)+1);
+  if (skip_size >= STRING_LINE_SIZE)
+    return FAILURE;
+
+  string_length = strlen(string_line_buffer + skip_size);
+
+  if (skip_size > (STRING_LINE_SIZE-1))
+    return FAILURE;
+
+  /* Add line to string buffer */
+  strncpy(buffer + (*index), 
+         string_line_buffer + skip_size, string_length);
+  
+  /* Buffer full, quit */
+  if ((*index) > (STRING_BUFFER_SIZE - 1)) {
+    //if (PARSE_DEBUG) printf("update_string_buffer: string buffer full!\n");
+    return FAILURE;
+  }    
+  
+  /* Otherwise, increment string index by the added string length */
+  (*index)+=string_length;
+    
+  return SUCCESS;
+  
+}
+
+
+/* Helper function: returns the length of the prefix portion in the line
+   buffer (the passed string here). In other words, given
+   the string 'per_frame_1 = x = ....', return the length of 'per_frame_1 = '
+   Returns -1 if syntax error
+*/
+
+int get_string_prefix_len(char * string) {
+  
+  int i = 0;
+
+  /* Null argument check */
+  if (string == NULL)
+    return FAILURE;
+
+  
+  /* First find the equal sign */
+  while (string[i] != '=') {
+    if (string[i] == 0)
+      return FAILURE;
+    i++;
+  }
+
+  /* If the string already ends at the next char then give up */
+  if (string[i+1] == 0)
+    return FAILURE;
+
+  /* Move past the equal sign */
+  i++;
+
+  /* Now found the start of the LHS variable, ie skip the spaces */
+  while(string[i] == ' ') {
+    i++;
+  }
+
+  /* If this is the end of the string then its a syntax error */
+  if (string[i] == 0)
+    return FAILURE;
+
+  /* Finished succesfully, return the length */
+  return i;
+}
diff --git a/modules/visualization/galaktos/parser.h b/modules/visualization/galaktos/parser.h
new file mode 100644 (file)
index 0000000..6e2d515
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef PARSER_H
+#define PARSER_H
+#define PARSE_DEBUG 0
+#include "expr_types.h"
+#include "per_frame_eqn_types.h"
+#include "init_cond_types.h"
+#include "preset_types.h"
+
+per_frame_eqn_t * parse_per_frame_eqn(FILE * fs, int index, struct PRESET_T * preset);
+int parse_per_pixel_eqn(FILE * fs, preset_t * preset);
+init_cond_t * parse_init_cond(FILE * fs, char * name, struct PRESET_T * preset);
+int parse_preset_name(FILE * fs, char * name);
+int parse_top_comment(FILE * fs);
+int parse_line(FILE * fs, struct PRESET_T * preset);
+#endif
diff --git a/modules/visualization/galaktos/per_frame_eqn.c b/modules/visualization/galaktos/per_frame_eqn.c
new file mode 100644 (file)
index 0000000..77db6ce
--- /dev/null
@@ -0,0 +1,115 @@
+/*****************************************************************************
+ * per_frame_eqn.c:
+ *****************************************************************************
+ * Copyright (C) 2004 VideoLAN
+ * $Id$
+ *
+ * Authors: Cyril Deguet <asmax@videolan.org>
+ *          code from projectM http://xmms-projectm.sourceforge.net
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ *****************************************************************************/
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "fatal.h"
+#include "common.h"
+#include "per_frame_eqn_types.h"
+#include "per_frame_eqn.h"
+
+#include "expr_types.h"
+#include "eval.h"
+
+/* Evaluate an equation */
+void eval_per_frame_eqn(per_frame_eqn_t * per_frame_eqn) {
+
+  if (per_frame_eqn == NULL)
+    return;
+
+     if (PER_FRAME_EQN_DEBUG) { 
+                printf("per_frame_%d=%s= ", per_frame_eqn->index, per_frame_eqn->param->name);
+                fflush(stdout);
+        }
+        
+    //*((double*)per_frame_eqn->param->engine_val) = eval_gen_expr(per_frame_eqn->gen_expr);
+       set_param(per_frame_eqn->param, eval_gen_expr(per_frame_eqn->gen_expr));
+     if (PER_FRAME_EQN_DEBUG) printf(" = %.4f\n", *((double*)per_frame_eqn->param->engine_val)); 
+                
+}
+
+/*
+void eval_per_frame_init_eqn(per_frame_eqn_t * per_frame_eqn) {
+
+   double val;
+   init_cond_t * init_cond;
+   if (per_frame_eqn == NULL)
+     return;
+
+     if (PER_FRAME_EQN_DEBUG) { 
+                printf("per_frame_init: %s = ", per_frame_eqn->param->name);
+                fflush(stdout);
+        }
+                       
+       
+    val = *((double*)per_frame_eqn->param->engine_val) = eval_gen_expr(per_frame_eqn->gen_expr);
+    if (PER_FRAME_EQN_DEBUG) printf(" = %f\n", *((double*)per_frame_eqn->param->engine_val)); 
+     
+       if (per_frame_eqn->param->flags & P_FLAG_QVAR) {
+               
+               per_frame_eqn->param->init_val.double_val = val;
+               if ((init_cond = new_init_cond(per_frame_eqn->param)) == NULL)
+                       return;
+               
+               if ((list_append(init_cond_list, init_cond)) < 0) {
+                       free_init_cond(init_cond);
+                       return;
+               }
+    }
+}
+*/
+
+/* Frees perframe equation structure */
+void free_per_frame_eqn(per_frame_eqn_t * per_frame_eqn) {
+
+       if (per_frame_eqn == NULL)
+         return;
+       
+  free_gen_expr(per_frame_eqn->gen_expr);
+  free(per_frame_eqn);
+}
+
+/* Create a new per frame equation */
+per_frame_eqn_t * new_per_frame_eqn(int index, param_t * param, gen_expr_t * gen_expr) {
+
+  per_frame_eqn_t * per_frame_eqn;
+
+  per_frame_eqn = (per_frame_eqn_t*)malloc(sizeof(per_frame_eqn_t));
+
+  if (per_frame_eqn == NULL)
+    return NULL;
+
+  per_frame_eqn->param = param;
+  per_frame_eqn->gen_expr = gen_expr;
+  per_frame_eqn->index = index;
+  /* Set per frame eqn name */
+  //  memset(per_frame_eqn->name, 0, MAX_TOKEN_SIZE);
+  //strncpy(per_frame_eqn->name, name, MAX_TOKEN_SIZE-1);
+  return per_frame_eqn;
+
+}
diff --git a/modules/visualization/galaktos/per_frame_eqn.h b/modules/visualization/galaktos/per_frame_eqn.h
new file mode 100644 (file)
index 0000000..908982f
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef PER_FRAME_EQN_H
+#define PER_FRAME_EQN_H
+#define PER_FRAME_EQN_DEBUG 0
+
+per_frame_eqn_t * new_per_frame_eqn(int index, param_t * param, struct GEN_EXPR_T * gen_expr);
+void eval_per_frame_eqn(per_frame_eqn_t * per_frame_eqn);
+void free_per_frame_eqn(per_frame_eqn_t * per_frame_eqn);
+void eval_per_frame_init_eqn(per_frame_eqn_t * per_frame_eqn);
+#endif
diff --git a/modules/visualization/galaktos/per_frame_eqn_types.h b/modules/visualization/galaktos/per_frame_eqn_types.h
new file mode 100644 (file)
index 0000000..c02305c
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef PER_FRAME_EQN_TYPES_H
+#define PER_FRAME_EQN_TYPES_H
+#include "param_types.h"
+#include "expr_types.h"
+
+typedef struct PER_FRAME_EQN_T {
+  int index;
+  struct PARAM_T * param; /* parameter to be assigned a value */
+  struct GEN_EXPR_T * gen_expr;   /* expression that paremeter is equal to */
+} per_frame_eqn_t;
+#endif
diff --git a/modules/visualization/galaktos/per_pixel_eqn.c b/modules/visualization/galaktos/per_pixel_eqn.c
new file mode 100644 (file)
index 0000000..0be34f1
--- /dev/null
@@ -0,0 +1,229 @@
+/*****************************************************************************
+ * per_pixel_eqn.c:
+ *****************************************************************************
+ * Copyright (C) 2004 VideoLAN
+ * $Id$
+ *
+ * Authors: Cyril Deguet <asmax@videolan.org>
+ *          code from projectM http://xmms-projectm.sourceforge.net
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ *****************************************************************************/
+
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "fatal.h"
+#include "common.h"
+
+#include "expr_types.h"
+#include "eval.h"
+
+#include "splaytree_types.h"
+#include "splaytree.h"
+
+#include "param_types.h"
+#include "param.h"
+
+#include "per_pixel_eqn.h"
+#include "per_pixel_eqn_types.h"
+
+#include "engine_vars.h"
+
+
+extern preset_t * active_preset;
+
+extern int mesh_i;
+extern int mesh_j;
+
+
+
+/* Evaluates a per pixel equation */
+inline void evalPerPixelEqn(per_pixel_eqn_t * per_pixel_eqn) {
+
+  double ** param_matrix = NULL;
+  gen_expr_t * eqn_ptr = NULL;
+  int x,y;
+
+  eqn_ptr = per_pixel_eqn->gen_expr; 
+ if (per_pixel_eqn->param->matrix == NULL) {
+    if (PER_PIXEL_EQN_DEBUG) printf("evalPerPixelEqn: [begin initializing matrix] (index = %d) (name = %s)\n", 
+                         per_pixel_eqn->index, per_pixel_eqn->param->name);
+    
+    param_matrix = per_pixel_eqn->param->matrix = (double**)malloc(gx*sizeof(double*));
+    
+    for(x = 0; x < gx; x++)
+      param_matrix[x] = (double *)malloc(gy * sizeof(double));
+
+    for (x = 0; x < gx; x++)
+      for (y = 0; y < gy; y++)
+       param_matrix[x][y] = 0.0;
+
+    if (per_pixel_eqn->param->name == NULL)
+      printf("null parameter?\n");
+
+    //    printf("PARAM MATRIX: \"%s\" initialized.\n", per_pixel_eqn->param->name);
+  }
+  else 
+    param_matrix = (double**)per_pixel_eqn->param->matrix;
+  if (eqn_ptr == NULL)
+    printf("something is seriously wrong...\n");
+  for (mesh_i = 0; mesh_i < gx; mesh_i++) {    
+    for (mesh_j = 0; mesh_j < gy; mesh_j++) {     
+      param_matrix[mesh_i][mesh_j] = eval_gen_expr(eqn_ptr);
+    }
+  }
+  
+  /* Now that this parameter has been referenced with a per
+     pixel equation, we let the evaluator know by setting
+     this flag */
+  per_pixel_eqn->param->matrix_flag = 1; 
+}
+
+inline void evalPerPixelEqns() {
+
+  /* Evaluate all per pixel equations using splay traversal */
+  splay_traverse(evalPerPixelEqn, active_preset->per_pixel_eqn_tree);
+
+  /* Set mesh i / j values to -1 so engine vars are used by default again */
+  mesh_i = mesh_j = -1;
+
+}
+/* Adds a per pixel equation according to its string name. This
+   will be used only by the parser */
+
+int add_per_pixel_eqn(char * name, gen_expr_t * gen_expr, preset_t * preset) {
+
+  per_pixel_eqn_t * per_pixel_eqn;
+  int index;
+  param_t * param = NULL;
+
+  /* Argument checks */
+  if (preset == NULL)
+         return FAILURE;
+  if (gen_expr == NULL)
+         return FAILURE;
+  if (name == NULL)
+         return FAILURE;
+  
+ if (PER_PIXEL_EQN_DEBUG) printf("add_per_pixel_eqn: per pixel equation (name = \"%s\")\n", name);
+ if (!strncmp(name, "dx", strlen("dx"))) 
+   preset->per_pixel_flag[DX_OP] = TRUE;
+ else if (!strncmp(name, "dy", strlen("dy"))) 
+   preset->per_pixel_flag[DY_OP] = TRUE;
+ else if (!strncmp(name, "cx", strlen("cx"))) 
+   preset->per_pixel_flag[CX_OP] = TRUE;
+ else if (!strncmp(name, "cy", strlen("cy"))) 
+   preset->per_pixel_flag[CX_OP] = TRUE;
+ else if (!strncmp(name, "zoom", strlen("zoom"))) 
+   preset->per_pixel_flag[ZOOM_OP] = TRUE;
+ else if (!strncmp(name, "zoomexp", strlen("zoomexp"))) 
+   preset->per_pixel_flag[ZOOMEXP_OP] = TRUE;
+ else if (!strncmp(name, "rot", strlen("rot")))
+   preset->per_pixel_flag[ROT_OP] = TRUE;
+ else if (!strncmp(name, "sx", strlen("sx")))
+   preset->per_pixel_flag[SX_OP] = TRUE;
+ else if (!strncmp(name, "sy", strlen("sy")))
+   preset->per_pixel_flag[SY_OP] = TRUE;
+
+ /* Search for the parameter so we know what matrix the per pixel equation is referencing */
+
+ if ((param = find_param(name, preset, TRUE)) == NULL) {
+   if (PER_PIXEL_EQN_DEBUG) printf("add_per_pixel_eqn: failed to allocate a new parameter!\n");
+   return FAILURE;
+ }      
+
+ /* Find most largest index in the splaytree */
+ // if ((per_pixel_eqn = splay_find_max(active_preset->per_pixel_eqn_tree)) == NULL)
+ // index = 0;
+ // else
+ index = splay_size(preset->per_pixel_eqn_tree);
+   
+ /* Create the per pixel equation given the index, parameter, and general expression */
+ if ((per_pixel_eqn = new_per_pixel_eqn(index, param, gen_expr)) == NULL) {
+   if (PER_PIXEL_EQN_DEBUG) printf("add_per_pixel_eqn: failed to create new per pixel equation!\n");
+   return FAILURE;
+
+ }
+
+ if (PER_PIXEL_EQN_DEBUG) printf("add_per_pixel_eqn: new equation (index = %d) (param = \"%s\")\n", 
+                                per_pixel_eqn->index, per_pixel_eqn->param->name);
+ /* Insert the per pixel equation into the preset per pixel database */
+ if (splay_insert(per_pixel_eqn, &per_pixel_eqn->index, preset->per_pixel_eqn_tree) < 0) {
+   free_per_pixel_eqn(per_pixel_eqn);
+   printf("failed to add per pixel eqn!\n");
+   return FAILURE;      
+ }
+
+ /* Done */ 
+ return SUCCESS;
+}
+
+per_pixel_eqn_t * new_per_pixel_eqn(int index, param_t * param, gen_expr_t * gen_expr) {
+
+       per_pixel_eqn_t * per_pixel_eqn;
+       
+       if (index < 0)
+         return NULL;
+       if (param == NULL)
+         return NULL;
+       if (gen_expr == NULL)
+         return NULL;
+       
+       if ((per_pixel_eqn = (per_pixel_eqn_t*)malloc(sizeof(per_pixel_eqn_t))) == NULL)
+         return NULL;
+
+       
+       per_pixel_eqn->index = index;
+       per_pixel_eqn->param = param;
+       per_pixel_eqn->gen_expr = gen_expr;
+       
+       return per_pixel_eqn;   
+}
+
+
+void free_per_pixel_eqn(per_pixel_eqn_t * per_pixel_eqn) {
+
+       if (per_pixel_eqn == NULL)
+               return;
+       
+       free_gen_expr(per_pixel_eqn->gen_expr);
+       
+       free(per_pixel_eqn);
+       
+       return;
+}
+
+inline int isPerPixelEqn(int op) {
+    
+  return active_preset->per_pixel_flag[op];
+
+}
+
+inline int resetPerPixelEqnFlags(preset_t * preset) {
+  int i;
+
+  for (i = 0; i < NUM_OPS;i++)
+    preset->per_pixel_flag[i] = FALSE;
+
+  return SUCCESS;
+}
diff --git a/modules/visualization/galaktos/per_pixel_eqn.h b/modules/visualization/galaktos/per_pixel_eqn.h
new file mode 100644 (file)
index 0000000..332ef15
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef PER_PIXEL_EQN_H
+#define PER_PIXEL_EQN_H
+
+#include "expr_types.h"
+#include "preset_types.h"
+
+#define PER_PIXEL_EQN_DEBUG 0
+inline void evalPerPixelEqns();
+inline int isPerPixelEqn(int index);
+int add_per_pixel_eqn(char * name, gen_expr_t * gen_expr, struct PRESET_T * preset);
+void free_per_pixel_eqn(per_pixel_eqn_t * per_pixel_eqn);
+per_pixel_eqn_t * new_per_pixel_eqn(int index, param_t  * param, gen_expr_t * gen_expr);
+inline int resetPerPixelEqnFlags();
+
+#endif
diff --git a/modules/visualization/galaktos/per_pixel_eqn_types.h b/modules/visualization/galaktos/per_pixel_eqn_types.h
new file mode 100644 (file)
index 0000000..a5d4021
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef PER_PIXEL_EQN_TYPES_H
+#define PER_PIXEL_EQN_TYPES_H
+/* This is sort of ugly, but it is also the fastest way to access the per pixel equations */
+#include "common.h"
+#include "expr_types.h"
+
+typedef struct PER_PIXEL_EQN_T {
+  int index; /* used for splay tree ordering. */
+  int flags; /* primarily to specify if this variable is user-defined */
+  param_t * param; 
+  gen_expr_t * gen_expr;       
+} per_pixel_eqn_t;
+
+
+#define ZOOM_OP 0
+#define ZOOMEXP_OP 1
+#define ROT_OP 2
+#define CX_OP 3
+#define CY_OP 4
+#define SX_OP 5
+#define SY_OP  6
+#define DX_OP 7
+#define DY_OP 8
+#define WARP_OP 9
+#define NUM_OPS 10 /* obviously, this number is dependent on the number of existing per pixel operations */
+#endif
diff --git a/modules/visualization/galaktos/per_point_types.h b/modules/visualization/galaktos/per_point_types.h
new file mode 100644 (file)
index 0000000..ce10a41
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef PER_POINT_EQN_TYPES_H
+#define PER_POINT_EQN_TYPES_H
+
+#include "custom_wave_types.h"
+
+typedef struct PER_POINT_EQN {
+
+  custom_wave_t * custom_wave;
+  
+
+} per_point_eqn_t;
+
+#endif
index becf8b90061cf67359bab8f9e5d9b58095c69c60..8a2c4be390761b8a5e19fe0e44f92d9ea41301df 100644 (file)
@@ -5,6 +5,9 @@
  * $Id$
  *
  * Authors: Cyril Deguet <asmax@videolan.org>
+ *          Implementation of the winamp plugin MilkDrop
+ *          based on projectM http://xmms-projectm.sourceforge.net
+ *          and SciVi http://xmms-scivi.sourceforge.net
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
 /*****************************************************************************
  * Preamble
  *****************************************************************************/
+
 #include "plugin.h"
 #include "glx.h"
 #include "main.h"
+#include "PCM.h"
+#include "video_init.h"
+#include <GL/glu.h>
 
 #include <vlc/input.h>
 #include <vlc/vout.h>
@@ -61,6 +68,9 @@ static void Thread   ( vlc_object_t * );
 
 static char *TitleGet( vlc_object_t * );
 
+
+extern GLuint RenderTargetTextureID;
+
 /*****************************************************************************
  * Open: open a scope effect plugin
  *****************************************************************************/
@@ -100,12 +110,12 @@ static int Open( vlc_object_t *p_this )
     var_Create( p_thread, "galaktos-height", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
     var_Get( p_thread, "galaktos-height", &height );
 */
-    vlc_mutex_init( p_filter, &p_thread->lock );
-    vlc_cond_init( p_filter, &p_thread->wait );
+    p_thread->i_cur_sample = 0;
+    bzero( p_thread->p_data, 2*2*512 );
+
+    galaktos_glx_init( p_thread, 600, 600, 0 );
+    galaktos_init( p_thread );
 
-    p_thread->i_blocks = 0;
-    aout_DateInit( &p_thread->date, p_filter->output.i_rate );
-    aout_DateSet( &p_thread->date, 0 );
     p_thread->i_channels = aout_FormatNbChannels( &p_filter->input );
 
     p_thread->psz_title = TitleGet( VLC_OBJECT( p_filter ) );
@@ -114,9 +124,6 @@ static int Open( vlc_object_t *p_this )
                            VLC_THREAD_PRIORITY_LOW, VLC_FALSE ) )
     {
         msg_Err( p_filter, "cannot lauch galaktos thread" );
-        vout_Destroy( p_thread->p_vout );
-        vlc_mutex_destroy( &p_thread->lock );
-        vlc_cond_destroy( &p_thread->wait );
         if( p_thread->psz_title ) free( p_thread->psz_title );
         vlc_object_detach( p_thread );
         vlc_object_destroy( p_thread );
@@ -127,38 +134,6 @@ static int Open( vlc_object_t *p_this )
     return VLC_SUCCESS;
 }
 
-/*****************************************************************************
- * DoWork: process samples buffer
- *****************************************************************************
- * This function queues the audio buffer to be processed by the galaktos thread
- *****************************************************************************/
-static void DoWork( aout_instance_t * p_aout, aout_filter_t * p_filter,
-                    aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
-{
-    aout_filter_sys_t *p_sys = p_filter->p_sys;
-    block_t *p_block;
-
-    p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
-    p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes;
-
-    /* Queue sample */
-    vlc_mutex_lock( &p_sys->p_thread->lock );
-    if( p_sys->p_thread->i_blocks == MAX_BLOCKS )
-    {
-        vlc_mutex_unlock( &p_sys->p_thread->lock );
-        return;
-    }
-
-    p_block = block_New( p_sys->p_thread, p_in_buf->i_nb_bytes );
-    if( !p_block ) return;
-    memcpy( p_block->p_buffer, p_in_buf->p_buffer, p_in_buf->i_nb_bytes );
-    p_block->i_pts = p_in_buf->start_date;
-
-    p_sys->p_thread->pp_blocks[p_sys->p_thread->i_blocks++] = p_block;
-
-    vlc_cond_signal( &p_sys->p_thread->wait );
-    vlc_mutex_unlock( &p_sys->p_thread->lock );
-}
 
 /*****************************************************************************
  * float to s16 conversion
@@ -173,61 +148,43 @@ static inline int16_t FloatToInt16( float f )
         return (int16_t)( f * 32768.0 );
 }
 
+
 /*****************************************************************************
- * Fill buffer
+ * DoWork: process samples buffer
+ *****************************************************************************
+ * This function queues the audio buffer to be processed by the galaktos thread
  *****************************************************************************/
-static int FillBuffer( int16_t *p_data, int *pi_data,
-                       audio_date_t *pi_date, audio_date_t *pi_date_end,
-                       galaktos_thread_t *p_this )
+static void DoWork( aout_instance_t * p_aout, aout_filter_t * p_filter,
+                    aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
 {
-    int i_samples = 0;
-    block_t *p_block;
-
-    while( *pi_data < 512 )
-    {
-        if( !p_this->i_blocks ) return VLC_EGENERIC;
+    int i_samples;
+    int i_channels;
+    float *p_float;
+    galaktos_thread_t *p_thread = p_filter->p_sys->p_thread;
 
-        p_block = p_this->pp_blocks[0];
-        i_samples = __MIN( 512 - *pi_data, p_block->i_buffer /
-                           sizeof(float) / p_this->i_channels );
+    p_float = (float *)p_in_buf->p_buffer;
+    i_channels = p_thread->i_channels;
 
-        /* Date management */
-        if( p_block->i_pts > 0 &&
-            p_block->i_pts != aout_DateGet( pi_date_end ) )
-        {
-           aout_DateSet( pi_date_end, p_block->i_pts );
-        }
-        p_block->i_pts = 0;
+    p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
+    p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes;
 
-        aout_DateIncrement( pi_date_end, i_samples );
+    for( i_samples = p_in_buf->i_nb_samples; i_samples > 0; i_samples-- )
+    {
+        int i_cur_sample = p_thread->i_cur_sample;
 
-        while( i_samples > 0 )
+        p_thread->p_data[0][i_cur_sample] = FloatToInt16( p_float[0] );
+        if( i_channels > 1 )
         {
-            float *p_float = (float *)p_block->p_buffer;
-
-            p_data[*pi_data] = FloatToInt16( p_float[0] );
-            if( p_this->i_channels > 1 )
-                p_data[512 + *pi_data] = FloatToInt16( p_float[1] );
-
-            (*pi_data)++;
-            p_block->p_buffer += (sizeof(float) * p_this->i_channels);
-            p_block->i_buffer -= (sizeof(float) * p_this->i_channels);
-            i_samples--;
+            p_thread->p_data[1][i_cur_sample] = FloatToInt16( p_float[1] );
         }
+        p_float += i_channels;
 
-        if( !p_block->i_buffer )
+        if( ++(p_thread->i_cur_sample) == 512 )
         {
-            block_Release( p_block );
-            p_this->i_blocks--;
-            if( p_this->i_blocks )
-                memmove( p_this->pp_blocks, p_this->pp_blocks + 1,
-                         p_this->i_blocks * sizeof(block_t *) );
+            addPCM( p_thread->p_data );
+            p_thread->i_cur_sample = 0;
         }
     }
-
-    *pi_date = *pi_date_end;
-    *pi_data = 0;
-    return VLC_SUCCESS;
 }
 
 /*****************************************************************************
@@ -236,35 +193,45 @@ static int FillBuffer( int16_t *p_data, int *pi_data,
 static void Thread( vlc_object_t *p_this )
 {
     galaktos_thread_t *p_thread = (galaktos_thread_t*)p_this;
-    vlc_value_t width, height, speed;
-    audio_date_t i_pts;
-    int16_t p_data[2][512];
-    int i_data = 0, i_count = 0;
-    int i;
 
-    galaktos_glx_init( p_thread, 512, 512 );
+    int count=0;
+    double realfps=0,fpsstart=0;
+    int timed=0;
+    int timestart=0;
+    int mspf=0;
+    int w = 600, h = 600;
+
+    galaktos_glx_activate_window( p_thread );
+    setup_opengl( w, h );
+    CreateRenderTarget(512, &RenderTargetTextureID, NULL);
+
+    timestart=mdate()/1000;
 
     while( !p_thread->b_die )
     {
-        /* goom_update is damn slow, so just copy data and release the lock */
-        vlc_mutex_lock( &p_thread->lock );
-        if( FillBuffer( (int16_t *)p_data, &i_data, &i_pts,
-                        &p_thread->date, p_thread ) != VLC_SUCCESS )
-            vlc_cond_wait( &p_thread->wait, &p_thread->lock );
-        vlc_mutex_unlock( &p_thread->lock );
-
-        if( galaktos_update( p_thread, p_data ) == 1 )
+        mspf = 1000 / 60;
+        if( galaktos_update( p_thread ) == 1 )
         {
             p_thread->b_die = 1;
         }
-
         if( p_thread->psz_title )
         {
             free( p_thread->psz_title );
             p_thread->psz_title = NULL;
         }
 
-        msleep( VOUT_OUTMEM_SLEEP );
+        if (++count%100==0)
+        {
+            realfps=100/((mdate()/1000-fpsstart)/1000);
+ //           printf("%f\n",realfps);
+            fpsstart=mdate()/1000;
+        }
+        //framerate limiter
+        timed=mspf-(mdate()/1000-timestart);
+      //   printf("%d,%d\n",time,mspf);
+        if (timed>0) msleep(1000*timed);
+    //     printf("Limiter %d\n",(mdate()/1000-timestart));
+        timestart=mdate()/1000;
     }
 
     galaktos_glx_done( p_thread );
@@ -281,23 +248,13 @@ static void Close( vlc_object_t *p_this )
     /* Stop galaktos Thread */
     p_sys->p_thread->b_die = VLC_TRUE;
 
-    vlc_mutex_lock( &p_sys->p_thread->lock );
-    vlc_cond_signal( &p_sys->p_thread->wait );
-    vlc_mutex_unlock( &p_sys->p_thread->lock );
+    galaktos_done( p_sys->p_thread );
 
     vlc_thread_join( p_sys->p_thread );
 
     /* Free data */
-    vout_Request( p_filter, p_sys->p_thread->p_vout, 0, 0, 0, 0 );
-    vlc_mutex_destroy( &p_sys->p_thread->lock );
-    vlc_cond_destroy( &p_sys->p_thread->wait );
     vlc_object_detach( p_sys->p_thread );
 
-    while( p_sys->p_thread->i_blocks-- )
-    {
-        block_Release( p_sys->p_thread->pp_blocks[p_sys->p_thread->i_blocks] );
-    }
-
     vlc_object_destroy( p_sys->p_thread );
 
     free( p_sys );
index 925135469e48fa8a48c7a652620a67bba0ef87b9..738868d4647d8e3e770a74c1c0ab777703f30550 100644 (file)
 typedef struct
 {
     VLC_COMMON_MEMBERS
-    vout_thread_t *p_vout;
 
     char          *psz_title;
 
-    vlc_mutex_t   lock;
-    vlc_cond_t    wait;
-
     /* Audio properties */
-    int i_channels;
-
-    /* Audio samples queue */
-    block_t       *pp_blocks[MAX_BLOCKS];
-    int           i_blocks;
+    int           i_channels;
 
-    audio_date_t  date;
+    int16_t       p_data[2][512];
+    int           i_cur_sample;
 
     /* OS specific data */
     void          *p_os_data;
diff --git a/modules/visualization/galaktos/preset.c b/modules/visualization/galaktos/preset.c
new file mode 100644 (file)
index 0000000..76c1272
--- /dev/null
@@ -0,0 +1,1026 @@
+/*****************************************************************************
+ * preset.c:
+ *****************************************************************************
+ * Copyright (C) 2004 VideoLAN
+ * $Id$
+ *
+ * Authors: Cyril Deguet <asmax@videolan.org>
+ *          code from projectM http://xmms-projectm.sourceforge.net
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ *****************************************************************************/
+
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <dirent.h>
+#include <time.h>
+#include "common.h"
+#include "fatal.h"
+
+#include "preset_types.h"
+#include "preset.h"
+
+#include "parser.h"
+
+#include "expr_types.h"
+#include "eval.h"
+
+#include "splaytree_types.h"
+#include "splaytree.h"
+#include "tree_types.h"
+
+#include "per_frame_eqn_types.h"
+#include "per_frame_eqn.h"
+
+#include "per_pixel_eqn_types.h"
+#include "per_pixel_eqn.h"
+
+#include "init_cond_types.h"
+#include "init_cond.h"
+
+#include "param_types.h"
+#include "param.h"
+
+#include "func_types.h"
+#include "func.h"
+
+#include "custom_wave_types.h"
+#include "custom_wave.h"
+
+#include "custom_shape_types.h"
+#include "custom_shape.h"
+
+#include "idle_preset.h"
+
+/* The maximum number of preset names loaded into buffer */
+#define MAX_PRESETS_IN_DIR 50000
+extern int per_frame_eqn_count;
+extern int per_frame_init_eqn_count;
+//extern int custom_per_frame_eqn_count;
+
+extern splaytree_t * builtin_param_tree;
+
+preset_t * active_preset = NULL;
+preset_t * idle_preset = NULL;
+FILE * write_stream = NULL;
+
+
+int preset_index = -1;
+int preset_name_buffer_size = 0;
+splaytree_t * chrono_order_preset_name_tree = NULL;
+int get_preset_path(char ** preset_path_ptr, char * filepath, char * filename);
+preset_t * load_preset(char * pathname);
+int is_valid_extension(char * name);   
+int load_preset_file(char * pathname, preset_t * preset);
+int close_preset(preset_t * preset);
+
+int write_preset_name(FILE * fs);
+int write_per_pixel_equations(FILE * fs);
+int write_per_frame_equations(FILE * fs);
+int write_per_frame_init_equations(FILE * fs);
+int write_init_conditions(FILE * fs);
+void load_init_cond(param_t * param);
+void load_init_conditions();
+void write_init(init_cond_t * init_cond);
+int init_idle_preset();
+int destroy_idle_preset();
+void load_custom_wave_init_conditions();
+void load_custom_wave_init(custom_wave_t * custom_wave);
+
+void load_custom_shape_init_conditions();
+void load_custom_shape_init(custom_shape_t * custom_shape);
+
+/* loadPresetDir: opens the directory buffer
+   denoted by 'dir' to load presets */
+   
+int loadPresetDir(char * dir) {
+
+  struct dirent ** name_list;
+  char * preset_name;
+  int i, j, dir_size;
+  
+  if (dir == NULL)
+       return ERROR;
+  if (chrono_order_preset_name_tree != NULL) {
+       if (PRESET_DEBUG) printf("loadPresetDir: previous directory doesn't appear to be closed!\n");
+       /* Let this slide for now */
+  }    
+  
+  /* Scan the entire directory, storing each entry in a dirent struct array that needs 
+     to be freed later. For more information, consult scandir(3) in the man pages */
+  if ((dir_size = scandir(dir, &name_list, 0, alphasort)) < 0) {
+       if (PRESET_DEBUG) printf("loadPresetDir: failed to open directory \"%s\"\n", dir);
+       return ERROR;
+  }
+  
+  chrono_order_preset_name_tree = create_splaytree(compare_int, copy_int, free_int);
+  
+  /* Iterate through entire dirent name list, adding to the preset name list if it
+     is valid */  
+  for (i = 0; ((i < dir_size) && (i < MAX_PRESETS_IN_DIR));i++) {
+
+       /* Only perform the next set of operations if the preset name 
+          contains a valid extension */
+       if (is_valid_extension(name_list[i]->d_name)) {
+               
+               /* Handle the out of memory case. My guess is xmms would
+                  crash before this program would, but whatever...*/
+               if ((preset_name = (char*)malloc(MAX_PATH_SIZE)) == NULL) {
+                       if (PRESET_DEBUG) printf("loadPresetDir: out of memory! \n");
+                       
+                       /* Free the rest of the dirent name list */
+                       for (j = i; j < dir_size; j++) 
+                               free(name_list[j]);
+                       destroy_splaytree(chrono_order_preset_name_tree);
+                       return OUTOFMEM_ERROR;
+               }
+                               
+               /* Now create the full path */
+           if (get_preset_path(&preset_name, dir, name_list[i]->d_name) < 0) {
+                       if (PRESET_DEBUG) printf("loadPresetDir: failed to generate full preset path name!\n");
+                       
+                       /* Free the rest of the dirent name list */
+                       for (j = i; j < dir_size; j++) 
+                               free(name_list[j]);
+                       destroy_splaytree(chrono_order_preset_name_tree);
+                       return OUTOFMEM_ERROR;
+                       
+               }
+               
+               /* Insert the character string into the splay tree, with the key being its sequence number */
+               splay_insert(preset_name, &preset_name_buffer_size, chrono_order_preset_name_tree);
+               preset_name_buffer_size++;
+       }
+       
+       /* Free the dirent struct */
+       free(name_list[i]);
+       
+  }    
+  
+  free(name_list);
+  
+  /* No valid files in directory! */
+  if (chrono_order_preset_name_tree->root == NULL) {
+       if (PRESET_DEBUG) printf("loadPresetDir: no valid files in directory \"%s\"\n", dir);
+       destroy_splaytree(chrono_order_preset_name_tree);
+       chrono_order_preset_name_tree = NULL;
+       return FAILURE;   
+  }    
+         
+  /* Start the prefix index right before the first entry, so next preset
+     starts at the top of the list */
+  preset_index = -1;
+  
+  /* Start the first preset */
+
+  switchPreset(ALPHA_NEXT, HARD_CUT);
+  
+  return SUCCESS;
+}
+
+/* closePresetDir: closes the current
+   preset directory buffer */
+
+int closePresetDir() {
+
+  /* No preset director appears to be loaded */        
+  if (chrono_order_preset_name_tree == NULL) 
+    return SUCCESS;
+  
+  if (PRESET_DEBUG) {
+        printf("closePresetDir: freeing directory buffer...");
+        fflush(stdout);
+  }  
+  
+  /* Free each entry in the directory preset name tree */
+  splay_traverse(free_int, chrono_order_preset_name_tree);
+  
+  /* Destroy the chronological order splay tree */
+  destroy_splaytree(chrono_order_preset_name_tree);
+  chrono_order_preset_name_tree = NULL;
+  preset_name_buffer_size = 0;
+  if (PRESET_DEBUG) printf("finished\n");
+  
+  return SUCCESS;
+}
+
+
+
+/* Converts a preset file name to a full path */ 
+int get_preset_path(char ** preset_path_ptr, char * filepath, char * filename) {
+
+  char * preset_path;
+       
+  /* An insanely paranoid sequence of argument checks */
+  if (preset_path_ptr == NULL)
+       return ERROR;
+  if (*preset_path_ptr == NULL)
+    return ERROR;
+  if (filename == NULL)
+       return ERROR;
+  if (filepath == NULL)
+       return ERROR;
+  
+  /* Mostly here for looks */
+  preset_path = *preset_path_ptr;
+
+  /* Clear the name space first */
+  memset(preset_path, 0, MAX_PATH_SIZE);
+  
+  /* Now create the string "PATH/FILENAME", where path is either absolute or relative location
+     of the .milk file, and filename is the name of the preset file itself */
+  strcat(
+       strcat(
+               strncpy(
+                       preset_path, 
+                   filepath, 
+            MAX_PATH_SIZE-1),   
+        "/"), 
+    filename); 
+
+  return SUCCESS;
+}      
+
+/* switchPreset: loads the next preset from the directory stream.
+   loadPresetDir() must be called first. This is a
+   sequential load function */
+
+int switchPreset(switch_mode_t switch_mode, int cut_type) {
+
+  preset_t * new_preset;
+       
+  int switch_index;
+       
+  /* Make sure a preset directory list is in the buffer */
+  if (chrono_order_preset_name_tree == NULL) {
+    if (PRESET_DEBUG) printf("switchPreset: it helps if you open a directory first with a loadPresetDir() call\n");
+    return ERROR;
+  }
+  
+  
+  switch (switch_mode) {
+         
+  case ALPHA_NEXT:
+  /* An index variable that iterates through the directory
+     buffer, doing wrap around when it reaches the end of
+        the buffer */
+  
+  if (preset_index == (preset_name_buffer_size - 1))
+               switch_index = preset_index = 0;
+  else 
+               switch_index = ++preset_index;
+  break;
+
+  case ALPHA_PREVIOUS:
+         
+  if (preset_index == 0)
+               switch_index = preset_index = preset_name_buffer_size - 1;
+  else 
+               switch_index = --preset_index;
+  break;
+  
+  case RANDOM_NEXT:
+       switch_index = (int) (preset_name_buffer_size*(rand()/(RAND_MAX+1.0)));
+       break;
+  case RESTART_ACTIVE:
+       switch_index = preset_index;
+       break;
+  default:
+       return FAILURE;
+  }
+  
+    
+  /* Finally, load the preset using its actual path */
+  if ((new_preset = load_preset((char*)splay_find(&switch_index, chrono_order_preset_name_tree))) == NULL) {
+       if (PRESET_DEBUG) printf("switchPreset: failed to load preset\n");
+       return ERROR;
+  }
+
+  /* Closes a preset currently loaded, if any */
+  if ((active_preset != NULL) && (active_preset != idle_preset))
+    close_preset(active_preset);
+
+  /* Sets global active_preset pointer */
+  active_preset = new_preset;
+
+  /* Reinitialize the engine variables to sane defaults */
+  reset_engine_vars();
+
+  /* Add any missing initial conditions */
+  load_init_conditions();
+
+  /* Add any missing initial conditions for each wave */
+  load_custom_wave_init_conditions();
+
+/* Add any missing initial conditions for each shape */
+  load_custom_shape_init_conditions();
+
+  /* Need to evaluate the initial conditions once */
+  evalInitConditions();
+
+  //  evalInitPerFrameEquations();
+  return SUCCESS;
+}
+
+/* Loads a specific preset by absolute path */
+int loadPresetByFile(char * filename) {
+
+  preset_t * new_preset;
+  /* Finally, load the preset using its actual path */
+  if ((new_preset = load_preset(filename)) == NULL) {
+       if (PRESET_DEBUG) printf("loadPresetByFile: failed to load preset!\n");
+       return ERROR;     
+  }
+
+  /* Closes a preset currently loaded, if any */
+  if ((active_preset != NULL) && (active_preset != idle_preset))
+    close_preset(active_preset); 
+
+  /* Sets active preset global pointer */
+  active_preset = new_preset;
+
+  /* Reinitialize engine variables */
+  reset_engine_vars();
+
+  /* Add any missing initial conditions for each wave */
+  load_custom_wave_init_conditions();
+
+ /* Add any missing initial conditions for each wave */
+  load_custom_shape_init_conditions();
+
+  /* Add any missing initial conditions */
+  load_init_conditions();
+  
+  /* Need to do this once for menu */
+  evalInitConditions();
+  //  evalPerFrameInitEquations();
+  return SUCCESS;
+
+}
+
+int init_idle_preset() {
+
+  preset_t * preset;
+  int i;
+
+    /* Initialize idle preset struct */
+  if ((preset = (preset_t*)malloc(sizeof(preset_t))) == NULL)
+    return FAILURE;
+
+  
+  strncpy(preset->name, "idlepreset", strlen("idlepreset"));
+
+  /* Initialize equation trees */
+  preset->init_cond_tree = create_splaytree(compare_string, copy_string, free_string);
+  preset->user_param_tree = create_splaytree(compare_string, copy_string, free_string);
+  preset->per_frame_eqn_tree = create_splaytree(compare_int, copy_int, free_int);
+  preset->per_pixel_eqn_tree = create_splaytree(compare_int, copy_int, free_int);
+  preset->per_frame_init_eqn_tree = create_splaytree(compare_string, copy_string, free_string);
+  preset->custom_wave_tree = create_splaytree(compare_int, copy_int, free_int);
+  preset->custom_shape_tree = create_splaytree(compare_int, copy_int, free_int);
+  /* Set file path to dummy name */  
+  strncpy(preset->file_path, "IDLE PRESET", MAX_PATH_SIZE-1);
+  
+  /* Set initial index values */
+  preset->per_pixel_eqn_string_index = 0;
+  preset->per_frame_eqn_string_index = 0;
+  preset->per_frame_init_eqn_string_index = 0;
+  memset(preset->per_pixel_flag, 0, sizeof(int)*NUM_OPS);
+  
+  /* Clear string buffers */
+  memset(preset->per_pixel_eqn_string_buffer, 0, STRING_BUFFER_SIZE);
+  memset(preset->per_frame_eqn_string_buffer, 0, STRING_BUFFER_SIZE);
+  memset(preset->per_frame_init_eqn_string_buffer, 0, STRING_BUFFER_SIZE);
+
+  idle_preset = preset;
+  
+  return SUCCESS;
+}
+
+int destroy_idle_preset() {
+
+  return close_preset(idle_preset);
+  
+}
+
+/* initPresetLoader: initializes the preset
+   loading library. this should be done before
+   any parsing */
+int initPresetLoader() {
+
+  /* Initializes the builtin parameter database */
+  init_builtin_param_db();
+
+  /* Initializes the builtin function database */
+  init_builtin_func_db();
+       
+  /* Initializes all infix operators */
+  init_infix_ops();
+
+  /* Set the seed to the current time in seconds */
+  srand(time(NULL));
+
+  /* Initialize the 'idle' preset */
+  init_idle_preset();
+
+
+  reset_engine_vars();
+
+  active_preset = idle_preset;
+  load_init_conditions();
+
+  /* Done */
+  if (PRESET_DEBUG) printf("initPresetLoader: finished\n");
+  return SUCCESS;
+}
+
+/* Sort of experimental code here. This switches
+   to a hard coded preset. Useful if preset directory
+   was not properly loaded, or a preset fails to parse */
+
+void switchToIdlePreset() {
+
+
+  /* Idle Preset already activated */
+  if (active_preset == idle_preset)
+    return;
+
+
+  /* Close active preset */
+  if (active_preset != NULL)
+    close_preset(active_preset);
+
+  /* Sets global active_preset pointer */
+  active_preset = idle_preset;
+
+  /* Reinitialize the engine variables to sane defaults */
+  reset_engine_vars();
+
+  /* Add any missing initial conditions */
+  load_init_conditions();
+
+  /* Need to evaluate the initial conditions once */
+  evalInitConditions();
+
+}
+
+/* destroyPresetLoader: closes the preset
+   loading library. This should be done when 
+   projectM does cleanup */
+
+int destroyPresetLoader() {
+  
+  if ((active_preset != NULL) && (active_preset != idle_preset)) {     
+       close_preset(active_preset);      
+  }    
+
+  active_preset = NULL;
+  
+  destroy_idle_preset();
+  destroy_builtin_param_db();
+  destroy_builtin_func_db();
+  destroy_infix_ops();
+
+  return SUCCESS;
+
+}
+
+/* load_preset_file: private function that loads a specific preset denoted
+   by the given pathname */
+int load_preset_file(char * pathname, preset_t * preset) { 
+  FILE * fs;
+  int retval;
+
+  if (pathname == NULL)
+         return FAILURE;
+  if (preset == NULL)
+         return FAILURE;
+  
+  /* Open the file corresponding to pathname */
+  if ((fs = fopen(pathname, "r")) == 0) {
+    if (PRESET_DEBUG) printf("load_preset_file: loading of file %s failed!\n", pathname);
+    return ERROR;      
+  }
+
+  if (PRESET_DEBUG) printf("load_preset_file: file stream \"%s\" opened successfully\n", pathname);
+
+  /* Parse any comments */
+  if (parse_top_comment(fs) < 0) {
+    if (PRESET_DEBUG) printf("load_preset_file: no left bracket found...\n");
+    fclose(fs);
+    return FAILURE;
+  }
+  
+  /* Parse the preset name and a left bracket */
+  if (parse_preset_name(fs, preset->name) < 0) {
+    if (PRESET_DEBUG) printf("load_preset_file: loading of preset name in file \"%s\" failed\n", pathname);
+    fclose(fs);
+    return ERROR;
+  }
+  
+  if (PRESET_DEBUG) printf("load_preset_file: preset \"%s\" parsed\n", preset->name);
+
+  /* Parse each line until end of file */
+  if (PRESET_DEBUG) printf("load_preset_file: beginning line parsing...\n");
+  while ((retval = parse_line(fs, preset)) != EOF) {
+    if (retval == PARSE_ERROR) {
+      if (PRESET_DEBUG > 1) printf("load_preset_file: parse error in file \"%s\"\n", pathname);
+    }
+  }
+  
+  if (PRESET_DEBUG) printf("load_preset_file: finished line parsing successfully\n"); 
+
+  /* Now the preset has been loaded.
+     Evaluation calls can be made at appropiate
+     times in the frame loop */
+  
+  fclose(fs);
+   
+  if (PRESET_DEBUG) printf("load_preset_file: file \"%s\" closed, preset ready\n", pathname);
+  return SUCCESS;
+  
+}
+
+void evalInitConditions() {
+  splay_traverse(eval_init_cond, active_preset->init_cond_tree);
+  splay_traverse(eval_init_cond, active_preset->per_frame_init_eqn_tree);
+}
+
+void evalPerFrameEquations() {
+  splay_traverse(eval_per_frame_eqn, active_preset->per_frame_eqn_tree);
+}
+
+void evalPerFrameInitEquations() {
+  //printf("evalPerFrameInitEquations: per frame init unimplemented!\n");
+  //  splay_traverse(eval_per_frame_eqn, active_preset->per_frame_init_eqn_tree);
+}      
+
+/* Returns nonzero if string 'name' contains .milk or
+   (the better) .prjm extension. Not a very strong function currently */
+int is_valid_extension(char * name) {
+
+       if (PRESET_DEBUG > 1) {
+               printf("is_valid_extension: scanning string \"%s\"...", name);
+               fflush(stdout);
+       }
+
+       if (strstr(name, MILKDROP_FILE_EXTENSION)) {
+                       if (PRESET_DEBUG > 1) printf("\".milk\" extension found in string [true]\n");
+                       return TRUE;
+       }       
+       
+       if (strstr(name, PROJECTM_FILE_EXTENSION)) {
+                   if (PRESET_DEBUG > 1) printf("\".prjm\" extension found in string [true]\n");
+                       return TRUE;
+       }
+        
+       if (PRESET_DEBUG > 1) printf("no valid extension found [false]\n");
+       return FALSE;
+}
+
+/* Private function to close a preset file */
+int close_preset(preset_t * preset) {
+
+  if (preset == NULL)
+    return FAILURE;
+
+
+  splay_traverse(free_init_cond, preset->init_cond_tree);
+  destroy_splaytree(preset->init_cond_tree);
+  
+  splay_traverse(free_init_cond, preset->per_frame_init_eqn_tree);
+  destroy_splaytree(preset->per_frame_init_eqn_tree);
+  
+  splay_traverse(free_per_pixel_eqn, preset->per_pixel_eqn_tree);
+  destroy_splaytree(preset->per_pixel_eqn_tree);
+  
+  splay_traverse(free_per_frame_eqn, preset->per_frame_eqn_tree);
+  destroy_splaytree(preset->per_frame_eqn_tree);
+  
+  splay_traverse(free_param, preset->user_param_tree);
+  destroy_splaytree(preset->user_param_tree);
+  
+  splay_traverse(free_custom_wave, preset->custom_wave_tree);
+  destroy_splaytree(preset->custom_wave_tree);
+
+  splay_traverse(free_custom_shape, preset->custom_shape_tree);
+  destroy_splaytree(preset->custom_shape_tree);
+
+  free(preset); 
+  
+  return SUCCESS;
+
+}
+
+void reloadPerPixel(char *s, preset_t * preset) {
+  
+  FILE * fs;
+  int slen;
+  char c;
+  int i;
+
+  if (s == NULL)
+    return;
+
+  if (preset == NULL)
+    return;
+
+  /* Clear previous per pixel equations */
+  splay_traverse(free_per_pixel_eqn, preset->per_pixel_eqn_tree);
+  destroy_splaytree(preset->per_pixel_eqn_tree);
+  preset->per_pixel_eqn_tree = create_splaytree(compare_int, copy_int, free_int);
+
+  /* Convert string to a stream */
+  fs = fmemopen (s, strlen(s), "r");
+
+  while ((c = fgetc(fs)) != EOF) {
+    ungetc(c, fs);
+    parse_per_pixel_eqn(fs, preset);
+  }
+
+  fclose(fs);
+
+  /* Clear string space */
+  memset(preset->per_pixel_eqn_string_buffer, 0, STRING_BUFFER_SIZE);
+
+  /* Compute length of string */
+  slen = strlen(s);
+
+  /* Copy new string into buffer */
+  strncpy(preset->per_pixel_eqn_string_buffer, s, slen);
+
+  /* Yet again no bounds checking */
+  preset->per_pixel_eqn_string_index = slen;
+
+  /* Finished */
+  return;
+}
+
+/* Obviously unwritten */
+void reloadPerFrameInit(char *s, preset_t * preset) {
+
+}
+
+void reloadPerFrame(char * s, preset_t * preset) {
+
+  FILE * fs;
+  int slen;
+  char c;
+  int eqn_count = 1;
+  per_frame_eqn_t * per_frame;
+
+  if (s == NULL)
+    return;
+
+  if (preset == NULL)
+    return;
+
+  /* Clear previous per frame equations */
+  splay_traverse(free_per_frame_eqn, preset->per_frame_eqn_tree);
+  destroy_splaytree(preset->per_frame_eqn_tree);
+  preset->per_frame_eqn_tree = create_splaytree(compare_int, copy_int, free_int);
+
+  /* Convert string to a stream */
+  fs = fmemopen (s, strlen(s), "r");
+
+  while ((c = fgetc(fs)) != EOF) {
+    ungetc(c, fs);
+    if ((per_frame = parse_per_frame_eqn(fs, eqn_count, preset)) != NULL) {
+      splay_insert(per_frame, &eqn_count, preset->per_frame_eqn_tree);
+      eqn_count++;
+    }
+  }
+
+  fclose(fs);
+
+  /* Clear string space */
+  memset(preset->per_frame_eqn_string_buffer, 0, STRING_BUFFER_SIZE);
+
+  /* Compute length of string */
+  slen = strlen(s);
+
+  /* Copy new string into buffer */
+  strncpy(preset->per_frame_eqn_string_buffer, s, slen);
+
+  /* Yet again no bounds checking */
+  preset->per_frame_eqn_string_index = slen;
+
+  /* Finished */
+  printf("reloadPerFrame: %d eqns parsed succesfully\n", eqn_count-1);
+  return;
+
+}
+
+preset_t * load_preset(char * pathname) {
+
+  preset_t * preset;
+  int i;
+
+  /* Initialize preset struct */
+  if ((preset = (preset_t*)malloc(sizeof(preset_t))) == NULL)
+    return NULL;
+   
+  /* Initialize equation trees */
+  preset->init_cond_tree = create_splaytree(compare_string, copy_string, free_string);
+  preset->user_param_tree = create_splaytree(compare_string, copy_string, free_string);
+  preset->per_frame_eqn_tree = create_splaytree(compare_int, copy_int, free_int);
+  preset->per_pixel_eqn_tree = create_splaytree(compare_int, copy_int, free_int);
+  preset->per_frame_init_eqn_tree = create_splaytree(compare_string, copy_string, free_string);
+  preset->custom_wave_tree = create_splaytree(compare_int, copy_int, free_int);
+  preset->custom_shape_tree = create_splaytree(compare_int, copy_int, free_int);
+
+  memset(preset->per_pixel_flag, 0, sizeof(int)*NUM_OPS);
+
+  /* Copy file path */  
+  strncpy(preset->file_path, pathname, MAX_PATH_SIZE-1);
+  
+  /* Set initial index values */
+  preset->per_pixel_eqn_string_index = 0;
+  preset->per_frame_eqn_string_index = 0;
+  preset->per_frame_init_eqn_string_index = 0;
+  
+  
+  /* Clear string buffers */
+  memset(preset->per_pixel_eqn_string_buffer, 0, STRING_BUFFER_SIZE);
+  memset(preset->per_frame_eqn_string_buffer, 0, STRING_BUFFER_SIZE);
+  memset(preset->per_frame_init_eqn_string_buffer, 0, STRING_BUFFER_SIZE);
+  
+  
+  if (load_preset_file(pathname, preset) < 0) {
+       if (PRESET_DEBUG) printf("load_preset: failed to load file \"%s\"\n", pathname);
+       close_preset(preset);
+       return NULL;
+  }
+
+  /* It's kind of ugly to reset these values here. Should definitely be placed in the parser somewhere */
+  per_frame_eqn_count = 0;
+  per_frame_init_eqn_count = 0;
+
+  /* Finished, return new preset */
+  return preset;
+}
+
+void savePreset(char * filename) {
+
+  FILE * fs;
+
+  if (filename == NULL)
+    return;
+  
+  /* Open the file corresponding to pathname */
+  if ((fs = fopen(filename, "w+")) == 0) {
+    if (PRESET_DEBUG) printf("savePreset: failed to create filename \"%s\"!\n", filename);
+    return;    
+  }
+
+  write_stream = fs;
+
+  if (write_preset_name(fs) < 0) {
+    write_stream = NULL;
+    fclose(fs);
+    return;
+  }
+
+  if (write_init_conditions(fs) < 0) {
+    write_stream = NULL;
+    fclose(fs);
+    return;
+  }
+
+  if (write_per_frame_init_equations(fs) < 0) {
+    write_stream = NULL;
+    fclose(fs);
+    return;
+  }
+
+  if (write_per_frame_equations(fs) < 0) {
+    write_stream = NULL;
+    fclose(fs);
+    return;
+  }
+
+  if (write_per_pixel_equations(fs) < 0) {
+    write_stream = NULL;
+    fclose(fs);
+    return;
+  }
+  write_stream = NULL;
+  fclose(fs);
+
+}
+
+int write_preset_name(FILE * fs) {
+
+  char s[256];
+  int len;
+
+  memset(s, 0, 256);
+
+  if (fs == NULL)
+    return FAILURE;
+
+  /* Format the preset name in a string */
+  sprintf(s, "[%s]\n", active_preset->name);
+
+  len = strlen(s);
+
+  /* Write preset name to file stream */
+  if (fwrite(s, 1, len, fs) != len)
+    return FAILURE;
+
+  return SUCCESS;
+
+}
+
+int write_init_conditions(FILE * fs) {
+
+  if (fs == NULL)
+    return FAILURE;
+  if (active_preset == NULL)
+    return FAILURE;
+
+
+  splay_traverse(write_init, active_preset->init_cond_tree);
+  
+  return SUCCESS;
+}
+
+void write_init(init_cond_t * init_cond) {
+
+  char s[512];
+  int len;
+
+  if (write_stream == NULL)
+    return;
+
+  memset(s, 0, 512);
+
+  if (init_cond->param->type == P_TYPE_BOOL)
+    sprintf(s, "%s=%d\n", init_cond->param->name, init_cond->init_val.bool_val);
+
+  else if (init_cond->param->type == P_TYPE_INT)    
+    sprintf(s, "%s=%d\n", init_cond->param->name, init_cond->init_val.int_val);
+
+  else if (init_cond->param->type == P_TYPE_DOUBLE)
+    sprintf(s, "%s=%f\n", init_cond->param->name, init_cond->init_val.double_val);
+
+  else { printf("write_init: unknown parameter type!\n"); return; }
+  
+  len = strlen(s);
+
+  if ((fwrite(s, 1, len, write_stream)) != len)
+    printf("write_init: failed writing to file stream! Out of disk space?\n");
+  
+}
+
+
+int write_per_frame_init_equations(FILE * fs) {
+
+  int len;
+
+  if (fs == NULL)
+    return FAILURE;
+  if (active_preset == NULL)
+    return FAILURE;
+  
+  len = strlen(active_preset->per_frame_init_eqn_string_buffer);
+
+  if (fwrite(active_preset->per_frame_init_eqn_string_buffer, 1, len, fs) != len)
+    return FAILURE;
+
+  return SUCCESS;
+}
+
+
+int write_per_frame_equations(FILE * fs) {
+
+  int len;
+
+  if (fs == NULL)
+    return FAILURE;
+  if (active_preset == NULL)
+    return FAILURE;
+
+  len = strlen(active_preset->per_frame_eqn_string_buffer);
+
+  if (fwrite(active_preset->per_frame_eqn_string_buffer, 1, len, fs) != len)
+    return FAILURE;
+
+  return SUCCESS;
+}
+
+
+int write_per_pixel_equations(FILE * fs) {
+
+  int len;
+
+  if (fs == NULL)
+    return FAILURE;
+  if (active_preset == NULL)
+    return FAILURE;
+
+  len = strlen(active_preset->per_pixel_eqn_string_buffer);
+
+  if (fwrite(active_preset->per_pixel_eqn_string_buffer, 1, len, fs) != len)
+    return FAILURE;
+
+  return SUCCESS;
+}
+
+
+void load_init_conditions() {
+
+  splay_traverse(load_init_cond, builtin_param_tree);
+
+}
+
+void load_init_cond(param_t * param) {
+
+  init_cond_t * init_cond;
+  value_t init_val;
+
+  /* Don't count read only parameters as initial conditions */
+  if (param->flags & P_FLAG_READONLY)
+    return;
+
+  /* If initial condition was not defined by the preset file, force a default one
+     with the following code */
+  if ((init_cond = splay_find(param->name, active_preset->init_cond_tree)) == NULL) {
+    
+    /* Make sure initial condition does not exist in the set of per frame initial equations */
+    if ((init_cond = splay_find(param->name, active_preset->per_frame_init_eqn_tree)) != NULL)
+      return;
+    
+    if (param->type == P_TYPE_BOOL)
+      init_val.bool_val = 0;
+    
+    else if (param->type == P_TYPE_INT)
+      init_val.int_val = *(int*)param->engine_val;
+
+    else if (param->type == P_TYPE_DOUBLE)
+      init_val.double_val = *(double*)param->engine_val;
+
+    //printf("%s\n", param->name);
+    /* Create new initial condition */
+    if ((init_cond = new_init_cond(param, init_val)) == NULL)
+      return;
+    
+    /* Insert the initial condition into this presets tree */
+    if (splay_insert(init_cond, init_cond->param->name, active_preset->init_cond_tree) < 0) {
+      free_init_cond(init_cond);
+      return;
+    }
+    
+  }
+}
+
+void load_custom_wave_init_conditions() {
+
+  splay_traverse(load_custom_wave_init, active_preset->custom_wave_tree);
+
+}
+
+void load_custom_wave_init(custom_wave_t * custom_wave) {
+
+  load_unspecified_init_conds(custom_wave);
+
+}
+
+
+void load_custom_shape_init_conditions() {
+
+  splay_traverse(load_custom_shape_init, active_preset->custom_shape_tree);
+
+}
+
+void load_custom_shape_init(custom_shape_t * custom_shape) {
+  load_unspecified_init_conds_shape(custom_shape);
+}
diff --git a/modules/visualization/galaktos/preset.h b/modules/visualization/galaktos/preset.h
new file mode 100644 (file)
index 0000000..0c6b1c4
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef PRESET_H
+#define PRESET_H
+#define PRESET_DEBUG 0 /* 0 for no debugging, 1 for normal, 2 for insane */
+
+#define HARD_CUT 0
+#define SOFT_CUT 1
+#include "preset_types.h"
+
+void evalInitConditions();
+void evalPerFrameEquations();
+void evalPerFrameInitEquations();
+
+int switchPreset(switch_mode_t switch_mode, int cut_type);
+void switchToIdlePreset();
+int loadPresetDir(char * dir);
+int closePresetDir();
+int initPresetLoader();
+int destroyPresetLoader();
+int loadPresetByFile(char * filename);
+void reloadPerFrame(char * s, preset_t * preset);
+void reloadPerFrameInit(char *s, preset_t * preset);
+void reloadPerPixel(char *s, preset_t * preset);
+void savePreset(char * name);
+
+
+#endif
diff --git a/modules/visualization/galaktos/preset_types.h b/modules/visualization/galaktos/preset_types.h
new file mode 100644 (file)
index 0000000..06cfa89
--- /dev/null
@@ -0,0 +1,41 @@
+#ifndef PRESET_TYPES_H
+#define PRESET_TYPES_H
+
+#include "splaytree_types.h"
+#include "expr_types.h"
+#include "per_pixel_eqn_types.h"
+
+typedef enum { 
+  ALPHA_NEXT,
+  ALPHA_PREVIOUS,
+  RANDOM_NEXT,
+  RESTART_ACTIVE,
+} switch_mode_t;
+
+typedef struct PRESET_T {
+  
+  char name[MAX_TOKEN_SIZE]; /* preset name as parsed in file */
+  char file_path[MAX_PATH_SIZE]; /* Points to the preset file name */
+  
+  int per_pixel_eqn_string_index;
+  int per_frame_eqn_string_index;
+  int per_frame_init_eqn_string_index;
+       
+  int per_pixel_flag[NUM_OPS];
+  char per_pixel_eqn_string_buffer[STRING_BUFFER_SIZE];
+  char per_frame_eqn_string_buffer[STRING_BUFFER_SIZE];
+  char per_frame_init_eqn_string_buffer[STRING_BUFFER_SIZE];
+
+  /* Data structures that contain equation and initial condition information */
+  splaytree_t * per_frame_eqn_tree;   /* per frame equations */
+  splaytree_t * per_pixel_eqn_tree; /* per pixel equation tree */
+  gen_expr_t * per_pixel_eqn_array[NUM_OPS]; /* per pixel equation array */
+  splaytree_t * per_frame_init_eqn_tree; /* per frame initial equations */
+  splaytree_t * init_cond_tree; /* initial conditions */
+  splaytree_t * user_param_tree; /* user parameter splay tree */
+
+  splaytree_t * custom_wave_tree; /* custom wave forms for this preset */
+  splaytree_t * custom_shape_tree; /* custom shapes for this preset */
+
+} preset_t;
+#endif
diff --git a/modules/visualization/galaktos/splaytree.c b/modules/visualization/galaktos/splaytree.c
new file mode 100644 (file)
index 0000000..b214cc0
--- /dev/null
@@ -0,0 +1,703 @@
+/*****************************************************************************
+ * splaytree.c:
+ *****************************************************************************
+ * Copyright (C) 2004 VideoLAN
+ * $Id$
+ *
+ * Authors: Cyril Deguet <asmax@videolan.org>
+ *          code from projectM http://xmms-projectm.sourceforge.net
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ *****************************************************************************/
+
+
+
+/*
+                An implementation of top-down splaying
+                    D. Sleator <sleator@cs.cmu.edu>
+                            March 1992
+
+  "Splay trees", or "self-adjusting search trees" are a simple and
+  efficient data structure for storing an ordered set.  The data
+  structure consists of a binary tree, without parent pointers, and no
+  additional fields.  It allows searching, insertion, deletion,
+  deletemin, deletemax, splitting, joining, and many other operations,
+  all with amortized logarithmic performance.  Since the trees adapt to
+  the sequence of requests, their performance on real access patterns is
+  typically even better.  Splay trees are described in a number of texts
+  and papers [1,2,3,4,5].
+
+  The code here is adapted from simple top-down splay, at the bottom of
+  page 669 of [3].  It can be obtained via anonymous ftp from
+  spade.pc.cs.cmu.edu in directory /usr/sleator/public.
+
+  The chief modification here is that the splay operation works even if the
+  item being splayed is not in the tree, and even if the tree root of the
+  tree is NULL.  So the line:
+
+                              t = splay(i, t);
+
+  causes it to search for item with key i in the tree rooted at t.  If it's
+  there, it is splayed to the root.  If it isn't there, then the node put
+  at the root is the last one before NULL that would have been reached in a
+  normal binary search for i.  (It's a neighbor of i in the tree.)  This
+  allows many other operations to be easily implemented, as shown below.
+
+  [1] "Fundamentals of data structures in C", Horowitz, Sahni,
+       and Anderson-Freed, Computer Science Press, pp 542-547.
+
+  [2] "Data Structures and Their Algorithms", Lewis and Denenberg,
+       Harper Collins, 1991, pp 243-251.
+  [3] "Self-adjusting Binary Search Trees" Sleator and Tarjan,
+       JACM Volume 32, No 3, July 1985, pp 652-686.
+  [4] "Data Structure and Algorithm Analysis", Mark Weiss,
+       Benjamin Cummins, 1992, pp 119-130.
+  [5] "Data Structures, Algorithms, and Performance", Derick Wood,
+       Addison-Wesley, 1993, pp 367-375.
+
+  The following code was written by Daniel Sleator, and is released
+  in the public domain. It has been heavily modified by Carmelo Piccione,
+  (cep@andrew.cmu.edu), to suit personal needs, 
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "common.h"
+#include "fatal.h"
+
+#include "splaytree_types.h"
+#include "splaytree.h"
+
+
+
+static inline splaynode_t * splay (void * key, splaynode_t * t, int * match_type, int (*compare)());
+static inline int free_splaynode(splaynode_t * splaynode, void (*free_key)());
+static inline void splay_traverse_helper (void (*func_ptr)(), splaynode_t * splaynode);
+static inline splaynode_t * splay_delete_helper(void * key, splaynode_t * t, int (*compare)(), void (*free_key)());
+static inline void splay_find_above_min_helper(void * max_key, void ** closest_key, splaynode_t * root, int (*compare)());
+static inline void splay_find_below_max_helper(void * max_key, void ** closest_key, splaynode_t * root, int (*compare)());
+static inline splaynode_t * new_splaynode(int type, void * key, void * data);
+static inline int splay_insert_node(splaynode_t * splaynode, splaytree_t * splaytree);
+static inline int splay_rec_size(splaynode_t * splaynode);
+
+/* Creates a splay tree given a compare key function, copy key function, and free key function.
+   Ah yes, the wonders of procedural programming */
+inline splaytree_t * create_splaytree(int (*compare)(), void * (*copy_key)(), void (*free_key)()) {
+
+  splaytree_t * splaytree;
+
+  /* Allocate memory for the splaytree struct */
+  if ((splaytree = (splaytree_t*)malloc(sizeof(splaytree_t))) == NULL)
+    return NULL;
+
+  /* Set struct entries */
+  splaytree->root = NULL;
+  splaytree->compare = compare;
+  splaytree->copy_key = copy_key;
+  splaytree->free_key = free_key;
+  
+  /* Return instantiated splay tree */
+  return splaytree;
+}
+
+/* Destroys a splay tree */
+inline int destroy_splaytree(splaytree_t * splaytree) {
+
+  /* Null argument check */
+  if (splaytree == NULL)
+    return FAILURE;
+
+  /* Recursively free all splaynodes in tree */
+  free_splaynode(splaytree->root, splaytree->free_key);
+
+  /* Free the splaytree struct itself */
+  free(splaytree);
+  
+  /* Done, return success */
+  return SUCCESS;
+
+}
+
+/* Recursively free all the splaynodes */
+static inline int free_splaynode(splaynode_t * splaynode, void (*free_key)()) {
+
+  /* Ok if this happens, a recursive base case */
+  if (splaynode == NULL)
+    return SUCCESS;
+
+  /* Free left node */
+  free_splaynode(splaynode->left, free_key);
+  
+  /* Free right node */
+  free_splaynode(splaynode->right, free_key);
+  
+  /* Free this node's key */
+  free_key(splaynode->key);
+  
+  /* Note that the data pointers are not freed here.
+     Should be freed with a splay traversal function */
+  
+  /* Free the splaynode structure itself */
+  free(splaynode);
+  /* Finished, return success */
+  return SUCCESS;
+
+}
+
+/* Traverses the entire splay tree with the given function func_ptr */
+inline void splay_traverse(void (*func_ptr)(), splaytree_t * splaytree) {
+
+  /* Null argument check */
+
+  if (splaytree == NULL)
+    return; 
+  if (func_ptr == NULL)
+       return;
+  
+  /* Call recursive helper function */
+  splay_traverse_helper(func_ptr, splaytree->root);
+
+  return;
+}
+
+/* Helper function to traverse the entire splaytree */
+static inline void splay_traverse_helper (void (*func_ptr)(), splaynode_t * splaynode) {  
+
+  /* Normal if this happens, its a base case of recursion */
+  if (splaynode == NULL)
+    return;
+
+  /* Recursively traverse to the left */
+  splay_traverse_helper(func_ptr, splaynode->left);
+  
+  
+  /* Node is a of regular type, so its ok to perform the function on it */
+  if (splaynode->type == REGULAR_NODE_TYPE)
+       func_ptr(splaynode->data);
+  
+  /* Node is of symbolic link type, do nothing */
+  else if (splaynode->type == SYMBOLIC_NODE_TYPE)
+       ;
+  
+  /* Unknown node type */
+  else
+    ;
+  
+  /* Recursively traverse to the right */
+  splay_traverse_helper(func_ptr, splaynode->right);
+
+  /* Done */
+  return;
+}
+
+/* Find the node corresponding to the given key in splaytree, return its data pointer */
+inline void * splay_find(void * key, splaytree_t * splaytree) {
+
+  splaynode_t * splaynode;
+  int match_type;
+
+  if (key == NULL)
+         return NULL;
+  
+  if (splaytree == NULL)
+         return NULL;
+  
+  splaynode = splaytree->root;
+  
+  /* Bring the targeted splay node to the top of the splaytree */
+  splaynode = splay(key, splaynode, &match_type, splaytree->compare);
+  splaytree->root = splaynode;
+  
+  
+  /* We only want perfect matches, so return null when match isn't perfect */
+  if (match_type == CLOSEST_MATCH) 
+    return NULL;
+
+  /* This shouldn't happen because of the match type check, but whatever */
+  if (splaytree->root == NULL)
+         return NULL;
+  
+  /* Node is a regular type, return its data pointer */
+  if (splaytree->root->type == REGULAR_NODE_TYPE) /* regular node */
+       return splaytree->root->data;
+  
+  /* If the node is a symlink, pursue one link */
+  if (splaytree->root->type == SYMBOLIC_NODE_TYPE) /* symbolic node */
+       return ((splaynode_t*)splaytree->root->data)->data;
+    
+  
+  /* Unknown type */
+  return NULL;
+}
+
+/* Gets the splaynode that the given key points to */
+inline splaynode_t * get_splaynode_of(void * key, splaytree_t * splaytree) {
+
+  splaynode_t * splaynode;
+  int match_type;
+  
+  /* Null argument checks */   
+  if (splaytree == NULL)
+         return NULL;
+  
+  if (key == NULL)
+         return NULL;
+  
+  splaynode = splaytree->root;
+
+  /* Find the splaynode */
+  splaynode = splay(key, splaynode, &match_type, splaytree->compare);
+  splaytree->root = splaynode;
+  /* Only perfect matches are valid */
+  if (match_type == CLOSEST_MATCH)
+    return NULL;
+
+  /* Return the perfect match splay node */
+  return splaynode;
+}
+
+/* Finds the desired node, and changes the tree such that it is the root */
+static inline splaynode_t * splay (void * key, splaynode_t * t, int * match_type, int (*compare)()) {
+  
+/* Simple top down splay, not requiring key to be in the tree t. 
+   What it does is described above. */
+    splaynode_t N, *l, *r, *y;
+    *match_type = CLOSEST_MATCH;
+  
+       if (t == NULL) return t;
+    N.left = N.right = NULL;
+    l = r = &N;
+  
+    for (;;) {
+       if (compare(key, t->key) < 0) {
+           if (t->left == NULL) break;
+           if (compare(key, t->left->key) < 0) {
+               y = t->left;                           /* rotate right */
+               t->left = y->right;
+               y->right = t;
+               t = y;
+               if (t->left == NULL) break;
+           }
+           r->left = t;                               /* link right */
+           r = t;
+           t = t->left;
+       } else if (compare(key, t->key) > 0) {
+           if (t->right == NULL) break;
+           if (compare(key, t->right->key) > 0) {
+               y = t->right;                          /* rotate left */
+               t->right = y->left;
+               y->left = t;
+               t = y;
+               if (t->right == NULL) break;
+           }
+           l->right = t;                              /* link left */
+           l = t;
+           t = t->right;
+       } else {
+         *match_type = PERFECT_MATCH;
+         break;
+       }
+    }
+    l->right = t->left;                                /* assemble */
+    r->left = t->right;
+    t->left = N.right;
+    t->right = N.left;
+    
+    return t;
+
+    //return NULL;
+}
+
+/* Deletes a splay node from a splay tree. If the node doesn't exist
+   then nothing happens */
+inline int splay_delete(void * key, splaytree_t * splaytree) {
+  
+  splaynode_t * splaynode;
+
+  /* Use helper function to delete the node and return the resulting tree */
+  if ((splaynode = splay_delete_helper(key, splaytree->root, splaytree->compare, splaytree->free_key)) == NULL)
+         return FAILURE;
+  
+  /* Set new splaytree root equal to the returned splaynode after deletion */
+  splaytree->root = splaynode;
+  
+  /* Finished, no errors */
+  return SUCCESS;
+}
+
+/* Deletes a splay node */
+static inline splaynode_t * splay_delete_helper(void * key, splaynode_t * splaynode, int (*compare)(), void (*free_key)()) {
+       
+    splaynode_t * new_root;
+    int match_type;
+       
+       /* Argument check */    
+    if (splaynode == NULL) 
+               return NULL;
+       
+    splaynode = splay(key, splaynode, &match_type, compare);
+       
+       /* If entry wasn't found, quit here */
+       if (match_type == CLOSEST_MATCH) 
+               return NULL;
+       
+       /* If the targeted node's left pointer is null, then set the new root
+          equal to the splaynode's right child */
+       if (splaynode->left == NULL) {
+           new_root = splaynode->right;
+       } 
+       
+       /* Otherwise, do something I don't currently understand */
+       else {
+           new_root = splay(key, splaynode->left, &match_type, compare);
+           new_root->right = splaynode->right;
+       }
+
+       /* Set splay nodes children pointers to null */
+       splaynode->left = splaynode->right = NULL;
+       
+       /* Free the splaynode (and only this node since its children are now empty */
+       free_splaynode(splaynode, free_key);
+       
+       /* Return the resulting tree */
+       return new_root;
+       
+}
+
+/* Create a new splay node type */
+static inline splaynode_t * new_splaynode(int type, void * key, void * data) {
+       splaynode_t * splaynode;        
+       /* Argument checks */
+       if (data == NULL)
+               return NULL;
+       
+       if (key == NULL)
+               return NULL;
+       
+       /* Creates the new splay node struct */
+       if ((splaynode = (splaynode_t*)malloc(sizeof(splaynode_t))) == NULL)
+               return NULL;
+       
+       splaynode->data = data;
+       splaynode->type = type;
+       splaynode->key = key;
+       
+       /* Return the new splay node */
+       return splaynode;
+}
+
+/* Inserts a link into the splay tree */
+inline int splay_insert_link(void * alias_key, void * orig_key, splaytree_t * splaytree) {
+
+   splaynode_t * splaynode, * data_node;
+   void * key_clone;
+
+   /* Null arguments */        
+   if (splaytree == NULL)
+               return FAILURE;
+   
+   if (alias_key == NULL)
+               return FAILURE;
+
+   if (orig_key == NULL)
+               return FAILURE;
+   
+   /* Find the splaynode corresponding to the original key */
+   if ((data_node = get_splaynode_of(orig_key, splaytree)) == NULL)
+          return FAILURE;
+   
+   /* Create a new splay node of symbolic link type */
+   if ((splaynode = new_splaynode(SYMBOLIC_NODE_TYPE, (key_clone = splaytree->copy_key(alias_key)), data_node)) == NULL) {
+               splaytree->free_key(key_clone);
+               return OUTOFMEM_ERROR;
+   }
+
+   /* Insert the splaynode into the given splaytree */
+   if ((splay_insert_node(splaynode, splaytree)) < 0) {
+     splaynode->left=splaynode->right = NULL;
+     free_splaynode(splaynode, splaytree->free_key);
+     return FAILURE;
+   }           
+       
+   /* Done, return success */
+   return SUCCESS;
+}      
+
+/* Inserts 'data' into the 'splaytree' paired with the passed 'key' */
+inline int splay_insert(void * data, void * key, splaytree_t * splaytree) {
+
+       splaynode_t * splaynode;
+       void * key_clone;
+       
+       /* Null argument checks */
+       if (splaytree == NULL) {
+           return FAILURE;
+       }
+       
+       if (key == NULL)
+               return FAILURE;
+       
+       /* Clone the key argument */
+       key_clone = splaytree->copy_key(key);
+
+       /* Create a new splaynode (of regular type) */
+       if ((splaynode = new_splaynode(REGULAR_NODE_TYPE, key_clone, data)) == NULL) {
+               splaytree->free_key(key_clone);
+               return OUTOFMEM_ERROR;          
+       }
+       
+       
+       /* Inserts the splaynode into the splaytree */
+       if (splay_insert_node(splaynode, splaytree) < 0) {
+         splaynode->left=splaynode->right=NULL;
+         free_splaynode(splaynode, splaytree->free_key);
+         return FAILURE;               
+       }       
+     
+
+       return SUCCESS;
+}
+
+/* Helper function to insert splaynodes into the splaytree */
+static inline int splay_insert_node(splaynode_t * splaynode, splaytree_t * splaytree) {
+  int match_type;
+  int cmpval;
+  void * key;
+  splaynode_t * t;
+       
+  /* Null argument checks */
+  if (splaytree == NULL)
+    return FAILURE;
+
+  if (splaynode == NULL)
+       return FAILURE;
+  
+  key = splaynode->key;
+  
+  t = splaytree->root; 
+
+
+  /* Root is null, insert splaynode here */
+  if (t == NULL) {
+       splaynode->left = splaynode->right = NULL;
+       splaytree->root = splaynode;
+       return SUCCESS;
+
+  }
+  
+  t = splay(key, t, &match_type, splaytree->compare);
+  
+  if ((cmpval = splaytree->compare(key,t->key)) < 0) {
+       splaynode->left = t->left;
+       splaynode->right = t;
+       t->left = NULL;
+       splaytree->root = splaynode;
+       return SUCCESS;
+
+  } 
+
+  else if (cmpval > 0) {
+       splaynode->right = t->right;
+       splaynode->left = t;
+       t->right = NULL; 
+       splaytree->root = splaynode;
+       return SUCCESS;
+   } 
+   
+   /* Item already exists in tree, don't reinsert */
+  else {
+    
+    return FAILURE;
+  }
+}
+
+/* Returns the 'maximum' key that is less than the given key in the splaytree */
+inline void * splay_find_below_max(void * key, splaytree_t * splaytree) {
+       
+       void * closest_key;
+       
+       if (splaytree == NULL)
+               return NULL;
+       if (splaytree->root == NULL)
+               return NULL;
+       if (key == NULL)
+               return NULL;
+       
+       closest_key = NULL;
+       
+       splay_find_below_max_helper(key, &closest_key, splaytree->root, splaytree->compare);
+
+       if (closest_key == NULL) return NULL;
+       return splay_find(closest_key, splaytree);
+}
+
+
+/* Returns the 'minimum' key that is greater than the given key in the splaytree */
+inline void * splay_find_above_min(void * key, splaytree_t * splaytree) {
+       
+       void * closest_key;
+       
+       if (splaytree == NULL)
+               return NULL;
+       if (splaytree->root == NULL)
+               return NULL;
+       if (key == NULL)
+               return NULL;
+       closest_key = NULL;
+       
+       splay_find_above_min_helper(key, &closest_key, splaytree->root, splaytree->compare);
+
+       if (closest_key == NULL) { 
+               return NULL;
+       }
+       
+       return splay_find(closest_key, splaytree);
+}
+
+/* Helper function */
+static inline void splay_find_below_max_helper(void * min_key, void ** closest_key, splaynode_t * root, int (*compare)()) {
+
+               /* Empty root, return*/ 
+               if (root == NULL)
+                       return;
+                       
+               /* The root key is less than the previously found closest key.
+                  Also try to make the key non null if the value is less than the max key */
+               
+               if ((*closest_key == NULL) || (compare(root->key, *closest_key) < 0)) {
+                       
+                       /*  The root key is less than the given max key, so this is the
+                               smallest change from the given max key */
+                       if (compare(root->key, min_key) > 0) {
+                               
+                               *closest_key = root->key;
+                               
+                               /* Look right again in case even a greater key exists that is 
+                                  still less than the given max key */
+                               splay_find_below_max_helper(min_key, closest_key, root->left, compare);
+                       }
+                       
+                       /* The root key is greater than the given max key, and greater than 
+                          the closest key, so search left */
+                       else {
+                               splay_find_below_max_helper(min_key, closest_key, root->right, compare);                                
+                       }       
+               }       
+               
+               /* The root key is less than the found closest key, search right */
+               else {
+                               splay_find_below_max_helper(min_key, closest_key, root->left, compare);                         
+               }
+       
+}
+
+/* Helper function */
+static inline void splay_find_above_min_helper(void * max_key, void ** closest_key, splaynode_t * root, int (*compare)()) {
+
+               /* Empty root, stop */  
+               if (root == NULL)
+                       return;
+                       
+               /* The root key is greater than the previously found closest key.
+                  Also try to make the key non null if the value is less than the min key */
+               
+               if ((*closest_key == NULL) || (compare(root->key, *closest_key) > 0)) {
+                       
+                       /*  The root key is greater than the given min key, so this is the
+                               smallest change from the given min key */
+                       if (compare(root->key, max_key) < 0) {
+                               
+                               *closest_key = root->key;
+                               
+                          /* Look left again in case even a smaller key exists that is 
+                                 still greater than the given min key */
+                               splay_find_above_min_helper(max_key, closest_key, root->right, compare);
+                       }
+                       
+                       /* The root key is less than the given min key, and less than 
+                          the closest key, so search right */
+                       else {
+                               splay_find_above_min_helper(max_key, closest_key, root->left, compare);                         
+                       }       
+               }       
+               
+               /* The root key is greater than the found closest key, search left */
+               else {
+                               splay_find_above_min_helper(max_key, closest_key, root->right, compare);                                
+               }
+}      
+
+/* Find the minimum entry of the splay tree */
+inline void * splay_find_min(splaytree_t * t) {
+
+       splaynode_t * splaynode;
+       
+       if (t == NULL)
+               return NULL;
+       if (t->root == NULL)
+               return NULL;
+       
+       splaynode = t->root;
+       
+       while (splaynode->left != NULL)
+               splaynode= splaynode->left;
+       
+       return splaynode->data;
+}
+
+
+/* Find the maximum entry of the splay tree */
+inline void * splay_find_max(splaytree_t * t) {
+
+       splaynode_t * splaynode;
+       
+       if (t == NULL)
+               return NULL;
+       if (t->root == NULL)
+               return NULL;
+       
+       splaynode = t->root;
+        
+       while (splaynode->right != NULL) {
+         printf("data:%d\n", *(int*)splaynode->key);
+               splaynode = splaynode->right;
+       }
+       return splaynode->data;
+}
+
+inline int splay_size(splaytree_t * t) {
+
+       if (t == NULL)
+         return 0;
+       if (t->root == NULL)
+         return 0;
+       
+       return splay_rec_size(t->root);
+        
+}
+
+static inline int splay_rec_size(splaynode_t * splaynode) {
+
+  if (!splaynode)
+    return 0;
+
+  return 1 + splay_rec_size(splaynode->left) + splay_rec_size(splaynode->right);
+
+}
diff --git a/modules/visualization/galaktos/splaytree.h b/modules/visualization/galaktos/splaytree.h
new file mode 100644 (file)
index 0000000..856ea2c
--- /dev/null
@@ -0,0 +1,24 @@
+#ifndef SPLAYTREE_H
+#define SPLAYTREE_H
+#define REGULAR_NODE_TYPE 0
+#define SYMBOLIC_NODE_TYPE 1
+
+#define PERFECT_MATCH 0
+#define CLOSEST_MATCH 1
+
+
+
+inline void * splay_find(void * key, splaytree_t * t);
+inline int splay_insert(void * data, void * key, splaytree_t * t);
+inline int splay_insert_link(void * alias_key, void * orig_key, splaytree_t * splaytree);
+inline int splay_delete(void * key, splaytree_t * splaytree);
+inline int splay_size(splaytree_t * t);
+inline splaytree_t * create_splaytree(int (*compare)(), void * (*copy_key)(), void (*free_key)());
+inline int destroy_splaytree(splaytree_t * splaytree);
+inline void splay_traverse(void (*func_ptr)(), splaytree_t * splaytree);
+inline splaynode_t  * get_splaynode_of(void * key, splaytree_t * splaytree);
+inline void * splay_find_above_min(void * key, splaytree_t * root);
+inline void * splay_find_below_max(void * key, splaytree_t * root);
+inline void * splay_find_min(splaytree_t * t);
+inline void * splay_find_max(splaytree_t * t);
+#endif
diff --git a/modules/visualization/galaktos/splaytree_types.h b/modules/visualization/galaktos/splaytree_types.h
new file mode 100644 (file)
index 0000000..96ef977
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef SPLAYTREE_TYPES_H
+#define SPLAYTREE_TYPES_H
+
+typedef struct SPLAYNODE_T {
+  int type;
+  struct SPLAYNODE_T * left, * right;
+  void * data;
+  void * key;
+} splaynode_t;
+
+typedef struct SPLAYTREE_T {
+  splaynode_t * root;
+  int (*compare)();
+  void * (*copy_key)();
+  void (*free_key)();
+} splaytree_t;
+#endif
diff --git a/modules/visualization/galaktos/tree_types.c b/modules/visualization/galaktos/tree_types.c
new file mode 100644 (file)
index 0000000..ff0fc02
--- /dev/null
@@ -0,0 +1,93 @@
+/*****************************************************************************
+ * tree_types.c:
+ *****************************************************************************
+ * Copyright (C) 2004 VideoLAN
+ * $Id$
+ *
+ * Authors: Cyril Deguet <asmax@videolan.org>
+ *          code from projectM http://xmms-projectm.sourceforge.net
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ *****************************************************************************/
+
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "common.h"
+
+/* Compares integer value numbers in 32 bit range */
+int compare_int(int * num1, int * num2) {
+
+       if ((*num1) < (*num2))
+               return -1;
+       if ((*num1) > (*num2))
+               return 1;
+       
+       return 0;
+}
+
+/* Compares strings in lexographical order */
+int compare_string(char * str1, char * str2) {
+
+  //  printf("comparing \"%s\" to \"%s\"\n", str1, str2);
+  //return strcmp(str1, str2);
+  return strncmp(str1, str2, MAX_TOKEN_SIZE-1);
+       
+}      
+
+/* Compares a string in version order. That is, file1 < file2 < file10 */
+int compare_string_version(char * str1, char * str2) {
+
+  return strverscmp(str1, str2);
+
+}
+
+
+void free_int(void * num) {
+       free(num);
+}
+
+
+void free_string(char * string) {
+       
+       free(string);   
+}      
+void * copy_int(int * num) {
+       
+       int * new_num;
+       
+       if ((new_num = (int*)malloc(sizeof(int))) == NULL)
+               return NULL;
+
+       *new_num = *num;
+       
+       return (void*)new_num;
+}      
+
+
+void * copy_string(char * string) {
+       
+       char * new_string;
+       
+       if ((new_string = (char*)malloc(MAX_TOKEN_SIZE)) == NULL)
+               return NULL;
+       
+       strncpy(new_string, string, MAX_TOKEN_SIZE-1);
+       
+       return (void*)new_string;
+}
diff --git a/modules/visualization/galaktos/tree_types.h b/modules/visualization/galaktos/tree_types.h
new file mode 100644 (file)
index 0000000..e730b96
--- /dev/null
@@ -0,0 +1,10 @@
+int compare_int(char * num1, char * num2);
+int compare_string(char * str1, char * str2);
+
+void free_int(int * num);
+void free_string(char * string);
+
+void * copy_int(int * num);
+void * copy_string(char * string);
+
+void * compare_string_version(char * str1, char * str2);
diff --git a/modules/visualization/galaktos/video_init.c b/modules/visualization/galaktos/video_init.c
new file mode 100644 (file)
index 0000000..a03df2f
--- /dev/null
@@ -0,0 +1,137 @@
+/*****************************************************************************
+ * video_init.c:
+ *****************************************************************************
+ * Copyright (C) 2004 VideoLAN
+ * $Id$
+ *
+ * Authors: Cyril Deguet <asmax@videolan.org>
+ *          code from projectM http://xmms-projectm.sourceforge.net
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ *****************************************************************************/
+
+
+
+//video_init.c - SDL/Opengl Windowing Creation/Resizing Functions
+//
+//by Peter Sperl
+//
+//Opens an SDL Window and creates an OpenGL session
+//also able to handle resizing and fullscreening of windows
+//just call init_display again with differant variables
+
+#include <GL/gl.h>
+#include <GL/glu.h>
+#include "video_init.h"
+
+extern int texsize;
+
+
+void setup_opengl( int w, int h )
+{
+   
+    /* Our shading model--Gouraud (smooth). */
+     glShadeModel( GL_SMOOTH);
+    /* Culling. */
+    //    glCullFace( GL_BACK );
+    //    glFrontFace( GL_CCW );
+    //    glEnable( GL_CULL_FACE );
+    /* Set the clear color. */
+    glClearColor( 0, 0, 0, 0 );
+    /* Setup our viewport. */
+     glViewport( 0, 0, w, h );
+    /*
+     * Change to the projection matrix and set
+     * our viewing volume.
+     */
+    glMatrixMode(GL_TEXTURE);
+    glLoadIdentity();
+    
+    //    gluOrtho2D(0.0, (GLfloat) width, 0.0, (GLfloat) height);
+    glMatrixMode(GL_PROJECTION);
+    glLoadIdentity();  
+   
+    //    glFrustum(0.0, height, 0.0,width,10,40);
+    glMatrixMode(GL_MODELVIEW);
+    glLoadIdentity();
+
+glDrawBuffer(GL_BACK); 
+  glReadBuffer(GL_BACK); 
+  glEnable(GL_BLEND); 
+
+     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 
+     // glBlendFunc(GL_SRC_ALPHA, GL_ONE); 
+  glEnable(GL_LINE_SMOOTH);
+  glEnable(GL_POINT_SMOOTH);
+  glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
+  glClear(GL_COLOR_BUFFER_BIT);
+  // glCopyTexImage2D(GL_TEXTURE_2D,0,GL_RGB,0,0,texsize,texsize,0);
+  //glCopyTexSubImage2D(GL_TEXTURE_2D,0,0,0,0,0,texsize,texsize);
+   glLineStipple(2, 0xAAAA);
+  
+    
+}
+
+void CreateRenderTarget(int texsize,int *RenderTargetTextureID, int *RenderTarget )
+{
+    /* Create the texture that will be bound to the render target */
+    glGenTextures(1, RenderTargetTextureID);
+    glBindTexture(GL_TEXTURE_2D, *RenderTargetTextureID);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+#if 0
+    /* Create the render target */
+    *RenderTarget = SDL_GL_CreateRenderTarget(texsize,texsize, NULL);
+        if ( *RenderTarget ) {
+    
+       int value;
+
+       //printf("Created render target:\n");
+       SDL_GL_GetRenderTargetAttribute( *RenderTarget, SDL_GL_RED_SIZE, &value );
+       //      printf( "SDL_GL_RED_SIZE: %d\n", value);
+       SDL_GL_GetRenderTargetAttribute( *RenderTarget, SDL_GL_GREEN_SIZE, &value );
+       //      printf( "SDL_GL_GREEN_SIZE: %d\n", value);
+       SDL_GL_GetRenderTargetAttribute( *RenderTarget, SDL_GL_BLUE_SIZE, &value );
+       //      printf( "SDL_GL_BLUE_SIZE: %d\n", value);
+       SDL_GL_GetRenderTargetAttribute( *RenderTarget, SDL_GL_ALPHA_SIZE, &value );
+       //      printf( "SDL_GL_ALPHA_SIZE: %d\n", value);
+       SDL_GL_GetRenderTargetAttribute( *RenderTarget, SDL_GL_DEPTH_SIZE, &value );
+       //      printf( "SDL_GL_DEPTH_SIZE: %d\n", value );
+
+       SDL_GL_BindRenderTarget(*RenderTarget, *RenderTargetTextureID);
+       
+    } else {
+#endif
+        /* We can fake a render target in this demo by rendering to the
+         * screen and copying to a texture before we do normal rendering.
+         */
+
+        glBindTexture(GL_TEXTURE_2D, *RenderTargetTextureID);
+        glTexImage2D(GL_TEXTURE_2D,
+                       0,
+                       GL_RGB,
+                       texsize, texsize,
+                       0,
+                       GL_RGB,
+                       GL_UNSIGNED_BYTE,
+                       0);
+ //   }
+
+}
+
+
+
+
diff --git a/modules/visualization/galaktos/video_init.h b/modules/visualization/galaktos/video_init.h
new file mode 100644 (file)
index 0000000..70d8d9b
--- /dev/null
@@ -0,0 +1,3 @@
+void setup_opengl( int w, int h );
+
+void CreateRenderTarget(int texsize,int *RenderTargetTextureID, int *RenderTarget);