diff Plugins/Visualization/paranormal/pn/pndisplacement.c @ 1507:0c5fdcf3f947 trunk

[svn] - incomplete stuff
author nenolod
date Sun, 06 Aug 2006 01:53:29 -0700
parents
children a898e415ad8f
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Plugins/Visualization/paranormal/pn/pndisplacement.c	Sun Aug 06 01:53:29 2006 -0700
@@ -0,0 +1,423 @@
+/* Paranormal - A highly customizable audio visualization library
+ * Copyright (C) 2001  Jamie Gennis <jgennis@mindspring.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <math.h>
+#include <glib.h>
+#include "pndisplacement.h"
+#include "pnbooleanoption.h"
+#include "pnstringoption.h"
+#include "pncpu.h"
+
+enum
+{
+  PN_PIXEL_DISPLACEMENT_NO_PIXEL = 0xffffffff
+};
+
+static void         pn_displacement_class_init       (PnDisplacementClass *class);
+static void         pn_displacement_init             (PnDisplacement *displacement,
+						     PnDisplacementClass *class);
+/* PnObject signals */
+static void         pn_displacement_destroy          (PnObject *object);
+
+/* PnActuator methods */
+static void         pn_displacement_prepare          (PnDisplacement *displacement,
+						     PnImage *image);
+static void         pn_displacement_execute          (PnDisplacement *displacement,
+						     PnImage *image,
+						     PnAudioData *audio_data);
+
+static PnActuatorClass *parent_class = NULL;
+
+GType
+pn_displacement_get_type (void)
+{
+  static GType displacement_type = 0;
+
+  if (! displacement_type)
+    {
+      static const GTypeInfo displacement_info =
+      {
+	sizeof (PnDisplacementClass),
+	NULL,		/* base_init */
+	NULL,		/* base_finalize */
+	(GClassInitFunc) pn_displacement_class_init,
+	NULL,		/* class_finalize */
+	NULL,		/* class_data */
+        sizeof (PnDisplacement),
+	0,              /* n_preallocs */
+	(GInstanceInitFunc) pn_displacement_init
+      };
+
+      /* FIXME: should this be dynamic? */
+      displacement_type = g_type_register_static (PN_TYPE_ACTUATOR,
+						 "PnDisplacement",
+						 &displacement_info,
+						 0);
+    }
+  return displacement_type;
+}
+
+static void
+pn_displacement_class_init (PnDisplacementClass *class)
+{
+  GObjectClass *gobject_class;
+  PnObjectClass *object_class;
+  PnUserObjectClass *user_object_class;
+  PnActuatorClass *actuator_class;
+
+  parent_class = g_type_class_peek_parent (class);
+
+  gobject_class = (GObjectClass *) class;
+  object_class = (PnObjectClass *) class;
+  user_object_class = (PnUserObjectClass *) class;
+  actuator_class = (PnActuatorClass *) class;
+
+  /* PnObject signals */
+  object_class->destroy = pn_displacement_destroy;
+
+  /* PnActuator methods */
+  actuator_class->prepare = (PnActuatorPrepFunc) pn_displacement_prepare;
+  actuator_class->execute = (PnActuatorExecFunc) pn_displacement_execute;
+}
+
+static void
+pn_displacement_init (PnDisplacement *displacement, PnDisplacementClass *class)
+{
+  PnStringOption *init_script_opt, *frame_script_opt;
+
+  /* Set up the name and description */
+  pn_user_object_set_name (PN_USER_OBJECT (displacement), "Transform.Displacement");
+  pn_user_object_set_description (PN_USER_OBJECT (displacement),
+				  "Displaces the image");
+
+  /* Set up the options */
+  init_script_opt = pn_string_option_new ("init_script", "The initialization script");
+  frame_script_opt = pn_string_option_new ("frame_script", "The per-frame script");
+
+  pn_actuator_add_option (PN_ACTUATOR (displacement), PN_OPTION (init_script_opt));
+  pn_actuator_add_option (PN_ACTUATOR (displacement), PN_OPTION (frame_script_opt));
+
+  /* Create the script objects and symbol table */
+  displacement->init_script = pn_script_new ();
+  pn_object_ref (PN_OBJECT (displacement->init_script));
+  pn_object_sink (PN_OBJECT (displacement->init_script));
+  displacement->frame_script = pn_script_new ();
+  pn_object_ref (PN_OBJECT (displacement->frame_script));
+  pn_object_sink (PN_OBJECT (displacement->frame_script));
+  displacement->symbol_table = pn_symbol_table_new ();
+  pn_object_ref (PN_OBJECT (displacement->symbol_table));
+  pn_object_sink (PN_OBJECT (displacement->symbol_table));
+
+  /* Get the variables from the symbol table */
+  displacement->x_var = pn_symbol_table_ref_variable_by_name (displacement->symbol_table, "x");
+  displacement->y_var = pn_symbol_table_ref_variable_by_name (displacement->symbol_table, "y");
+  displacement->volume_var = pn_symbol_table_ref_variable_by_name (displacement->symbol_table, "volume");
+}
+
+static void
+pn_displacement_destroy (PnObject *object)
+{
+  PnDisplacement *displacement;
+
+  displacement = (PnDisplacement *) object;
+
+  pn_object_unref (PN_OBJECT (displacement->init_script));
+  pn_object_unref (PN_OBJECT (displacement->frame_script));
+  pn_object_unref (PN_OBJECT (displacement->symbol_table));
+}
+
+/* FIXME: optimize this */
+static void
+pn_displacement_prepare (PnDisplacement *displacement, PnImage *image)
+{
+  PnStringOption *init_script_opt, *frame_script_opt;
+
+  g_return_if_fail (displacement != NULL);
+  g_return_if_fail (PN_IS_DISPLACEMENT (displacement));
+  g_return_if_fail (image != NULL);
+  g_return_if_fail (PN_IS_IMAGE (image));
+
+  /* Parse the script strings */
+  init_script_opt =
+    (PnStringOption *) pn_actuator_get_option_by_index (PN_ACTUATOR (displacement),
+							PN_DISPLACEMENT_OPT_INIT_SCRIPT);
+  frame_script_opt =
+    (PnStringOption *) pn_actuator_get_option_by_index (PN_ACTUATOR (displacement),
+							PN_DISPLACEMENT_OPT_FRAME_SCRIPT);
+
+  pn_script_parse_string (displacement->init_script, displacement->symbol_table,
+			  pn_string_option_get_value (init_script_opt));
+  pn_script_parse_string (displacement->frame_script, displacement->symbol_table,
+			  pn_string_option_get_value (frame_script_opt));
+
+  /* Set up 0 displacement */
+  PN_VARIABLE_VALUE (displacement->x_var) = 0.0;
+  PN_VARIABLE_VALUE (displacement->y_var) = 0.0;
+
+  /* Run the init script */
+  pn_script_execute (displacement->init_script);
+
+  if (PN_ACTUATOR_CLASS (parent_class)->prepare)
+    PN_ACTUATOR_CLASS (parent_class)->prepare (PN_ACTUATOR (displacement), image);
+}
+
+static void
+pn_displacement_exec (PnImage *image, gint offset, guint nw, guint ne, guint sw, guint se,
+		      gint startx, gint starty, gint endx, gint endy)
+{
+  gint i, j, width, height, stride;
+  PnColor *src, *dest, zero = {0,0,0,0};
+  guint r, g, b;
+
+  width = pn_image_get_width (image);
+  height = pn_image_get_height (image);
+  stride = pn_image_get_pitch (image) >> 2;
+
+  src = pn_image_get_image_buffer (image);
+  dest = pn_image_get_transform_buffer (image);
+
+  for (j=0; j<height; j++)
+    for (i=0; i<width; i++)
+      {
+	if (i < startx || i >= endx
+	    || j < starty || j >= endy)
+	  dest[j * stride + i] = zero;
+	else
+	  {
+	    r = src[(j * stride + i) + offset].red * nw;
+	    g = src[(j * stride + i) + offset].green * nw;
+	    b = src[(j * stride + i) + offset].blue * nw;
+
+	    r += src[(j * stride + (i + 1)) + offset].red * ne;
+	    g += src[(j * stride + (i + 1)) + offset].green * ne;
+	    b += src[(j * stride + (i + 1)) + offset].blue * ne;
+
+	    r += src[((j + 1) * stride + i) + offset].red * sw;
+	    g += src[((j + 1) * stride + i) + offset].green * sw;
+	    b += src[((j + 1) * stride + i) + offset].blue * sw;
+
+	    r += src[((j + 1) * stride + (i + 1)) + offset].red * se;
+	    g += src[((j + 1) * stride + (i + 1)) + offset].green * se;
+	    b += src[((j + 1) * stride + (i + 1)) + offset].blue * se;
+
+	    dest[j * stride + i].red = r >> 7;
+	    dest[j * stride + i].green = g >> 7;
+	    dest[j * stride + i].blue = b >> 7;
+	  }
+      }
+}
+
+#ifdef PN_USE_MMX
+static void
+pn_displacement_exec_mmx (PnImage *image, gint offset, guint nw, guint ne, guint sw, guint se,
+			  gint startx, gint starty, gint endx, gint endy)
+{
+  PnColor *src, *dest, *endptr;
+  gint width, height, stride, i;
+  guint64 upnw; /* a place to store the unpacked se weight */
+
+  width = pn_image_get_width (image);
+  height = pn_image_get_height (image);
+  stride = pn_image_get_pitch (image) >> 2;
+
+  src = pn_image_get_image_buffer (image);
+  dest = pn_image_get_transform_buffer (image);
+
+  memset (dest, 0, pn_image_get_pitch (image) * starty);
+  for (i=MAX(starty, 0); i<endy; i++)
+    {
+      memset (dest + i * stride, 0, startx * sizeof (PnColor));
+      memset (dest + i * stride + endx, 0, (width - endx) * sizeof (PnColor));
+    }
+  memset (dest + endy * stride, 0, (height - endy) * pn_image_get_pitch (image));
+
+  src += (starty * stride) + offset;
+  endptr = src + endx;
+  src += startx;
+  dest += (starty * stride) + startx;
+
+  __asm__ __volatile__ (
+			/* Unpack the weights */
+			"pxor %%mm7,%%mm7\n\t"          /* zero mm7 for unpacking */
+			"movd %8,%%mm4\n\t"             /* load the weights */
+			"punpcklbw %%mm7,%%mm4\n\t"     /* unpack the weights to words */
+			"movq %%mm4,%%mm6\n\t"          /* copy the weights for separate expansion */
+			"punpcklwd %%mm4,%%mm4\n\t"     /* expand the top weights */
+			"punpckhwd %%mm6,%%mm6\n\t"     /* expand the bottom weights */
+			"movq %%mm4,%%mm5\n\t"          /* copy the top pixels for separate expansion */
+			"movq %%mm6,%%mm7\n\t"          /* copy the bottom pixels for separate expansion */
+			"punpckldq %%mm4,%%mm4\n\t"     /* expand the NW weight */
+			"punpckhdq %%mm5,%%mm5\n\t"     /* expand the NE weight */
+			"punpckldq %%mm6,%%mm6\n\t"     /* expand the SW weight */
+			"punpckhdq %%mm7,%%mm7\n\t"     /* expand the SE weight */
+			"movq %%mm7,%4\n\t"             /* save the SE weight so we can use mm7 as 0 */
+			"pxor %%mm7,%%mm7\n\t"          /* re-zero mm7 */
+
+			"10:\n\t"
+
+			/* zero mm7 for unpacking */
+			"pxor %%mm7,%%mm7\n\t"
+
+			/* load & unpack the pixels */
+			"movd (%0),%%mm0\n\t"
+			"punpcklbw %%mm7,%%mm0\n\t"
+			"movd 4(%0),%%mm1\n\t"
+			"punpcklbw %%mm7,%%mm1\n\t"
+			"movd (%0,%5),%%mm2\n\t"
+			"punpcklbw %%mm7,%%mm2\n\t"
+			"movd 4(%0,%5),%%mm3\n\t"
+			"punpcklbw %%mm7,%%mm3\n\t"
+
+			/* reload the unpacked se weight */
+			"movq %4,%%mm7\n\t"
+
+			/* weight each pixel */
+			"pmullw %%mm4,%%mm0\n\t"
+			"pmullw %%mm5,%%mm1\n\t"
+			"pmullw %%mm6,%%mm2\n\t"
+			"pmullw %%mm7,%%mm3\n\t"
+
+			/* add up the weighted pixels */
+			"paddw %%mm1,%%mm0\n\t"
+			"paddw %%mm2,%%mm0\n\t"
+			"paddw %%mm3,%%mm0\n\t"
+
+			/* normalize the resulting pixel, pack it, and write it */
+			"psrlw $7,%%mm0\n\t"
+			"packuswb %%mm0,%%mm0\n\t"
+			"movd %%mm0,(%1)\n\t"
+
+			/* advance the pointers */
+			"addl $4,%0\n\t"
+			"addl $4,%1\n\t"
+
+			/* see if we're done with this line */
+			"cmpl %3,%0\n\t"
+			"jl 10b\n\t"
+
+			/* advance the pointers */
+			"addl %7,%0\n\t"
+			"addl %7,%1\n\t"
+			"addl %5,%3\n\t"
+
+			/* see if we're done */
+			"incl %2\n\t"
+			"cmpl %6,%2\n\t"
+			"jl 10b\n\t"
+
+			"emms\n\t"
+
+			: /* no outputs */
+			: "r" (src), /* 0 */
+			"r" (dest), /* 1 */
+			"r" (starty), /* 2 */
+			"m" (endptr), /* 3 */
+			"m" (upnw), /* 4 */
+			"r" (pn_image_get_pitch (image)),  /* 5 */
+			"r" (endy), /* 6 */
+			"rm" (((stride - endx) + startx) * sizeof (PnColor)), /* 7 */
+			"rm" ((guint32)((se << 24) | (sw << 16) | (ne << 8) | nw ))); /* 8 */
+}
+#endif /* PN_USE_MMX */
+
+static void
+pn_displacement_execute (PnDisplacement *displacement, PnImage *image, PnAudioData *audio_data)
+{
+  g_return_if_fail (displacement != NULL);
+  g_return_if_fail (PN_IS_DISPLACEMENT (displacement));
+  g_return_if_fail (image != NULL);
+  g_return_if_fail (PN_IS_IMAGE (image));
+  g_return_if_fail (audio_data != NULL);
+  g_return_if_fail (PN_IS_AUDIO_DATA (audio_data));
+
+  /* set up the volume in-script variable */
+  PN_VARIABLE_VALUE (displacement->volume_var) = pn_audio_data_get_volume (audio_data);
+
+  /* run the frame scipt */
+  pn_script_execute (displacement->frame_script);
+
+  if (fabs (PN_VARIABLE_VALUE (displacement->x_var)) <= 2.0
+      && fabs (PN_VARIABLE_VALUE (displacement->y_var)) <= 2.0)
+    {
+      guint nw, ne, sw, se;
+      gint startx, starty, endx, endy;
+      gint offset;
+      gdouble x, y, xfrac, yfrac;
+
+      x = -PN_VARIABLE_VALUE (displacement->x_var) * (pn_image_get_width (image) >> 1);
+      y = PN_VARIABLE_VALUE (displacement->y_var) * (pn_image_get_height (image) >> 1);
+
+      xfrac = modf (x, &x);
+      yfrac = modf (y, &y);
+
+      if (x < 0.0 || xfrac < 0.0)
+	{
+	  x--;
+	  xfrac++;
+	}
+      if (y < 0.0 || yfrac < 0.0)
+	{
+	  y--;
+	  yfrac++;
+	}
+
+      se = xfrac * yfrac * 128.0;
+      sw = (1.0 - xfrac) * yfrac * 128.0;
+      ne = xfrac * (1.0 - yfrac) * 128.0;
+      nw = 128 - (se + sw + ne);
+
+      offset = (y * (pn_image_get_pitch (image) >> 2)) + x;
+
+      startx = -x;
+      starty = -y;
+      endx = pn_image_get_width (image) - (x+1);
+      endy = pn_image_get_height (image) - (y+1);
+
+      startx = MAX (startx, 0);
+      starty = MAX (starty, 0);
+      endx = MIN (endx, pn_image_get_width (image));
+      endy = MIN (endy, pn_image_get_height (image));
+
+      /* I'm too lazy to special case the rightmost & bottommost pixels */
+      if (endx == pn_image_get_width (image))
+	endx--;
+      if (endy == pn_image_get_height (image))
+	endy--;
+      
+#ifdef PN_USE_MMX
+      if (pn_cpu_get_caps () & PN_CPU_CAP_MMX)
+	pn_displacement_exec_mmx (image, offset, nw, ne, sw, se, startx, starty, endx, endy);
+      else
+#endif /* PN_USE_MMX */
+	pn_displacement_exec (image, offset, nw, ne, sw, se, startx, starty, endx, endy);
+    }
+  else
+    memset (pn_image_get_transform_buffer (image), 0,
+	    pn_image_get_pitch (image) * pn_image_get_height (image));
+
+  pn_image_apply_transform (image);
+
+  if (PN_ACTUATOR_CLASS (parent_class)->execute)
+    PN_ACTUATOR_CLASS (parent_class)->execute (PN_ACTUATOR (displacement), image, audio_data);
+}
+
+PnDisplacement*
+pn_displacement_new (void)
+{
+  return (PnDisplacement *) g_object_new (PN_TYPE_DISPLACEMENT, NULL);
+}