Copyright notices in docs
[mw/milkymist.git] / doc / milkdrop.tex
1 \documentclass[a4paper,11pt]{article}
2 \usepackage{fullpage}
3 \usepackage[latin1]{inputenc}
4 \usepackage[T1]{fontenc}
5 \usepackage[normalem]{ulem}
6 \usepackage[english]{babel}
7 \usepackage{listings,babel}
8 \lstset{breaklines=true,basicstyle=\ttfamily}
9 \usepackage{graphicx}
10 \usepackage{moreverb}
11 \usepackage{url}
12
13 \title{Implementing MilkDrop on Milkymist}
14 \author{S\'ebastien Bourdeauducq}
15 \date{December 2009}
16 \begin{document}
17 \setlength{\parindent}{0pt}
18 \setlength{\parskip}{5pt}
19 \maketitle{}
20 \section{Introduction}
21 MilkDrop is a popular, hardware-accelerated music visualization plugin for Winamp. MilkDrop is an environment for running presets, software which controls MilkDrop, and does not produce visualizations by itself.
22
23 Presets are saved in .milk format. Creating new presets is generally referred to as authoring, or writing, making the person that wrote a preset its author. Presets are distributed on the internet though Winamp, the Winamp Forums, and through the personal webpages of MilkDrop preset authors. A preset's title also doubles as its .milk save name, and usually includes the preset author or authors' pseudonym.
24
25 This document explains how to render such presets, with a focus on implementing them in Milkymist.
26
27 \section{Overview}
28 A \verb!.milk! file is composed of 2 major different kinds of scriptable equations. These are per\_frame and per\_vertex (sometimes called per\_pixel) equations.
29
30 Code in the per\_frame section is done once for each frame, modifying variables which affect different parameters that can be passed to other areas of code. Trigonometric functions which modify MilkDrop's internal looping time variable, systems of logic, and interaction with the audio information can be used to govern how these parameters evolve though time.
31
32 The screen is divided into a grid and the per\_vertex code is evaluated at each grid point (vertex). The pixels in-between these points interpolate their values from the surrounding 4 points on the grid. The size of the grid is 32x24 by default, but can be set higher or lower by the user. Per\_vertex equations allow the preset author to alter some of MilkDrop's parameters differently in certain areas of the screen based upon x and y values, distance from the center of the screen, and the angle.
33
34 More information is available in preset authoring guides available from MilkDrop website.
35
36 A diagram of the operations for rendering a preset is shown in Figure~\ref{fig:flow}.
37 \begin{figure}[htp]
38 \centering
39 \includegraphics[height=80mm]{flow.eps}
40 \caption{The rendering flow.}\label{fig:flow}
41 \end{figure}
42
43 \section{Generating the warping mesh}
44 In a MilkDrop preset, the warping mesh is computed from a set of parameters that can be fixed or generated by the per-frame and per-vertex equations.
45
46 Those parameters are the following:
47 \begin{itemize}
48 \item \verb!zoom!, which scales the image.
49 \item \verb!zoomexp!, which (locally) zooms the image more when getting further from the center.
50 \item \verb!sx!, \verb!sy!, \verb!cx! and \verb!cy!, which scales the image on X and Y axises around the point $ (cx, cy) $.
51 \item \verb!warp!, \verb!fWarpScale! and \verb!fWarpAnimSpeed!, which distort the image.
52 \item \verb!rot!, \verb!cx! and \verb!cy!, which rotates the image around the point $ (cx, cy) $.
53 \item \verb!dx! and \verb!dy!, which add a delta to the mesh point.
54 \end{itemize}
55
56 In the rendering process, every new frame is based on the old one warped using these parameters. For instance, this means that if the \verb!rot! parameter is held constant at a non-zero value, you get a continuous spiral movement, not a simple shift of the image.
57
58 Now, we need a formal description of what these parameters do.
59
60 In projectM 1.1 (an OpenGL implementation of MilkDrop), the warping is done via the method \verb!Renderer::Interpolation!, defined in \verb!Renderer.cpp!. This method just programs the GPU for doing image warping and decay. The warping mesh is passed in \verb!presetOutputs->x_mesh! and \verb!presetOutputs->y_mesh!, and the decay value in \verb!presetOutputs->decay!. The mesh coordinates are floating-point numbers between 0 and 1, which means the top-left corner of the screen is at $ (0, 0) $, the bottom-right at $ (1, 1) $ and the center at $ (0.5, 0.5) $.
61
62 The generation of the mesh is done from the per-frame and per-vertex equations results by the \verb!Renderer::PerPixelMath! method.
63
64 The order of the operations performed by this function is:
65 \begin{itemize}
66 \item make an initial zoomed mesh:
67 \[
68 \left\{ \begin{array}{rrlr}
69 zoom2(x, y) & = & zoom(x, y)^{zoomexp(x, y)^{rad(x, y) \cdot 2 - 1}} \\
70 meshx(x, y) & = & ( idx(x, y) - 0.5) \cdot zoom2(x, y) + 0.5 \\
71 meshy(x, y) & = & ( idy(x, y) - 0.5) \cdot zoom2(x, y) + 0.5
72 \end{array}
73 \right.
74 \]
75 with $ x $ and $ y $ representing the indexes of the current mesh point, $ zoom $ and $ zoomexp $ the results of the per-vertex equations, $ rad $ the distance from the center of the screen and $ idx $ and $idy $ the mesh for which no image transformation is performed (the image is copied verbatim), defined by:
76 \[
77 \left\{ \begin{array}{rrlr}
78 idx(x, y) & = & \frac{x}{meshcountx-1} \\
79 idy(x, y) & = & \frac{y}{meshcounty-1}
80 \end{array}
81 \right.
82 \]
83
84 For most presets, $ zoomexp = 1 $, so in the first versions of Milkymist we could use $ zoom2(x, y) = zoom(x, y) $.
85
86 \item scale the mesh according to \verb!sx! and \verb!sy!:
87 \[
88 \left\{ \begin{array}{rrlr}
89 meshx(x, y) & = & \frac{meshx(x, y) - cx(x, y)}{sx(x, y)} + cx(x, y)\\
90 meshy(x, y) & = & \frac{meshy(x, y) - cy(x, y)}{sy(x, y)} + cy(x, y)
91 \end{array}
92 \right.
93 \]
94
95 \item apply the effect triggered by the \verb!warp! parameter, using those magic formulas:
96 \[
97 \left\{ \begin{array}{rrlr}
98 wt & = & time \cdot animspeed \\
99 s & = & \frac{1}{scale} \\
100 f_0 & = & 23.36 + 8 \cdot cos(wt \cdot 1.413 + 10) \\
101 f_1 & = & 17.54 + 6 \cdot cos(wt \cdot 1.113 + 7) \\
102 f_2 & = & 21.08 + 6 \cdot cos(wt \cdot 1.233 + 3) \\
103 f_3 & = & 22.98 + 8 \cdot cos(wt \cdot 0.993 + 5) \\
104 meshx(x, y) & = & meshx(x, y) \\
105  &  & + warp \cdot 0.0035 \cdot sin(wt \cdot 0.333 + s \cdot (idx(x, y) \cdot f_0 - idy(x, y) \cdot f_3)) \\
106  &  & + warp \cdot 0.0035 \cdot cos(wt \cdot 0.753 - s \cdot (idx(x, y) \cdot f_1 - idy(x, y) \cdot f_2)) \\
107 meshy(x, y) & = & meshy(x, y) \\
108  &  & + warp \cdot 0.0035 \cdot cos(wt \cdot 0.375 - s \cdot (idx(x, y) \cdot f_2 + idy(x, y) \cdot f_1)) \\
109  &  & + warp \cdot 0.0035 \cdot sin(wt \cdot 0.825 + s \cdot (idx(x, y) \cdot f_0 + idy(x, y) \cdot f_3)) \\
110 \end{array}
111 \right.
112 \]
113
114 \item apply the rotation
115 \[
116 \left\{ \begin{array}{rrlr}
117 u(x, y) & = & meshx(x, y) - cx(x, y) \\
118 v(x, y) & = & meshy(x, y) - cy(x, y) \\
119 meshx(x, y) & = & u(x, y) \cdot cos(rot(x, y)) - v(x, y) \cdot sin(rot(x, y)) + cx(x, y) \\
120 meshy(x, y) & = & u(x, y) \cdot sin(rot(x, y)) + v(x, y) \cdot cos(rot(x, y)) + cy(x, y)
121 \end{array}
122 \right.
123 \]
124
125 \item apply the deltas
126 \[
127 \left\{ \begin{array}{rrlr}
128 meshx(x, y) & = & meshx(x, y) + dx(x, y)\\
129 meshy(x, y) & = & meshy(x, y) + dy(x, y)
130 \end{array}
131 \right.
132 \]
133
134 \end{itemize}
135
136 \section{Software architecture}
137 \begin{figure}[htp]
138 \centering
139 \includegraphics[height=90mm]{swarch.eps}
140 \caption{Software architecture of the rendering system.}\label{fig:swarch}
141 \end{figure}
142
143 \section*{Copyright notice}
144 Copyright \copyright 2007-2009 S\'ebastien Bourdeauducq. \\
145 Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the LICENSE.FDL file at the root of the Milkymist source distribution.
146
147 \end{document}