diff --git a/examples/lissajous/LICK/init.lua b/examples/lissajous/LICK/init.lua
new file mode 100644
index 0000000..6fc9157
--- /dev/null
+++ b/examples/lissajous/LICK/init.lua
@@ -0,0 +1,3 @@
+require "LICK/lick"
+
+
diff --git a/examples/lissajous/LICK/lib/color.lua b/examples/lissajous/LICK/lib/color.lua
new file mode 100644
index 0000000..b94c709
--- /dev/null
+++ b/examples/lissajous/LICK/lib/color.lua
@@ -0,0 +1,742 @@
+x11_color_table = {
+-- taken from the SuperCollider Color documentation:
+["alice blue"]={240, 248, 255},
+["AliceBlue"]={240, 248, 255},
+["antique white"]={250, 235, 215},
+["AntiqueWhite"]={250, 235, 215},
+["AntiqueWhite1"]={255, 239, 219},
+["AntiqueWhite2"]={238, 223, 204},
+["AntiqueWhite3"]={205, 192, 176},
+["AntiqueWhite4"]={139, 131, 120},
+["aquamarine"]={127, 255, 212},
+["aquamarine1"]={127, 255, 212},
+["aquamarine2"]={118, 238, 198},
+["aquamarine3"]={102, 205, 170},
+["aquamarine4"]={69, 139, 116},
+["azure"]={240, 255, 255},
+["azure1"]={240, 255, 255},
+["azure2"]={224, 238, 238},
+["azure3"]={193, 205, 205},
+["azure4"]={131, 139, 139},
+["beige"]={245, 245, 220},
+["bisque"]={255, 228, 196},
+["bisque1"]={255, 228, 196},
+["bisque2"]={238, 213, 183},
+["bisque3"]={205, 183, 158},
+["bisque4"]={139, 125, 107},
+["black"]={0, 0, 0},
+["blanched almond"]={255, 235, 205},
+["BlanchedAlmond"]={255, 235, 205},
+["blue"]={0, 0, 255},
+["blue violet"]={138, 43, 226},
+["blue1"]={0, 0, 255},
+["blue2"]={0, 0, 238},
+["blue3"]={0, 0, 205},
+["blue4"]={0, 0, 139},
+["BlueViolet"]={138, 43, 226},
+["brown"]={165, 42, 42},
+["brown1"]={255, 64, 64},
+["brown2"]={238, 59, 59},
+["brown3"]={205, 51, 51},
+["brown4"]={139, 35, 35},
+["burlywood"]={222, 184, 135},
+["burlywood1"]={255, 211, 155},
+["burlywood2"]={238, 197, 145},
+["burlywood3"]={205, 170, 125},
+["burlywood4"]={139, 115, 85},
+["cadet blue"]={95, 158, 160},
+["CadetBlue"]={95, 158, 160},
+["CadetBlue1"]={152, 245, 255},
+["CadetBlue2"]={142, 229, 238},
+["CadetBlue3"]={122, 197, 205},
+["CadetBlue4"]={83, 134, 139},
+["chartreuse"]={127, 255, 0},
+["chartreuse1"]={127, 255, 0},
+["chartreuse2"]={118, 238, 0},
+["chartreuse3"]={102, 205, 0},
+["chartreuse4"]={69, 139, 0},
+["chocolate"]={210, 105, 30},
+["chocolate1"]={255, 127, 36},
+["chocolate2"]={238, 118, 33},
+["chocolate3"]={205, 102, 29},
+["chocolate4"]={139, 69, 19},
+["coral"]={255, 127, 80},
+["coral1"]={255, 114, 86},
+["coral2"]={238, 106, 80},
+["coral3"]={205, 91, 69},
+["coral4"]={139, 62, 47},
+["cornflower blue"]={100, 149, 237},
+["CornflowerBlue"]={100, 149, 237},
+["cornsilk"]={255, 248, 220},
+["cornsilk1"]={255, 248, 220},
+["cornsilk2"]={238, 232, 205},
+["cornsilk3"]={205, 200, 177},
+["cornsilk4"]={139, 136, 120},
+["cyan"]={0, 255, 255},
+["cyan1"]={0, 255, 255},
+["cyan2"]={0, 238, 238},
+["cyan3"]={0, 205, 205},
+["cyan4"]={0, 139, 139},
+["dark goldenrod"]={184, 134, 11},
+["dark green"]={0, 100, 0},
+["dark khaki"]={189, 183, 107},
+["dark olive green"]={85, 107, 47},
+["dark orange"]={255, 140, 0},
+["dark orchid"]={153, 50, 204},
+["dark salmon"]={233, 150, 122},
+["dark sea green"]={143, 188, 143},
+["dark slate blue"]={72, 61, 139},
+["dark slate gray"]={47, 79, 79},
+["dark slate grey"]={47, 79, 79},
+["dark turquoise"]={0, 206, 209},
+["dark violet"]={148, 0, 211},
+["DarkGoldenrod"]={184, 134, 11},
+["DarkGoldenrod1"]={255, 185, 15},
+["DarkGoldenrod2"]={238, 173, 14},
+["DarkGoldenrod3"]={205, 149, 12},
+["DarkGoldenrod4"]={139, 101, 8},
+["DarkGreen"]={0, 100, 0},
+["DarkKhaki"]={189, 183, 107},
+["DarkOliveGreen"]={85, 107, 47},
+["DarkOliveGreen1"]={202, 255, 112},
+["DarkOliveGreen2"]={188, 238, 104},
+["DarkOliveGreen3"]={162, 205, 90},
+["DarkOliveGreen4"]={110, 139, 61},
+["DarkOrange"]={255, 140, 0},
+["DarkOrange1"]={255, 127, 0},
+["DarkOrange2"]={238, 118, 0},
+["DarkOrange3"]={205, 102, 0},
+["DarkOrange4"]={139, 69, 0},
+["DarkOrchid"]={153, 50, 204},
+["DarkOrchid1"]={191, 62, 255},
+["DarkOrchid2"]={178, 58, 238},
+["DarkOrchid3"]={154, 50, 205},
+["DarkOrchid4"]={104, 34, 139},
+["DarkSalmon"]={233, 150, 122},
+["DarkSeaGreen"]={143, 188, 143},
+["DarkSeaGreen1"]={193, 255, 193},
+["DarkSeaGreen2"]={180, 238, 180},
+["DarkSeaGreen3"]={155, 205, 155},
+["DarkSeaGreen4"]={105, 139, 105},
+["DarkSlateBlue"]={72, 61, 139},
+["DarkSlateGray"]={47, 79, 79},
+["DarkSlateGray1"]={151, 255, 255},
+["DarkSlateGray2"]={141, 238, 238},
+["DarkSlateGray3"]={121, 205, 205},
+["DarkSlateGray4"]={82, 139, 139},
+["DarkSlateGrey"]={47, 79, 79},
+["DarkTurquoise"]={0, 206, 209},
+["DarkViolet"]={148, 0, 211},
+["deep pink"]={255, 20, 147},
+["deep sky blue"]={0, 191, 255},
+["DeepPink"]={255, 20, 147},
+["DeepPink1"]={255, 20, 147},
+["DeepPink2"]={238, 18, 137},
+["DeepPink3"]={205, 16, 118},
+["DeepPink4"]={139, 10, 80},
+["DeepSkyBlue"]={0, 191, 255},
+["DeepSkyBlue1"]={0, 191, 255},
+["DeepSkyBlue2"]={0, 178, 238},
+["DeepSkyBlue3"]={0, 154, 205},
+["DeepSkyBlue4"]={0, 104, 139},
+["dim gray"]={105, 105, 105},
+["dim grey"]={105, 105, 105},
+["DimGray"]={105, 105, 105},
+["DimGrey"]={105, 105, 105},
+["dodger blue"]={30, 144, 255},
+["DodgerBlue"]={30, 144, 255},
+["DodgerBlue1"]={30, 144, 255},
+["DodgerBlue2"]={28, 134, 238},
+["DodgerBlue3"]={24, 116, 205},
+["DodgerBlue4"]={16, 78, 139},
+["firebrick"]={178, 34, 34},
+["firebrick1"]={255, 48, 48},
+["firebrick2"]={238, 44, 44},
+["firebrick3"]={205, 38, 38},
+["firebrick4"]={139, 26, 26},
+["floral white"]={255, 250, 240},
+["FloralWhite"]={255, 250, 240},
+["forest green"]={34, 139, 34},
+["ForestGreen"]={34, 139, 34},
+["gainsboro"]={220, 220, 220},
+["ghost white"]={248, 248, 255},
+["GhostWhite"]={248, 248, 255},
+["gold"]={255, 215, 0},
+["gold1"]={255, 215, 0},
+["gold2"]={238, 201, 0},
+["gold3"]={205, 173, 0},
+["gold4"]={139, 117, 0},
+["goldenrod"]={218, 165, 32},
+["goldenrod1"]={255, 193, 37},
+["goldenrod2"]={238, 180, 34},
+["goldenrod3"]={205, 155, 29},
+["goldenrod4"]={139, 105, 20},
+["gray"]={190, 190, 190},
+["gray0"]={0, 0, 0},
+["gray1"]={3, 3, 3},
+["gray10"]={26, 26, 26},
+["gray100"]={255, 255, 255},
+["gray11"]={28, 28, 28},
+["gray12"]={31, 31, 31},
+["gray13"]={33, 33, 33},
+["gray14"]={36, 36, 36},
+["gray15"]={38, 38, 38},
+["gray16"]={41, 41, 41},
+["gray17"]={43, 43, 43},
+["gray18"]={46, 46, 46},
+["gray19"]={48, 48, 48},
+["gray2"]={5, 5, 5},
+["gray20"]={51, 51, 51},
+["gray21"]={54, 54, 54},
+["gray22"]={56, 56, 56},
+["gray23"]={59, 59, 59},
+["gray24"]={61, 61, 61},
+["gray25"]={64, 64, 64},
+["gray26"]={66, 66, 66},
+["gray27"]={69, 69, 69},
+["gray28"]={71, 71, 71},
+["gray29"]={74, 74, 74},
+["gray3"]={8, 8, 8},
+["gray30"]={77, 77, 77},
+["gray31"]={79, 79, 79},
+["gray32"]={82, 82, 82},
+["gray33"]={84, 84, 84},
+["gray34"]={87, 87, 87},
+["gray35"]={89, 89, 89},
+["gray36"]={92, 92, 92},
+["gray37"]={94, 94, 94},
+["gray38"]={97, 97, 97},
+["gray39"]={99, 99, 99},
+["gray4"]={10, 10, 10},
+["gray40"]={102, 102, 102},
+["gray41"]={105, 105, 105},
+["gray42"]={107, 107, 107},
+["gray43"]={110, 110, 110},
+["gray44"]={112, 112, 112},
+["gray45"]={115, 115, 115},
+["gray46"]={117, 117, 117},
+["gray47"]={120, 120, 120},
+["gray48"]={122, 122, 122},
+["gray49"]={125, 125, 125},
+["gray5"]={13, 13, 13},
+["gray50"]={127, 127, 127},
+["gray51"]={130, 130, 130},
+["gray52"]={133, 133, 133},
+["gray53"]={135, 135, 135},
+["gray54"]={138, 138, 138},
+["gray55"]={140, 140, 140},
+["gray56"]={143, 143, 143},
+["gray57"]={145, 145, 145},
+["gray58"]={148, 148, 148},
+["gray59"]={150, 150, 150},
+["gray6"]={15, 15, 15},
+["gray60"]={153, 153, 153},
+["gray61"]={156, 156, 156},
+["gray62"]={158, 158, 158},
+["gray63"]={161, 161, 161},
+["gray64"]={163, 163, 163},
+["gray65"]={166, 166, 166},
+["gray66"]={168, 168, 168},
+["gray67"]={171, 171, 171},
+["gray68"]={173, 173, 173},
+["gray69"]={176, 176, 176},
+["gray7"]={18, 18, 18},
+["gray70"]={179, 179, 179},
+["gray71"]={181, 181, 181},
+["gray72"]={184, 184, 184},
+["gray73"]={186, 186, 186},
+["gray74"]={189, 189, 189},
+["gray75"]={191, 191, 191},
+["gray76"]={194, 194, 194},
+["gray77"]={196, 196, 196},
+["gray78"]={199, 199, 199},
+["gray79"]={201, 201, 201},
+["gray8"]={20, 20, 20},
+["gray80"]={204, 204, 204},
+["gray81"]={207, 207, 207},
+["gray82"]={209, 209, 209},
+["gray83"]={212, 212, 212},
+["gray84"]={214, 214, 214},
+["gray85"]={217, 217, 217},
+["gray86"]={219, 219, 219},
+["gray87"]={222, 222, 222},
+["gray88"]={224, 224, 224},
+["gray89"]={227, 227, 227},
+["gray9"]={23, 23, 23},
+["gray90"]={229, 229, 229},
+["gray91"]={232, 232, 232},
+["gray92"]={235, 235, 235},
+["gray93"]={237, 237, 237},
+["gray94"]={240, 240, 240},
+["gray95"]={242, 242, 242},
+["gray96"]={245, 245, 245},
+["gray97"]={247, 247, 247},
+["gray98"]={250, 250, 250},
+["gray99"]={252, 252, 252},
+["green"]={0, 255, 0},
+["green yellow"]={173, 255, 47},
+["green1"]={0, 255, 0},
+["green2"]={0, 238, 0},
+["green3"]={0, 205, 0},
+["green4"]={0, 139, 0},
+["GreenYellow"]={173, 255, 47},
+["grey"]={190, 190, 190},
+["grey0"]={0, 0, 0},
+["grey1"]={3, 3, 3},
+["grey10"]={26, 26, 26},
+["grey100"]={255, 255, 255},
+["grey11"]={28, 28, 28},
+["grey12"]={31, 31, 31},
+["grey13"]={33, 33, 33},
+["grey14"]={36, 36, 36},
+["grey15"]={38, 38, 38},
+["grey16"]={41, 41, 41},
+["grey17"]={43, 43, 43},
+["grey18"]={46, 46, 46},
+["grey19"]={48, 48, 48},
+["grey2"]={5, 5, 5},
+["grey20"]={51, 51, 51},
+["grey21"]={54, 54, 54},
+["grey22"]={56, 56, 56},
+["grey23"]={59, 59, 59},
+["grey24"]={61, 61, 61},
+["grey25"]={64, 64, 64},
+["grey26"]={66, 66, 66},
+["grey27"]={69, 69, 69},
+["grey28"]={71, 71, 71},
+["grey29"]={74, 74, 74},
+["grey3"]={8, 8, 8},
+["grey30"]={77, 77, 77},
+["grey31"]={79, 79, 79},
+["grey32"]={82, 82, 82},
+["grey33"]={84, 84, 84},
+["grey34"]={87, 87, 87},
+["grey35"]={89, 89, 89},
+["grey36"]={92, 92, 92},
+["grey37"]={94, 94, 94},
+["grey38"]={97, 97, 97},
+["grey39"]={99, 99, 99},
+["grey4"]={10, 10, 10},
+["grey40"]={102, 102, 102},
+["grey41"]={105, 105, 105},
+["grey42"]={107, 107, 107},
+["grey43"]={110, 110, 110},
+["grey44"]={112, 112, 112},
+["grey45"]={115, 115, 115},
+["grey46"]={117, 117, 117},
+["grey47"]={120, 120, 120},
+["grey48"]={122, 122, 122},
+["grey49"]={125, 125, 125},
+["grey5"]={13, 13, 13},
+["grey50"]={127, 127, 127},
+["grey51"]={130, 130, 130},
+["grey52"]={133, 133, 133},
+["grey53"]={135, 135, 135},
+["grey54"]={138, 138, 138},
+["grey55"]={140, 140, 140},
+["grey56"]={143, 143, 143},
+["grey57"]={145, 145, 145},
+["grey58"]={148, 148, 148},
+["grey59"]={150, 150, 150},
+["grey6"]={15, 15, 15},
+["grey60"]={153, 153, 153},
+["grey61"]={156, 156, 156},
+["grey62"]={158, 158, 158},
+["grey63"]={161, 161, 161},
+["grey64"]={163, 163, 163},
+["grey65"]={166, 166, 166},
+["grey66"]={168, 168, 168},
+["grey67"]={171, 171, 171},
+["grey68"]={173, 173, 173},
+["grey69"]={176, 176, 176},
+["grey7"]={18, 18, 18},
+["grey70"]={179, 179, 179},
+["grey71"]={181, 181, 181},
+["grey72"]={184, 184, 184},
+["grey73"]={186, 186, 186},
+["grey74"]={189, 189, 189},
+["grey75"]={191, 191, 191},
+["grey76"]={194, 194, 194},
+["grey77"]={196, 196, 196},
+["grey78"]={199, 199, 199},
+["grey79"]={201, 201, 201},
+["grey8"]={20, 20, 20},
+["grey80"]={204, 204, 204},
+["grey81"]={207, 207, 207},
+["grey82"]={209, 209, 209},
+["grey83"]={212, 212, 212},
+["grey84"]={214, 214, 214},
+["grey85"]={217, 217, 217},
+["grey86"]={219, 219, 219},
+["grey87"]={222, 222, 222},
+["grey88"]={224, 224, 224},
+["grey89"]={227, 227, 227},
+["grey9"]={23, 23, 23},
+["grey90"]={229, 229, 229},
+["grey91"]={232, 232, 232},
+["grey92"]={235, 235, 235},
+["grey93"]={237, 237, 237},
+["grey94"]={240, 240, 240},
+["grey95"]={242, 242, 242},
+["grey96"]={245, 245, 245},
+["grey97"]={247, 247, 247},
+["grey98"]={250, 250, 250},
+["grey99"]={252, 252, 252},
+["honeydew"]={240, 255, 240},
+["honeydew1"]={240, 255, 240},
+["honeydew2"]={224, 238, 224},
+["honeydew3"]={193, 205, 193},
+["honeydew4"]={131, 139, 131},
+["hot pink"]={255, 105, 180},
+["HotPink"]={255, 105, 180},
+["HotPink1"]={255, 110, 180},
+["HotPink2"]={238, 106, 167},
+["HotPink3"]={205, 96, 144},
+["HotPink4"]={139, 58, 98},
+["indian red"]={205, 92, 92},
+["IndianRed"]={205, 92, 92},
+["IndianRed1"]={255, 106, 106},
+["IndianRed2"]={238, 99, 99},
+["IndianRed3"]={205, 85, 85},
+["IndianRed4"]={139, 58, 58},
+["ivory"]={255, 255, 240},
+["ivory1"]={255, 255, 240},
+["ivory2"]={238, 238, 224},
+["ivory3"]={205, 205, 193},
+["ivory4"]={139, 139, 131},
+["khaki"]={240, 230, 140},
+["khaki1"]={255, 246, 143},
+["khaki2"]={238, 230, 133},
+["khaki3"]={205, 198, 115},
+["khaki4"]={139, 134, 78},
+["lavender"]={230, 230, 250},
+["lavender blush"]={255, 240, 245},
+["LavenderBlush"]={255, 240, 245},
+["LavenderBlush1"]={255, 240, 245},
+["LavenderBlush2"]={238, 224, 229},
+["LavenderBlush3"]={205, 193, 197},
+["LavenderBlush4"]={139, 131, 134},
+["lawn green"]={124, 252, 0},
+["LawnGreen"]={124, 252, 0},
+["lemon chiffon"]={255, 250, 205},
+["LemonChiffon"]={255, 250, 205},
+["LemonChiffon1"]={255, 250, 205},
+["LemonChiffon2"]={238, 233, 191},
+["LemonChiffon3"]={205, 201, 165},
+["LemonChiffon4"]={139, 137, 112},
+["light blue"]={173, 216, 230},
+["light coral"]={240, 128, 128},
+["light cyan"]={224, 255, 255},
+["light goldenrod"]={238, 221, 130},
+["light goldenrod yellow"]={250, 250, 210},
+["light gray"]={211, 211, 211},
+["light grey"]={211, 211, 211},
+["light pink"]={255, 182, 193},
+["light salmon"]={255, 160, 122},
+["light sea green"]={32, 178, 170},
+["light sky blue"]={135, 206, 250},
+["light slate blue"]={132, 112, 255},
+["light slate gray"]={119, 136, 153},
+["light slate grey"]={119, 136, 153},
+["light steel blue"]={176, 196, 222},
+["light yellow"]={255, 255, 224},
+["LightBlue"]={173, 216, 230},
+["LightBlue1"]={191, 239, 255},
+["LightBlue2"]={178, 223, 238},
+["LightBlue3"]={154, 192, 205},
+["LightBlue4"]={104, 131, 139},
+["LightCoral"]={240, 128, 128},
+["LightCyan"]={224, 255, 255},
+["LightCyan1"]={224, 255, 255},
+["LightCyan2"]={209, 238, 238},
+["LightCyan3"]={180, 205, 205},
+["LightCyan4"]={122, 139, 139},
+["LightGoldenrod"]={238, 221, 130},
+["LightGoldenrod1"]={255, 236, 139},
+["LightGoldenrod2"]={238, 220, 130},
+["LightGoldenrod3"]={205, 190, 112},
+["LightGoldenrod4"]={139, 129, 76},
+["LightGoldenrodYellow"]={250, 250, 210},
+["LightGray"]={211, 211, 211},
+["LightGrey"]={211, 211, 211},
+["LightPink"]={255, 182, 193},
+["LightPink1"]={255, 174, 185},
+["LightPink2"]={238, 162, 173},
+["LightPink3"]={205, 140, 149},
+["LightPink4"]={139, 95, 101},
+["LightSalmon"]={255, 160, 122},
+["LightSalmon1"]={255, 160, 122},
+["LightSalmon2"]={238, 149, 114},
+["LightSalmon3"]={205, 129, 98},
+["LightSalmon4"]={139, 87, 66},
+["LightSeaGreen"]={32, 178, 170},
+["LightSkyBlue"]={135, 206, 250},
+["LightSkyBlue1"]={176, 226, 255},
+["LightSkyBlue2"]={164, 211, 238},
+["LightSkyBlue3"]={141, 182, 205},
+["LightSkyBlue4"]={96, 123, 139},
+["LightSlateBlue"]={132, 112, 255},
+["LightSlateGray"]={119, 136, 153},
+["LightSlateGrey"]={119, 136, 153},
+["LightSteelBlue"]={176, 196, 222},
+["LightSteelBlue1"]={202, 225, 255},
+["LightSteelBlue2"]={188, 210, 238},
+["LightSteelBlue3"]={162, 181, 205},
+["LightSteelBlue4"]={110, 123, 139},
+["LightYellow"]={255, 255, 224},
+["LightYellow1"]={255, 255, 224},
+["LightYellow2"]={238, 238, 209},
+["LightYellow3"]={205, 205, 180},
+["LightYellow4"]={139, 139, 122},
+["lime green"]={50, 205, 50},
+["LimeGreen"]={50, 205, 50},
+["linen"]={250, 240, 230},
+["magenta"]={255, 0, 255},
+["magenta1"]={255, 0, 255},
+["magenta2"]={238, 0, 238},
+["magenta3"]={205, 0, 205},
+["magenta4"]={139, 0, 139},
+["maroon"]={176, 48, 96},
+["maroon1"]={255, 52, 179},
+["maroon2"]={238, 48, 167},
+["maroon3"]={205, 41, 144},
+["maroon4"]={139, 28, 98},
+["medium aquamarine"]={102, 205, 170},
+["medium blue"]={0, 0, 205},
+["medium orchid"]={186, 85, 211},
+["medium purple"]={147, 112, 219},
+["medium sea green"]={60, 179, 113},
+["medium slate blue"]={123, 104, 238},
+["medium spring green"]={0, 250, 154},
+["medium turquoise"]={72, 209, 204},
+["medium violet red"]={199, 21, 133},
+["MediumAquamarine"]={102, 205, 170},
+["MediumBlue"]={0, 0, 205},
+["MediumOrchid"]={186, 85, 211},
+["MediumOrchid1"]={224, 102, 255},
+["MediumOrchid2"]={209, 95, 238},
+["MediumOrchid3"]={180, 82, 205},
+["MediumOrchid4"]={122, 55, 139},
+["MediumPurple"]={147, 112, 219},
+["MediumPurple1"]={171, 130, 255},
+["MediumPurple2"]={159, 121, 238},
+["MediumPurple3"]={137, 104, 205},
+["MediumPurple4"]={93, 71, 139},
+["MediumSeaGreen"]={60, 179, 113},
+["MediumSlateBlue"]={123, 104, 238},
+["MediumSpringGreen"]={0, 250, 154},
+["MediumTurquoise"]={72, 209, 204},
+["MediumVioletRed"]={199, 21, 133},
+["midnight blue"]={25, 25, 112},
+["MidnightBlue"]={25, 25, 112},
+["mint cream"]={245, 255, 250},
+["MintCream"]={245, 255, 250},
+["misty rose"]={255, 228, 225},
+["MistyRose"]={255, 228, 225},
+["MistyRose1"]={255, 228, 225},
+["MistyRose2"]={238, 213, 210},
+["MistyRose3"]={205, 183, 181},
+["MistyRose4"]={139, 125, 123},
+["moccasin"]={255, 228, 181},
+["navajo white"]={255, 222, 173},
+["NavajoWhite"]={255, 222, 173},
+["NavajoWhite1"]={255, 222, 173},
+["NavajoWhite2"]={238, 207, 161},
+["NavajoWhite3"]={205, 179, 139},
+["NavajoWhite4"]={139, 121, 94},
+["navy"]={0, 0, 128},
+["navy blue"]={0, 0, 128},
+["NavyBlue"]={0, 0, 128},
+["old lace"]={253, 245, 230},
+["OldLace"]={253, 245, 230},
+["olive drab"]={107, 142, 35},
+["OliveDrab"]={107, 142, 35},
+["OliveDrab1"]={192, 255, 62},
+["OliveDrab2"]={179, 238, 58},
+["OliveDrab3"]={154, 205, 50},
+["OliveDrab4"]={105, 139, 34},
+["orange"]={255, 165, 0},
+["orange red"]={255, 69, 0},
+["orange1"]={255, 165, 0},
+["orange2"]={238, 154, 0},
+["orange3"]={205, 133, 0},
+["orange4"]={139, 90, 0},
+["OrangeRed"]={255, 69, 0},
+["OrangeRed1"]={255, 69, 0},
+["OrangeRed2"]={238, 64, 0},
+["OrangeRed3"]={205, 55, 0},
+["OrangeRed4"]={139, 37, 0},
+["orchid"]={218, 112, 214},
+["orchid1"]={255, 131, 250},
+["orchid2"]={238, 122, 233},
+["orchid3"]={205, 105, 201},
+["orchid4"]={139, 71, 137},
+["pale goldenrod"]={238, 232, 170},
+["pale green"]={152, 251, 152},
+["pale turquoise"]={175, 238, 238},
+["pale violet red"]={219, 112, 147},
+["PaleGoldenrod"]={238, 232, 170},
+["PaleGreen"]={152, 251, 152},
+["PaleGreen1"]={154, 255, 154},
+["PaleGreen2"]={144, 238, 144},
+["PaleGreen3"]={124, 205, 124},
+["PaleGreen4"]={84, 139, 84},
+["PaleTurquoise"]={175, 238, 238},
+["PaleTurquoise1"]={187, 255, 255},
+["PaleTurquoise2"]={174, 238, 238},
+["PaleTurquoise3"]={150, 205, 205},
+["PaleTurquoise4"]={102, 139, 139},
+["PaleVioletRed"]={219, 112, 147},
+["PaleVioletRed1"]={255, 130, 171},
+["PaleVioletRed2"]={238, 121, 159},
+["PaleVioletRed3"]={205, 104, 137},
+["PaleVioletRed4"]={139, 71, 93},
+["papaya whip"]={255, 239, 213},
+["PapayaWhip"]={255, 239, 213},
+["peach puff"]={255, 218, 185},
+["PeachPuff"]={255, 218, 185},
+["PeachPuff1"]={255, 218, 185},
+["PeachPuff2"]={238, 203, 173},
+["PeachPuff3"]={205, 175, 149},
+["PeachPuff4"]={139, 119, 101},
+["peru"]={205, 133, 63},
+["pink"]={255, 192, 203},
+["pink1"]={255, 181, 197},
+["pink2"]={238, 169, 184},
+["pink3"]={205, 145, 158},
+["pink4"]={139, 99, 108},
+["plum"]={221, 160, 221},
+["plum1"]={255, 187, 255},
+["plum2"]={238, 174, 238},
+["plum3"]={205, 150, 205},
+["plum4"]={139, 102, 139},
+["powder blue"]={176, 224, 230},
+["PowderBlue"]={176, 224, 230},
+["purple"]={160, 32, 240},
+["purple1"]={155, 48, 255},
+["purple2"]={145, 44, 238},
+["purple3"]={125, 38, 205},
+["purple4"]={85, 26, 139},
+["red"]={255, 0, 0},
+["red1"]={255, 0, 0},
+["red2"]={238, 0, 0},
+["red3"]={205, 0, 0},
+["red4"]={139, 0, 0},
+["rosy brown"]={188, 143, 143},
+["RosyBrown"]={188, 143, 143},
+["RosyBrown1"]={255, 193, 193},
+["RosyBrown2"]={238, 180, 180},
+["RosyBrown3"]={205, 155, 155},
+["RosyBrown4"]={139, 105, 105},
+["royal blue"]={65, 105, 225},
+["RoyalBlue"]={65, 105, 225},
+["RoyalBlue1"]={72, 118, 255},
+["RoyalBlue2"]={67, 110, 238},
+["RoyalBlue3"]={58, 95, 205},
+["RoyalBlue4"]={39, 64, 139},
+["saddle brown"]={139, 69, 19},
+["SaddleBrown"]={139, 69, 19},
+["salmon"]={250, 128, 114},
+["salmon1"]={255, 140, 105},
+["salmon2"]={238, 130, 98},
+["salmon3"]={205, 112, 84},
+["salmon4"]={139, 76, 57},
+["sandy brown"]={244, 164, 96},
+["SandyBrown"]={244, 164, 96},
+["sea green"]={46, 139, 87},
+["SeaGreen"]={46, 139, 87},
+["SeaGreen1"]={84, 255, 159},
+["SeaGreen2"]={78, 238, 148},
+["SeaGreen3"]={67, 205, 128},
+["SeaGreen4"]={46, 139, 87},
+["seashell"]={255, 245, 238},
+["seashell1"]={255, 245, 238},
+["seashell2"]={238, 229, 222},
+["seashell3"]={205, 197, 191},
+["seashell4"]={139, 134, 130},
+["sienna"]={160, 82, 45},
+["sienna1"]={255, 130, 71},
+["sienna2"]={238, 121, 66},
+["sienna3"]={205, 104, 57},
+["sienna4"]={139, 71, 38},
+["sky blue"]={135, 206, 235},
+["SkyBlue"]={135, 206, 235},
+["SkyBlue1"]={135, 206, 255},
+["SkyBlue2"]={126, 192, 238},
+["SkyBlue3"]={108, 166, 205},
+["SkyBlue4"]={74, 112, 139},
+["slate blue"]={106, 90, 205},
+["slate gray"]={112, 128, 144},
+["slate grey"]={112, 128, 144},
+["SlateBlue"]={106, 90, 205},
+["SlateBlue1"]={131, 111, 255},
+["SlateBlue2"]={122, 103, 238},
+["SlateBlue3"]={105, 89, 205},
+["SlateBlue4"]={71, 60, 139},
+["SlateGray"]={112, 128, 144},
+["SlateGray1"]={198, 226, 255},
+["SlateGray2"]={185, 211, 238},
+["SlateGray3"]={159, 182, 205},
+["SlateGray4"]={108, 123, 139},
+["SlateGrey"]={112, 128, 144},
+["snow"]={255, 250, 250},
+["snow1"]={255, 250, 250},
+["snow2"]={238, 233, 233},
+["snow3"]={205, 201, 201},
+["snow4"]={139, 137, 137},
+["spring green"]={0, 255, 127},
+["SpringGreen"]={0, 255, 127},
+["SpringGreen1"]={0, 255, 127},
+["SpringGreen2"]={0, 238, 118},
+["SpringGreen3"]={0, 205, 102},
+["SpringGreen4"]={0, 139, 69},
+["steel blue"]={70, 130, 180},
+["SteelBlue"]={70, 130, 180},
+["SteelBlue1"]={99, 184, 255},
+["SteelBlue2"]={92, 172, 238},
+["SteelBlue3"]={79, 148, 205},
+["SteelBlue4"]={54, 100, 139},
+["tan"]={210, 180, 140},
+["tan1"]={255, 165, 79},
+["tan2"]={238, 154, 73},
+["tan3"]={205, 133, 63},
+["tan4"]={139, 90, 43},
+["thistle"]={216, 191, 216},
+["thistle1"]={255, 225, 255},
+["thistle2"]={238, 210, 238},
+["thistle3"]={205, 181, 205},
+["thistle4"]={139, 123, 139},
+["tomato"]={255, 99, 71},
+["tomato1"]={255, 99, 71},
+["tomato2"]={238, 92, 66},
+["tomato3"]={205, 79, 57},
+["tomato4"]={139, 54, 38},
+["turquoise"]={64, 224, 208},
+["turquoise1"]={0, 245, 255},
+["turquoise2"]={0, 229, 238},
+["turquoise3"]={0, 197, 205},
+["turquoise4"]={0, 134, 139},
+["violet"]={238, 130, 238},
+["violet red"]={208, 32, 144},
+["VioletRed"]={208, 32, 144},
+["VioletRed1"]={255, 62, 150},
+["VioletRed2"]={238, 58, 140},
+["VioletRed3"]={205, 50, 120},
+["VioletRed4"]={139, 34, 82},
+["wheat"]={245, 222, 179},
+["wheat1"]={255, 231, 186},
+["wheat2"]={238, 216, 174},
+["wheat3"]={205, 186, 150},
+["wheat4"]={139, 126, 102},
+["white"]={255, 255, 255},
+["white smoke"]={245, 245, 245},
+["WhiteSmoke"]={245, 245, 245},
+["yellow"]={255, 255, 0},
+["yellow green"]={154, 205, 50},
+["yellow1"]={255, 255, 0},
+["yellow2"]={238, 238, 0},
+["yellow3"]={205, 205, 0},
+["yellow4"]={139, 139, 0},
+["YellowGreen"]={154, 205, 50}
+
+}
diff --git a/examples/lissajous/LICK/lib/docs/classes/Circle.html b/examples/lissajous/LICK/lib/docs/classes/Circle.html
new file mode 100644
index 0000000..852dc53
--- /dev/null
+++ b/examples/lissajous/LICK/lib/docs/classes/Circle.html
@@ -0,0 +1 @@
+
CircleCircle drawable circle
function(self, x, y, r, s, color)
Constructor draw(style)
draw the circle
\ No newline at end of file
diff --git a/examples/lissajous/LICK/lib/docs/classes/Drawable.html b/examples/lissajous/LICK/lib/docs/classes/Drawable.html
new file mode 100644
index 0000000..dcd58a1
--- /dev/null
+++ b/examples/lissajous/LICK/lib/docs/classes/Drawable.html
@@ -0,0 +1 @@
+DrawableDrawable base class for all drawable stuff
function(self, x, y, color)
Constructor wrapX(min, max)
can be called via wrapX(max) or wrapX(min,max)
wrapY(min, max)
can be called via wrapY(max) or wrapY(min,max)
wrap(str, min, max)
internal wrapper
set(str, val)
supercollider style 'set'
draw()
not yet implemented
\ No newline at end of file
diff --git a/examples/lissajous/LICK/lib/docs/classes/Line.html b/examples/lissajous/LICK/lib/docs/classes/Line.html
new file mode 100644
index 0000000..4faa005
--- /dev/null
+++ b/examples/lissajous/LICK/lib/docs/classes/Line.html
@@ -0,0 +1 @@
+LineLine draw a line
function(self, x, y, tx, ty)
Constructor
\ No newline at end of file
diff --git a/examples/lissajous/LICK/lib/docs/classes/Object.html b/examples/lissajous/LICK/lib/docs/classes/Object.html
new file mode 100644
index 0000000..84c6db9
--- /dev/null
+++ b/examples/lissajous/LICK/lib/docs/classes/Object.html
@@ -0,0 +1 @@
+ObjectObject base class
function(self)
Constructor
\ No newline at end of file
diff --git a/examples/lissajous/LICK/lib/docs/classes/SCObject.html b/examples/lissajous/LICK/lib/docs/classes/SCObject.html
new file mode 100644
index 0000000..2d1621a
--- /dev/null
+++ b/examples/lissajous/LICK/lib/docs/classes/SCObject.html
@@ -0,0 +1 @@
+SCObjectSCObject bass class for supercollider communication
function(self)
Constructor
\ No newline at end of file
diff --git a/examples/lissajous/LICK/lib/docs/classes/SCSynth.html b/examples/lissajous/LICK/lib/docs/classes/SCSynth.html
new file mode 100644
index 0000000..b2f94ac
--- /dev/null
+++ b/examples/lissajous/LICK/lib/docs/classes/SCSynth.html
@@ -0,0 +1 @@
+SCSynthSCSynth supercollider synthesizer class
function(self, nodename, freq)
Constructor set(control, val)
set a control, TODO: variable lenght of argument-pairs
os.time(),
bundle",
play()
sends an OSC message to the supercollider to start the synth
os.time(),
bundle",
free()
frees the node on the supercollider server
os.time()+0.8,
bundle",
\ No newline at end of file
diff --git a/examples/lissajous/LICK/lib/docs/guidelines.html b/examples/lissajous/LICK/lib/docs/guidelines.html
new file mode 100644
index 0000000..b394e30
--- /dev/null
+++ b/examples/lissajous/LICK/lib/docs/guidelines.html
@@ -0,0 +1,70 @@
+
+
+
+
+
+
+
+
+
+
+
+Guidelines for new live_libs classes
+
+1. Howto write a new class
+
+
+ <class name> =Â Class(<constructor>)
+ creates a class with function in constructor
+
+ <class name>:inherit(<other class name>)
+ if you want to inherit from any class.Everything should inherit directly or indirectly from object, because here the instance is added to the _internal_object_table
+
+If you want to call the constructor of the superclass write the following in the constructor of the current class:
+
+ <super class name>.<construct>(self, <arguments>)
+
+More on Classes and HUMP: http://vrld.github.com/hump/
+
+2. Commenting
+
+ In order to work the comment parser needs the following comment 'marks':
+
+
+ -- @ <class name>:<short description>
+ This marks a new class. The following line should be the class definition
+ Note: only one line comments are working
+
+ -- # <description>
+ This marks a new method.
+ Note: the limitations of class comments apply
+
+ any '--' without marks will not be included in the helpfile
+
+ Example:
+ -- @Drawable: base class for all drawable stuff
+ Drawable = Class(function(self, x, y, color)
+ self.color = color or hlpr.color("white",255)
+ -- call constructor of Object class
+ Object.construct(self)
+ self.position = Vector(x or 0,y or 0)
+ end)
+ Drawable:inherit(Object)
+
+ -- #can be called via wrapX(max) or wrapX(min,max)
+ function Drawable:wrapX(min, max)
+ if min and max then
+ self:wrap("x", min, max)
+ elseif min and not max thenÂ
+ self:wrap("x", 0, min)
+ end
+ end
+
+
+
+
diff --git a/examples/lissajous/LICK/lib/docs/guidelines.txt b/examples/lissajous/LICK/lib/docs/guidelines.txt
new file mode 100644
index 0000000..fd1010f
--- /dev/null
+++ b/examples/lissajous/LICK/lib/docs/guidelines.txt
@@ -0,0 +1,51 @@
+Guidelines for new live_libs classes
+
+1. Howto write a new class
+
+
+ = Class()
+ creates a class with function in constructor
+
+ :inherit()
+ if you want to inherit from any class. Everything should inherit directly or indirectly from object, because here the instance is added to the _internal_object_table
+
+If you want to call the constructor of the superclass write the following in the constructor of the current class:
+
+ .(self, )
+More on Classes and HUMP: http://vrld.github.com/hump/
+
+2. Commenting
+
+ In order to work the comment parser needs the following comment 'marks':
+
+
+ -- @ :
+ This marks a new class.
+ Note: only oneliners are working
+
+ -- #
+ This marks a new method.
+ Note: limitation of class comments apply
+
+ any '--' without marks will not be included in the helpfile
+
+ Example:
+ -- @Drawable: base class for all drawable stuff
+ Drawable = Class(function(self, x, y, color)
+ self.color = color or hlpr.color("white",255)
+ -- call constructor of Object class
+ Object.construct(self)
+ self.position = Vector(x or 0,y or 0)
+ end)
+ Drawable:inherit(Object)
+
+ -- #can be called via wrapX(max) or wrapX(min,max)
+ function Drawable:wrapX(min, max)
+ if min and max then
+ self:wrap("x", min, max)
+ elseif min and not max then
+ self:wrap("x", 0, min)
+ end
+ end
+
+
diff --git a/examples/lissajous/LICK/lib/docs/index.html b/examples/lissajous/LICK/lib/docs/index.html
new file mode 100644
index 0000000..6868575
--- /dev/null
+++ b/examples/lissajous/LICK/lib/docs/index.html
@@ -0,0 +1 @@
+live_libs_doclive_libs documentation
Guidelines for new classes and commentingClasses:
Object
SCObject
SCSynth
Drawable
Circle
Line
\ No newline at end of file
diff --git a/examples/lissajous/LICK/lib/help.lua b/examples/lissajous/LICK/lib/help.lua
new file mode 100644
index 0000000..744ffd4
--- /dev/null
+++ b/examples/lissajous/LICK/lib/help.lua
@@ -0,0 +1,109 @@
+-- parse the classes to readable html
+
+module(..., package.seeall)
+
+filename = "LICK/lib/object.lua"
+help_filename = "LICK/lib/docs/"
+
+-- some styles
+local style = ""
+
+local header1 = ""
+local header2 = ""..style..""
+local footer = ""
+local _newclasstitle = ""
+local newclasstitle_ = "
"
+local tab = " "
+
+
+-- generates the html file
+function generate()
+ class_file = love.filesystem.newFile( filename )
+ class_file:open('r')
+ local output = ""
+ output = header1.."test"..header2
+ local found_methods = 0
+ local found_classes = 0
+ local classes = {}
+ for line in class_file:lines() do
+ local b,e = string.find(line,"@")
+ local b1,e1 = string.find(line,"Class")
+ if b and e then
+ if found_classes > 0 then
+ output = output..footer
+ writeClassFile(name, output)
+ local output = ""
+
+ end
+ dp,ep = string.find(line, ":")
+ name = line:sub(e+1, dp-1 or 0)
+ print(name)
+ table.insert(classes,name)
+ output = header1..name..header2
+
+ output = output .._newclasstitle .. name..tab..tab..line:sub(dp+1) ..newclasstitle_
+ found_methods = 0
+ found_classes = found_classes + 1
+ elseif b1 and e1 and not string.find(line,"require") then
+ output = output ..""..tab..line:sub(e1+2).."
"..tab..tab.." Constructor"
+
+ end
+ local b,e = string.find(line,"#")
+ if method then
+ local dp,ep = string.find(line, ":")
+ ep = ep or 1
+ if found == 0 then
+ output = output .."Methods
"
+ found_methods = found_methods + 1
+ end
+ output = output.."".. tab ..line:sub(ep+1).."
"..tab..tab..method
+ method = nil
+ end
+ if b and e then
+ method = line:sub(e+1).."
"
+
+ --output = output..line:sub(e+1).."
"
+ end
+ end
+ output = output..footer
+ writeClassFile(name, output)
+
+ -- generate index.html
+ index = header1.."live_libs_doc"..header2
+ index = index.."live_libs documentation
"
+ index = index .. "Guidelines for new classes and commenting"
+ index = index.. "Classes:
"
+ for i,v in ipairs(classes) do
+ index = index..""..v.."
"
+ end
+ index = index..footer
+ writeFile("index", index)
+
+
+end
+
+function writeClassFile(name, output)
+ dir = love.filesystem.getWorkingDirectory( )
+ --print("touch "..dir.."/"..help_filename)
+ local path = dir.."/live_testproject/"..help_filename.."classes/"..name..".html"
+ os.execute("touch "..path)
+
+ local helpfile = io.open(path, "w" )
+ helpfile:write(output)
+ helpfile:close()
+
+end
+
+function writeFile(name, output)
+ dir = love.filesystem.getWorkingDirectory( )
+ --print("touch "..dir.."/"..help_filename)
+ local path = dir.."/live_testproject/"..help_filename..name..".html"
+ os.execute("touch "..path)
+
+ local helpfile = io.open(path, "w" )
+ helpfile:write(output)
+ helpfile:close()
+
+end
+
+
diff --git a/examples/lissajous/LICK/lib/hlpr.lua b/examples/lissajous/LICK/lib/hlpr.lua
new file mode 100644
index 0000000..13ded41
--- /dev/null
+++ b/examples/lissajous/LICK/lib/hlpr.lua
@@ -0,0 +1,350 @@
+-- hlpr libary: it's not about nice coding, ist about fast and easy coding
+-- by Rukano and Headchant, 2011
+
+
+-- global math
+pi = math.pi
+sin = math.sin
+deg = math.deg
+rad = math.rad
+
+State = State or {}
+
+function declare(t)
+ for i,v in pairs(t) do
+ if not State[i] then
+ State[i] = v
+ _G[i] = State[i]
+ end
+ end
+end
+require "LICK/lib/color"
+module(...,package.seeall)
+
+-- syntax shortcuts
+checkMode = love.graphics.checkMode
+circle = love.graphics.circle
+clear = love.graphics.clear
+draw = love.graphics.draw
+drawq = love.graphics.drawq
+getBackgroundColor = love.graphics.getBackgroundColor
+getBlendMode = love.graphics.getBlendMode
+getCaption =love.graphics.getCaption
+getColor = love.graphics.getColor
+getColorMode = love.graphics.getColorMode
+getFont = love.graphics.getFont
+getHeight = love.graphics.getHeight
+getLineStipple = love.graphics.getLineStipple
+getLineStyle = love.graphics.getLineStyle
+getLineWidth = love.graphics.getLineWidth
+getMaxPointSize = love.graphics.getMaxPointSize
+getModes = love.graphics.getModes
+getPointSize = love.graphics.getPointSize
+getPointStyle = love.graphics.getPointStyle
+getScissor = love.graphics.getScissor
+getWidth = love.graphics.getWidth
+isCreated = love.graphics.isCreated
+line = love.graphics.line
+newFont = love.graphics.newFont
+newFrameBuffer = love.graphics.newFramebuffer
+newImage = love.graphics.newImage
+newImageFont = love.graphics.newImageFont
+newParticleSystem = love.graphics.newParticleSystem
+newQuad = love.graphics.newQuad
+newScreenshot = love.graphics.newScreenshot
+newSpriteBatch = love.graphics.newSpriteBatch
+point = love.graphics.point
+polygon = love.graphics.polygon
+pop = love.graphics.pop
+present = love.graphics.present
+print = love.graphics.print
+printf = love.graphics.printf
+push = love.graphics.push
+quad = love.graphics.quad
+rectagle = love.graphics.rectangle
+reset = love.graphics.reset
+rotate = love.graphics.rotate
+scale = love.graphics.scale
+setBackgroundColor = love.graphics.setBackgroundColor
+setBlendMode = love.graphics.setBlendMode
+setCaption = love.graphics.setCaption
+setColor = love.graphics.setColor
+setColorMode = love.graphics.setColorMode
+setFont = love.graphics.setFont
+setIcon = love.graphics.setIcon
+setLine = love.graphics.setLine
+setLineStipple = love.graphics.setLineStipple
+setLineStyle = love.graphics.setLineStyle
+setLineWidth = love.graphics.setLineWidth
+setMode = love.graphics.setMode
+setPoint = love.graphics.setPoint
+setPointSize = love.graphics.setPointSize
+setPointStyle = love.graphics.setPointStyle
+setRenderTarget = love.graphics.setRenderTarget
+setScissor = love.graphics.setScissor
+toggleFullscreen = love.graphics.toggleFullscreen
+translate = love.graphics.translate
+triangle = love.graphics.triangle
+
+
+
+
+
+
+function color(r, g,b,a)
+ local color={}
+ local alpha=a or 255
+ local name=r or "azure"
+ if type(r) == "string" then
+ alpha = g or alpha
+ color = x11_color_table[name]
+ else
+ color[1]=r
+ color[2]=g
+ color[3]=b
+ end
+ color[4]=alpha
+ return color
+end
+
+-- clip withing range
+function clip(n,min,max)
+ return math.min(math.max(n, min or -math.huge), max or math.huge)
+end
+
+-- wrap within range, updated version
+function wrap(n, min, max)
+ local min = min or 0
+ return ((n - min) % ((max or 0) - min)) + min
+end
+
+-- setColor white
+function white()
+ love.graphics.setColor(255,255,255,255)
+end
+
+-- setColor black
+function black()
+ love.graphics.setColor(0,0,0,255)
+end
+
+-- shorter setColor white
+function w()
+ white()
+end
+
+-- shorter setColor black
+function b()
+ black()
+end
+
+-- fill the screen with translucent black
+function clear(alpha)
+ love.graphics.setColor(0,0,0,alpha)
+ love.graphics.rectangle("fill", 0,0,800,600)
+end
+
+-- shorter clear
+function cls(alpha)
+ clear(alpha)
+end
+
+-- one time clear
+function cls_once()
+ love.graphics.setColor(0,0,0,255)
+ love.graphics.rectangle("fill", 0,0,800,600)
+end
+
+
+-- returns random values from -1 to 1, g sets the equidistance
+function norm_random()
+ return 2 * math.random() - 1
+end
+
+-- shorte norm_random
+function n_rnd()
+ return norm_random()
+end
+
+-- drunk, brownnoise/drunk walk: x = x +/- random(width)
+function drunk(x, width, g)
+ x = x or 0
+ width = width or 1
+ g = g or 100
+ return (x + width*norm_random())
+end
+
+
+-- drnk, shorter version of drunk, start is only used the first time
+-- this makes some sense whatsoever...
+function drnk(width)
+ local last = 0
+ return function()
+ last = last + width * norm_random()
+ return last
+ end
+end
+
+-- scaling functions:
+
+function linlin(n,inMin,inMax,outMin,outMax,clip)
+ -- ported and adapted from:
+ -- SuperCollider SimpleNumber:linlin
+
+ local n=n or 0 -- to avoid giving back nil
+ local clip=clip or "minmax" -- default:clip minmax
+
+ if (inMin == nil) or (inMax == nil) or (outMin == nil) or (outMax == nil) then
+ -- just in case you forgot the parameters...
+ return n
+ end
+
+ if clip == "minmax" then
+ if n <= inMin then
+ return minoutMin
+ elseif n >= inMax then
+ return outMax
+ end
+ elseif clip == "min" then
+ if n <= inMin then
+ return outMin
+ end
+ elseif clip == "max" then
+ if n >= inMax then
+ return outMax
+ end
+ end
+
+ -- here is the magic!
+ n = (((n-inMin)/(inMax-inMin)) * (outMax-outMin)) + outMin
+ return n
+end
+
+function linexp(n,inMin,inMax,outMin,outMax,clip)
+ -- ported and adapted from:
+ -- SuperCollider SimpleNumber:linexp
+
+ local n=n or 0.00001 -- to avoid giving back nil
+ local clip=clip or "minmax" -- default:clip minmax
+
+ if (inMin == nil) or (inMax == nil) or (outMin == nil) or (outMax == nil) then
+ -- just in case...
+ return n
+ end
+
+ if clip == "minmax" then
+ if n <= inMin then
+ return outMin
+ elseif n >= inMax then
+ return outMax
+ end
+ elseif clip == "min" then
+ if n <= inMin then
+ return outMin
+ end
+ elseif clip == "max" then
+ if n >= inMax then
+ return outMax
+ end
+ end
+
+ -- here is the magic!
+ n = math.pow(outMax/outMin, (n-inMin)/(inMax-inMin)) * outMin
+ return n
+end
+
+function explin(n,inMin,inMax,outMin,outMax,clip)
+ -- ported and adapted from:
+ -- SuperCollider SimpleNumber:explin
+
+ local n=n or 0.00001 -- to avoid giving back nil
+ local clip=clip or "minmax" -- default:clip minmax
+
+ if (inMin == nil) or (inMax == nil) or (outMin == nil) or (outMax == nil) then
+ -- just in case...
+ return n
+ end
+
+ if clip == "minmax" then
+ if n <= inMin then
+ return outMin
+ elseif n >= inMax then
+ return outMax
+ end
+ elseif clip == "min" then
+ if n <= inMin then
+ return outMin
+ end
+ elseif clip == "max" then
+ if n >= inMax then
+ return outMax
+ end
+ end
+
+ -- here is the magic!
+ n = (((math.log(n/inMin)) / (math.log(inMax/inMin))) * (outMax-outMin)) + outMin
+ return n
+end
+
+function expexp(n,inMin,inMax,outMin,outMax,clip)
+ -- ported and adapted from:
+ -- SuperCollider SimpleNumber:expexp
+
+ local n=n or 0.00001 -- to avoid giving back nil
+ local clip=clip or "minmax" -- default:clip minmax
+
+ if (inMin == nil) or (inMax == nil) or (outMin == nil) or (outMax == nil) then
+ -- just in case...
+ return n
+ end
+
+ if clip == "minmax" then
+ if n <= inMin then
+ return outMin
+ elseif n >= inMax then
+ return outMax
+ end
+ elseif clip == "min" then
+ if n <= inMin then
+ return outMin
+ end
+ elseif clip == "max" then
+ if n >= inMax then
+ return outMax
+ end
+ end
+ -- here is the magic!
+ n = math.pow(outMax/outMin, math.log(n/inMin) / math.log(inMax/inMin)) * outMin
+ return n
+end
+
+-- returns easy sine oscillator
+function sin()
+ local x = 0
+ return function(dt)
+ x = x + (dt or 0)
+ if x > 2 * pi then x = x - 2*pi end
+ return math.sin(x)
+ end
+end
+
+-- updates all objects in the _object table
+function update_objects()
+ for i,v in ipairs(_internal_object_table) do
+ v:update(dt)
+ end
+end
+
+-- rotate around center
+function rotateCenter(angle)
+ local angle=angle or 0
+ local w, h = getWidth(), getHeight()
+ translate(w/2, h/2)
+ rotate(angle)
+ translate(-w/2, -h/2)
+end
+
+-- return a random table entry
+function choose(table)
+ return table[math.random(#table)]
+end
diff --git a/examples/lissajous/LICK/lib/hump/README.md b/examples/lissajous/LICK/lib/hump/README.md
new file mode 100644
index 0000000..759c724
--- /dev/null
+++ b/examples/lissajous/LICK/lib/hump/README.md
@@ -0,0 +1,48 @@
+HUMP - Helper Utilities for Massive Progression
+===============================================
+
+__HUMP__ is a small collection of tools for developing games with LÖVE.
+
+Contents:
+------------
+
+* *vector.lua*: powerful vector class (pure lua)
+* *class.lua*: "class" system supporting function inheritance (pure lua)
+* *camera.lua*: translate-, zoom- and rotatable camera
+* *gamestate.lua*: class to handle gamestates
+* *ringbuffer.lua*: a circular container
+* *sequence.lua*: utility to handle ingame cutscenes and such
+
+Documentation
+=============
+
+You can find the documentation here: [http://vrld.github.com/hump/](http://vrld.github.com/hump/ "project page")
+
+
+License
+=======
+Yay, *free software*:
+
+> Copyright (c) 2010 Matthias Richter
+>
+> Permission is hereby granted, free of charge, to any person obtaining a copy
+> of this software and associated documentation files (the "Software"), to deal
+> in the Software without restriction, including without limitation the rights
+> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+> copies of the Software, and to permit persons to whom the Software is
+> furnished to do so, subject to the following conditions:
+>
+> The above copyright notice and this permission notice shall be included in
+> all copies or substantial portions of the Software.
+>
+> Except as contained in this notice, the name(s) of the above copyright holders
+> shall not be used in advertising or otherwise to promote the sale, use or
+> other dealings in this Software without prior written authorization.
+>
+> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+> THE SOFTWARE.
diff --git a/examples/lissajous/LICK/lib/hump/camera.lua b/examples/lissajous/LICK/lib/hump/camera.lua
new file mode 100644
index 0000000..4bd8d14
--- /dev/null
+++ b/examples/lissajous/LICK/lib/hump/camera.lua
@@ -0,0 +1,90 @@
+--[[
+Copyright (c) 2010 Matthias Richter
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+Except as contained in this notice, the name(s) of the above copyright holders
+shall not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+]]--
+
+local setmetatable, require, love = setmetatable, require, love
+module(...)
+local vector = require(_PACKAGE..'vector')
+
+local camera = {}
+camera.__index = camera
+
+function new(pos, zoom, rot)
+ local pos = pos or vector(love.graphics.getWidth(), love.graphics.getHeight()) / 2
+ local zoom = zoom or 1
+ local rot = rot or 0
+ return setmetatable({pos = pos, zoom = zoom, rot = rot}, camera)
+end
+
+function camera:rotate(phi)
+ self.rot = self.rot + phi
+end
+
+function camera:translate(t)
+ self.pos = self.pos + t
+end
+camera.move = camera.translate
+
+function camera:predraw()
+ local center = vector(love.graphics.getWidth(), love.graphics.getHeight()) / (self.zoom * 2)
+ love.graphics.push()
+ love.graphics.scale(self.zoom)
+ love.graphics.translate(center:unpack())
+ love.graphics.rotate(self.rot)
+ love.graphics.translate((-self.pos):unpack())
+end
+
+function camera:postdraw()
+ love.graphics.pop()
+end
+
+function camera:draw(func)
+ self:predraw()
+ func()
+ self:postdraw()
+end
+
+function camera:toCameraCoords(p)
+ local w,h = love.graphics.getWidth(), love.graphics.getHeight()
+ local p = (p - self.pos):rotate_inplace(self.rot)
+ return vector(p.x * self.zoom + w/2, p.y * self.zoom + h/2)
+end
+
+function camera:toWorldCoords(p)
+ local w,h = love.graphics.getWidth(), love.graphics.getHeight()
+ local p = vector((p.x-w/2) / self.zoom, (p.y-h/2) / self.zoom):rotate_inplace(-self.rot)
+ return p + self.pos
+end
+
+function camera:mousepos()
+ return self:toWorldCoords(vector(love.mouse.getPosition()))
+end
+
+-- camera() as a shortcut to new()
+do
+ local m = {}
+ m.__call = function(_, ...) return new(...) end
+ setmetatable(_M, m)
+end
diff --git a/examples/lissajous/LICK/lib/hump/class.lua b/examples/lissajous/LICK/lib/hump/class.lua
new file mode 100644
index 0000000..2b014b9
--- /dev/null
+++ b/examples/lissajous/LICK/lib/hump/class.lua
@@ -0,0 +1,82 @@
+--[[
+Copyright (c) 2010 Matthias Richter
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+Except as contained in this notice, the name(s) of the above copyright holders
+shall not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+]]--
+
+local setmetatable, getmetatable = setmetatable, getmetatable
+local type, assert, pairs = type, assert, pairs
+local tostring, string_format = tostring, string.format
+module(...)
+
+local function __NULL__() end
+function new(constructor)
+ -- check name and constructor
+ local name = ''
+ if type(constructor) == "table" then
+ if constructor.name then name = constructor.name end
+ constructor = constructor[1]
+ end
+ assert(not constructor or type(constructor) == "function",
+ string_format('%s: constructor has to be nil or a function', name))
+
+ -- build class
+ local c = {}
+ c.__index = c
+ c.__tostring = function() return string_format("", name) end
+ c.construct = constructor or __NULL__
+ c.Construct = constructor or __NULL__
+ c.inherit = inherit
+ c.Inherit = inherit
+
+ local meta = {
+ __call = function(self, ...)
+ local obj = {}
+ self.construct(obj, ...)
+ return setmetatable(obj, self)
+ end,
+ __tostring = function() return tostring(name) end
+ }
+
+ return setmetatable(c, meta)
+end
+
+function inherit(class, interface, ...)
+ if not interface then return end
+
+ -- __index and construct are not overwritten as for them class[name] is defined
+ for name, func in pairs(interface) do
+ if not class[name] and type(func) == "function" then
+ class[name] = func
+ end
+ end
+
+ inherit(class, ...)
+end
+
+-- class() as shortcut to class.new()
+do
+ local m = {}
+ m.__call = function(_, ...) return new(...) end
+ setmetatable(_M, m)
+end
diff --git a/examples/lissajous/LICK/lib/hump/gamestate.lua b/examples/lissajous/LICK/lib/hump/gamestate.lua
new file mode 100644
index 0000000..746f81b
--- /dev/null
+++ b/examples/lissajous/LICK/lib/hump/gamestate.lua
@@ -0,0 +1,154 @@
+--[[
+Copyright (c) 2010-2011 Matthias Richter
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+Except as contained in this notice, the name(s) of the above copyright holders
+shall not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+]]--
+
+local error, assert, love = error, assert, love
+module(...)
+
+local function __NULL__() end
+-- default gamestate produces error on every callback
+local function __ERROR__() error("Gamestate not initialized. Use Gamestate.switch()") end
+current = {
+ enter = __ERROR__,
+ leave = __NULL__,
+ update = __ERROR__,
+ draw = __ERROR__,
+ focus = __ERROR__,
+ keyreleased = __ERROR__,
+ keypressed = __ERROR__,
+ mousepressed = __ERROR__,
+ mousereleased = __ERROR__,
+ joystickpressed = __ERROR__,
+ joystickreleased = __ERROR__,
+ quit = __ERROR__,
+}
+
+function new()
+ return {
+ enter = __NULL__,
+ leave = __NULL__,
+ update = __NULL__,
+ draw = __NULL__,
+ focus = __NULL__,
+ keyreleased = __NULL__,
+ keypressed = __NULL__,
+ mousepressed = __NULL__,
+ mousereleased = __NULL__,
+ joystickpressed = __NULL__,
+ joystickreleased = __NULL__,
+ quit = __NULL__,
+ }
+end
+
+function switch(to, ...)
+ assert(to, "Missing argument: Gamestate to switch to")
+ current:leave()
+ local pre = current
+ current = to
+ return current:enter(pre, ...)
+end
+
+local _update
+function update(...)
+ if _update then _update(...) end
+ return current:update(...)
+end
+
+local _draw
+function draw(...)
+ if _draw then _draw(...) end
+ return current:draw(...)
+end
+
+local _focus
+function focus(...)
+ if _focus then _focus(...) end
+ return current:focus(...)
+end
+
+local _keypressed
+function keypressed(...)
+ if _keypressed then _keypressed(...) end
+ return current:keypressed(...)
+end
+
+local _keyreleased
+function keyreleased(...)
+ if _keyreleased then _keyreleased(...) end
+ return current:keyreleased(...)
+end
+
+local _mousepressed
+function mousepressed(...)
+ if _mousereleased then _mousepressed(...) end
+ return current:mousepressed(...)
+end
+
+local _mousereleased
+function mousereleased(...)
+ if _mousereleased then _mousereleased(...) end
+ return current:mousereleased(...)
+end
+
+local _joystickpressed
+function joystickpressed(...)
+ if _joystickpressed then _joystickpressed(...) end
+ return current:joystickpressed(...)
+end
+
+local _joystickreleased
+function joystickreleased(...)
+ if _joystickreleased then _joystickreleased(...) end
+ return current:joystickreleased(...)
+end
+
+local _quit
+function quit(...)
+ if _quit then _quit(...) end
+ return current:quit(...)
+end
+
+function registerEvents()
+ _update = love.update
+ love.update = update
+ _draw = love.draw
+ love.draw = draw
+ _focus = love.focus
+ love.focus = focus
+ _keypressed = love.keypressed
+ love.keypressed = keypressed
+ _keyreleased = love.keyreleased
+ love.keyreleased = keyreleased
+ _mousepressed = love.mousepressed
+ love.mousepressed = mousepressed
+ _mousereleased = love.mousereleased
+ love.mousereleased = mousereleased
+ _joystickpressed = love.joystickpressed
+ love.joystickpressed = joystickpressed
+ _joystickreleased = love.joystickreleased
+ love.joystickreleased = joystickreleased
+ _quit = love.quit
+ love.quit = quit
+end
diff --git a/examples/lissajous/LICK/lib/hump/ringbuffer.lua b/examples/lissajous/LICK/lib/hump/ringbuffer.lua
new file mode 100644
index 0000000..2b2b3cb
--- /dev/null
+++ b/examples/lissajous/LICK/lib/hump/ringbuffer.lua
@@ -0,0 +1,99 @@
+--[[
+Copyright (c) 2010 Matthias Richter
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+Except as contained in this notice, the name(s) of the above copyright holders
+shall not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+]]--
+
+local setmetatable, getmetatable, table = setmetatable, getmetatable, table
+module(...)
+local ringbuffer = {}
+ringbuffer.__index = ringbuffer
+
+function new(...)
+ local rb = {}
+ rb.items = {...}
+ rb.current = 1
+ return setmetatable(rb, ringbuffer)
+end
+
+function ringbuffer:insert(item, ...)
+ if not item then return end
+ -- insert rest before self so order is restored, e.g.:
+ -- {1,<2>,3}:insert(4,5) -> {1,<2>,3}:insert(5) -> {1,<2>,5,3} -> {1,<2>,4,5,3}
+ self:insert(...)
+ table.insert(self.items, self.current+1, item)
+end
+
+function ringbuffer:append(item, ...)
+ if not item then return end
+ self.items[#self.items+1] = item
+ return self:append(...)
+end
+
+function ringbuffer:removeAt(k)
+ -- wrap position
+ local pos = (self.current + k) % #self.items
+ while pos < 1 do pos = pos + #self.items end
+
+ -- remove item
+ local item = table.remove(self.items, pos)
+
+ -- possibly adjust current pointer
+ if pos < self.current then self.current = self.current - 1 end
+ if self.current > #self.items then self.current = 1 end
+
+ -- return item
+ return item
+end
+
+function ringbuffer:remove()
+ return table.remove(self.items, self.current)
+end
+
+function ringbuffer:get()
+ return self.items[self.current]
+end
+
+function ringbuffer:size()
+ return #self.items
+end
+
+function ringbuffer:next()
+ self.current = (self.current % #self.items) + 1
+ return self:get()
+end
+
+function ringbuffer:prev()
+ self.current = self.current - 1
+ if self.current < 1 then
+ self.current = #self.items
+ end
+ return self:get()
+end
+
+-- Ringbuffer() as a shortcut to Ringbuffer.new()
+do
+ local m = {}
+ m.__call = function(_, ...) return new(...) end
+ setmetatable(_M, m)
+end
diff --git a/examples/lissajous/LICK/lib/hump/timer.lua b/examples/lissajous/LICK/lib/hump/timer.lua
new file mode 100644
index 0000000..2ce460d
--- /dev/null
+++ b/examples/lissajous/LICK/lib/hump/timer.lua
@@ -0,0 +1,83 @@
+--[[
+Copyright (c) 2010 Matthias Richter
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+Except as contained in this notice, the name(s) of the above copyright holders
+shall not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+]]--
+
+local assert, type = assert, type
+local pairs, ipairs = pairs, ipairs
+local min = math.min
+module(...)
+
+functions = {}
+function update(dt)
+ local to_remove = {}
+ for func, delay in pairs(functions) do
+ delay = delay - dt
+ if delay <= 0 then
+ to_remove[#to_remove+1] = func
+ else
+ functions[func] = delay
+ end
+ end
+ for _,func in ipairs(to_remove) do
+ functions[func] = nil
+ func(func)
+ end
+end
+
+function add(delay, func)
+ assert(type(func) == "function", "second argument needs to be a function")
+ functions[func] = delay
+end
+
+function addPeriodic(delay, func, count)
+ assert(type(func) == "function", "second argument needs to be a function")
+ if count then
+ return add(delay, function(f) func(func) count = count - 1 if count > 0 then add(delay, f) end end)
+ end
+ return add(delay, function(f) func(func) add(delay, f) end)
+end
+
+function clear()
+ functions = {}
+end
+
+function Interpolator(length, func)
+ assert(type(func) == "function", "second argument needs to be a function")
+ local t = 0
+ return function(dt, ...)
+ t = t + dt
+ return t <= length and func((t-dt)/length, ...) or nil
+ end
+end
+
+function Oscillator(length, func)
+ assert(type(func) == "function", "second argument needs to be a function")
+ local t = 0
+ return function(dt, ...)
+ t = t + dt
+ while t > length do t = t - length end
+ return func(t/length, ...)
+ end
+end
diff --git a/examples/lissajous/LICK/lib/hump/vector.lua b/examples/lissajous/LICK/lib/hump/vector.lua
new file mode 100644
index 0000000..b84f948
--- /dev/null
+++ b/examples/lissajous/LICK/lib/hump/vector.lua
@@ -0,0 +1,156 @@
+--[[
+Copyright (c) 2010 Matthias Richter
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+Except as contained in this notice, the name(s) of the above copyright holders
+shall not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+]]--
+
+local setmetatable, getmetatable = setmetatable, getmetatable
+local assert, type, tonumber = assert, type, tonumber
+local sqrt, cos, sin = math.sqrt, math.cos, math.sin
+module(...)
+
+local vector = {}
+vector.__index = vector
+
+function new(x,y)
+ local v = {x = x or 0, y = y or 0}
+ setmetatable(v, vector)
+ return v
+end
+
+function isvector(v)
+ return getmetatable(v) == vector
+end
+
+function vector:clone()
+ return new(self.x, self.y)
+end
+
+function vector:unpack()
+ return self.x, self.y
+end
+
+function vector:__tostring()
+ return "("..tonumber(self.x)..","..tonumber(self.y)..")"
+end
+
+function vector.__unm(a)
+ return new(-a.x, -a.y)
+end
+
+function vector.__add(a,b)
+ assert(isvector(a) and isvector(b), "Add: wrong argument types ( expected)")
+ return new(a.x+b.x, a.y+b.y)
+end
+
+function vector.__sub(a,b)
+ assert(isvector(a) and isvector(b), "Sub: wrong argument types ( expected)")
+ return new(a.x-b.x, a.y-b.y)
+end
+
+function vector.__mul(a,b)
+ if type(a) == "number" then
+ return new(a*b.x, a*b.y)
+ elseif type(b) == "number" then
+ return new(b*a.x, b*a.y)
+ else
+ assert(isvector(a) and isvector(b), "Mul: wrong argument types ( or expected)")
+ return a.x*b.x + a.y*b.y
+ end
+end
+
+function vector.__div(a,b)
+ assert(isvector(a) and type(b) == "number", "wrong argument types (expected / )")
+ return new(a.x / b, a.y / b)
+end
+
+function vector.__eq(a,b)
+ return a.x == b.x and a.y == b.y
+end
+
+function vector.__lt(a,b)
+ return a.x < b.x or (a.x == b.x and a.y < b.y)
+end
+
+function vector.__le(a,b)
+ return a.x <= b.x and a.y <= b.y
+end
+
+function vector.permul(a,b)
+ assert(isvector(a) and isvector(b), "permul: wrong argument types ( expected)")
+ return new(a.x*b.x, a.y*b.y)
+end
+
+function vector:len2()
+ return self * self
+end
+
+function vector:len()
+ return sqrt(self*self)
+end
+
+function vector.dist(a, b)
+ assert(isvector(a) and isvector(b), "dist: wrong argument types ( expected)")
+ return (b-a):len()
+end
+
+function vector:normalize_inplace()
+ local l = self:len()
+ self.x, self.y = self.x / l, self.y / l
+ return self
+end
+
+function vector:normalized()
+ return self / self:len()
+end
+
+function vector:rotate_inplace(phi)
+ local c, s = cos(phi), sin(phi)
+ self.x, self.y = c * self.x - s * self.y, s * self.x + c * self.y
+ return self
+end
+
+function vector:rotated(phi)
+ return self:clone():rotate_inplace(phi)
+end
+
+function vector:perpendicular()
+ return new(-self.y, self.x)
+end
+
+function vector:projectOn(v)
+ assert(isvector(v), "invalid argument: cannot project onto anything other than a new.")
+ return (self * v) * v / v:len2()
+end
+
+function vector:cross(other)
+ assert(isvector(other), "cross: wrong argument types ( expected)")
+ return self.x * other.y - self.y * other.x
+end
+
+-- vector() as shortcut to vector.new()
+do
+ local m = {}
+ m.__call = function(_, ...) return new(...) end
+ setmetatable(_M, m)
+end
diff --git a/examples/lissajous/LICK/lib/images/circle.png b/examples/lissajous/LICK/lib/images/circle.png
new file mode 100755
index 0000000..8f9ac29
Binary files /dev/null and b/examples/lissajous/LICK/lib/images/circle.png differ
diff --git a/examples/lissajous/LICK/lib/images/cloud.png b/examples/lissajous/LICK/lib/images/cloud.png
new file mode 100755
index 0000000..5b338bd
Binary files /dev/null and b/examples/lissajous/LICK/lib/images/cloud.png differ
diff --git a/examples/lissajous/LICK/lib/images/cross.png b/examples/lissajous/LICK/lib/images/cross.png
new file mode 100755
index 0000000..386dfc1
Binary files /dev/null and b/examples/lissajous/LICK/lib/images/cross.png differ
diff --git a/examples/lissajous/LICK/lib/images/dots.png b/examples/lissajous/LICK/lib/images/dots.png
new file mode 100755
index 0000000..17619f5
Binary files /dev/null and b/examples/lissajous/LICK/lib/images/dots.png differ
diff --git a/examples/lissajous/LICK/lib/images/holger.png b/examples/lissajous/LICK/lib/images/holger.png
new file mode 100755
index 0000000..7e78b87
Binary files /dev/null and b/examples/lissajous/LICK/lib/images/holger.png differ
diff --git a/examples/lissajous/LICK/lib/images/smoke.png b/examples/lissajous/LICK/lib/images/smoke.png
new file mode 100755
index 0000000..ff3d803
Binary files /dev/null and b/examples/lissajous/LICK/lib/images/smoke.png differ
diff --git a/examples/lissajous/LICK/lib/images/spiral1.png b/examples/lissajous/LICK/lib/images/spiral1.png
new file mode 100755
index 0000000..79ddcbf
Binary files /dev/null and b/examples/lissajous/LICK/lib/images/spiral1.png differ
diff --git a/examples/lissajous/LICK/lib/images/spiral2.png b/examples/lissajous/LICK/lib/images/spiral2.png
new file mode 100755
index 0000000..d7b9627
Binary files /dev/null and b/examples/lissajous/LICK/lib/images/spiral2.png differ
diff --git a/examples/lissajous/LICK/lib/images/star.png b/examples/lissajous/LICK/lib/images/star.png
new file mode 100755
index 0000000..85395e8
Binary files /dev/null and b/examples/lissajous/LICK/lib/images/star.png differ
diff --git a/examples/lissajous/LICK/lib/images/sun.png b/examples/lissajous/LICK/lib/images/sun.png
new file mode 100755
index 0000000..862fda4
Binary files /dev/null and b/examples/lissajous/LICK/lib/images/sun.png differ
diff --git a/examples/lissajous/LICK/lib/init.lua b/examples/lissajous/LICK/lib/init.lua
new file mode 100644
index 0000000..0f629e6
--- /dev/null
+++ b/examples/lissajous/LICK/lib/init.lua
@@ -0,0 +1,4 @@
+-- init live_libs
+Vector = require "LICK/lib/hump/vector"
+require "LICK/lib/object"
+require "LICK/lib/loveosc"
diff --git a/examples/lissajous/LICK/lib/loveosc/README b/examples/lissajous/LICK/lib/loveosc/README
new file mode 100644
index 0000000..f456f13
--- /dev/null
+++ b/examples/lissajous/LICK/lib/loveosc/README
@@ -0,0 +1,8 @@
+loveOSC is a fork of luaOSC(http://luaforge.net/projects/luaosc/) which implements the Open Sound Control Protocol (http://opensoundcontrol.org/) but substitutes the LPACK dependency with VSTRUCT for greater portability
+
+
+The testproject sends a OSC message to a server on port 57110, which is Supercolliders OSC port. It also receives OSC messages on port 7771.
+
+Features:
+- Client, sending/encoding OSC messages/bundles
+- Server, receiving/decoding/handle OSC messages
diff --git a/examples/lissajous/LICK/lib/loveosc/client.lua b/examples/lissajous/LICK/lib/loveosc/client.lua
new file mode 100644
index 0000000..09fd143
--- /dev/null
+++ b/examples/lissajous/LICK/lib/loveosc/client.lua
@@ -0,0 +1,340 @@
+--[[
+ -- luaosc Copyright (C) 2009 Jost Tobias Springenberg --
+
+ This file is part of luaosc.
+
+ luaosc 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 3 of the License, or
+ (at your option) any later version.
+
+ luaosc 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 Foobar. If not, see .
+--]]
+
+-- This is a luaOSC Fork from Jost Tobias Springenberg, additional code and modifications by Tilmann Hars, Headchant.com, Copyright 2010
+
+local socket = require "socket"
+local base = _G
+local string = require("string")
+local vstruct = require "LICK/lib/loveosc/vstruct"
+local pack = vstruct.pack
+local upack = vstruct.unpack
+
+--------------------------------
+-- some constants
+--------------------------------
+
+osc.client = {}
+osc.client.host = "localhost"
+osc.client.port = 57110
+osc.client.timeout = 0
+
+PROTOCOL = "OSC/1.0"
+
+ADJUSTMENT_FACTOR = 2208988800
+
+IMMEDIATE = string.rep('0', 31) .. '1'
+
+
+function osc.client:send( data )
+ local ip, port = assert(socket.dns.toip(osc.client.host)), osc.client.port
+ -- create a new UDP object
+ local udp = assert(socket.udp())
+ udp:settimeout(0)
+
+ --print(encode(data))
+ assert(udp:sendto(encode(data), ip, port), "could not send data")
+ --assert(udp:sendto(data, ip, port), "could not send data")
+
+ -- retrieve the answer and print results, warning: crashes love
+ --print(udp:receive() or "")
+end
+
+
+--------------------------------
+-- interface functions:
+-- decode(string)
+-- and encode(table)
+--------------------------------
+
+function decode(data)
+ if #data == 0 then
+ return nil
+ end
+ if string.match(data, "^#bundle") then
+ return decode_bundle(data)
+ else
+ return decode_message(data)
+ end
+end
+
+
+function encode(data)
+ local msg = ""
+ local idx = 1
+ if data == nil then
+ return nil
+ end
+
+ if data[1] == "#bundle" then
+ msg = msg .. encode_string(data[1])
+ --print("1 "..msg.."\n")
+ msg = msg .. encode_timetag(data[2])
+ --print("2 "..msg.."\n")
+ idx = 3
+ while idx <= #data do
+ local submsg = encode(data[idx])
+ msg = msg .. encode_int(#submsg) .. submsg
+ --print(idx.." "..submsg.."\n")
+ idx = idx + 1
+ end
+ return msg
+ else
+ local typestring = ","
+ local encodings = ""
+ idx = idx + 1
+ msg = msg .. encode_string(data[1])
+ for t, d in iter_pairwise(data, idx) do
+ typestring = typestring .. t
+ encodings = encodings .. collect_encoding_for_message(t, d)
+ end
+ --print("else "..msg..encode_string(typestring) .. encodings.."\n")
+
+ return msg .. encode_string(typestring) .. encodings
+ end
+end
+
+
+--------------------------------
+-- auxilliary functions
+--------------------------------
+
+digits = {}
+for i=0,9 do digits[i] = string.char(string.byte('0')+i) end
+for i=10,36 do digits[i] = string.char(string.byte('A')+i-10) end
+
+function numberstring(number, bas)
+ local s = ""
+ repeat
+ local remainder = base.math.mod(number,bas)
+ s = digits[remainder]..s
+ number = (number-remainder)/bas
+ until number==0
+ return s
+end
+
+
+function next_string(astring)
+ -- this is a workaraound because the lua pttern matching is
+ -- not as powerful as pcre and I did not want to include another
+ -- dependecy to an external re lib
+ local pos = 0
+ local num_nzero = 0
+ local num_zero = 0
+ local result = ""
+ if astring == nil then
+ -- ensure that string is not empty
+ base.error("error: string is empty - probably malformated message")
+ end
+ -- we match every character with the help of gmatch
+ for m in string.gmatch(astring, ".") do
+ pos = pos + 1
+ -- and then check if it is correctly padded with '\0's
+ if m ~= '\0' and num_zero == 0 then
+ num_nzero = (num_nzero + 1) % 4
+ result = result .. m
+ elseif num_zero ~= 0 and (num_zero + num_nzero) % 4 == 0 then
+ return result, pos
+ elseif m == '\0' then
+ num_zero = num_zero + 1
+ result = result .. m
+ else
+ return nil
+ end
+ end
+end
+
+function iter_pairwise(atable, startvalue)
+ local index = startvalue - 2
+ return function()
+ index = index + 2
+ return atable[index], atable[index+1]
+ end
+end
+
+function collect_encoding_for_message(t, data)
+ if t == 'i' then
+ return encode_int(data)
+ elseif t == 'f' then
+ return encode_float(data)
+ elseif t == 's' then
+ return encode_string(data)
+ elseif t == 'b' then
+ return encode_blob(data)
+ end
+end
+
+function collect_decoding_from_message(t, data, message)
+ table.insert(message, t)
+ if t == 'i' then
+ table.insert(message, decode_int(data))
+ return string.sub(data, 5)
+ elseif t == 'f' then
+ table.insert(message, decode_float(data))
+ return string.sub(data, 5)
+ elseif t == 's' then
+ local match, last = next_string(data)
+ table.insert(message, match)
+ return string.sub(data, last)
+ elseif t == 'b' then
+ local length = decode_int(data)
+ table.insert(message, string.sub(data, 4, length))
+ return string.sub(data, 4 + length + 1)
+ end
+end
+
+function get_addr_from_data(data)
+ local addr_raw_string,last = next_string(data)
+ local result = ""
+ if addr_raw_string == nil then
+ -- if we could not find an addr something went wrong
+ base.error("error: could not extract address from OSC message")
+ end
+ -- delete possible trailing zeros
+ for t in string.gmatch(addr_raw_string, "[^%z]") do
+ result = result .. t
+ end
+ return result, string.sub(data, last)
+end
+
+function get_types_from_data(data)
+ local typestring, last = next_string(data)
+ local result = {}
+ if typestring == nil then
+ return {}
+ end
+ -- split typestring into an iterable table
+ for t in string.gmatch(typestring, "[^,%z]") do
+ table.insert(result, t)
+ end
+ return result, string.sub(data, last)
+end
+
+--------------------------------
+-- decoding functions
+--------------------------------
+
+function decode_message(data)
+ local types, addr, tmp_data = nil
+ local message = {}
+ addr, tmp_data = get_addr_from_data(data)
+ types, tmp_data = get_types_from_data(tmp_data)
+ -- ensure that we at least found something
+ if addr == nil or types == nil then
+ return nil
+ end
+ for _,t in base.ipairs(types) do
+ tmp_data = collect_decoding_from_message(t, tmp_data, message)
+ end
+ return message
+end
+
+
+function decode_bundle(data)
+ local match, last = next_string(data)
+ local tmp_data = nil
+ local msg = {}
+ local sec, frac
+ -- skip first string data since it will only contian #bundle
+ tmp_data = string.sub(data, 9)
+ -- check that there is a part of the message left
+ if not tmp_data then
+ return nil
+ end
+ table.insert(msg, "#bundle")
+ _, sec, frac = upack("> u4 > u4", {string.sub(tmp_data, 1, 8)})
+ -- note this is an awful way of decoding to a bin string and
+ -- then decoding the frac again TODO: make this nicer
+ frac = numberstring(frac, 2)
+ if sec == 0 and frac == IMMEDIATE then
+ table.insert(msg, 0)
+ else
+ table.insert(msg, sec - ADJUSTMENT_FACTOR + decode_frac(frac) )
+ end
+ tmp_data = string.sub(tmp_data, 9)
+ while #tmp_data > 0 do
+ local length = decode_int(string.sub(tmp_data,1,4))
+ table.insert(msg, decode(string.sub(tmp_data, 5, 4 + length)))
+ tmp_data = string.sub(tmp_data, 9 + length)
+ end
+ return msg
+end
+
+function decode_frac(bin)
+ local frac = 0
+ for i=#bin,1 do
+ frac = (frac + string.sub(bin, i-1, i)) / 2
+ end
+ return frac
+end
+
+function decode_float(bin)
+ local pos, res = upack("> f4", {bin})
+ return res
+end
+
+function decode_int(bin)
+ local pos, res = upack("> i4", {bin} )
+ return res
+end
+
+--------------------------------
+-- encoding
+--------------------------------
+
+function encode_string(astring)
+ local fillbits = (4 - #astring % 4)
+ return astring .. string.rep('\0', fillbits)
+end
+
+function encode_int(num)
+ return pack("> i4",{ num })
+end
+
+function encode_blob(blob)
+ return encode_int(#blob) .. encode_string(#blob)
+end
+
+function encode_timetag(tpoint)
+ if tpoint == 0 then
+ return IMMEDIATE
+ else
+ local sec = math.floor(tpoint)
+ local frac = tpoint - sec
+
+ return pack("> u4 > u4", {sec + ADJUSTMENT_FACTOR , encode_frac(frac)})
+
+ end
+end
+
+
+
+function encode_frac(num)
+ local bin = ""
+ local frac = num
+ while #bin < 32 do
+ bin = bin .. base.math.floor(frac * 2)
+ frac = (frac * 2) - base.math.floor(frac * 2)
+ end
+ return bin
+end
+
+function encode_float(num)
+ return pack("> f4", {num})
+end
diff --git a/examples/lissajous/LICK/lib/loveosc/init.lua b/examples/lissajous/LICK/lib/loveosc/init.lua
new file mode 100644
index 0000000..d7f0bfb
--- /dev/null
+++ b/examples/lissajous/LICK/lib/loveosc/init.lua
@@ -0,0 +1,3 @@
+osc = {}
+require "LICK/lib/loveosc/client"
+require "LICK/lib/loveosc/server"
diff --git a/examples/lissajous/LICK/lib/loveosc/server.lua b/examples/lissajous/LICK/lib/loveosc/server.lua
new file mode 100644
index 0000000..3a9a93f
--- /dev/null
+++ b/examples/lissajous/LICK/lib/loveosc/server.lua
@@ -0,0 +1,81 @@
+--[[
+ -- luaosc Copyright (C) 2009 Jost Tobias Springenberg --
+
+ This file is part of luaosc.
+
+ luaosc 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 3 of the License, or
+ (at your option) any later version.
+
+ luaosc 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 Foobar. If not, see .
+--]]
+
+-- This is a luaOSC Fork from Jost Tobias Springenberg, additional code and modifications by Tilmann Hars, Headchant.com, Copyright 2010
+
+require "socket"
+
+osc.server = {}
+osc.server.host = "localhost"
+osc.server.port = 7771
+osc.server.socket = socket.udp() or error('error could not create lua socket object')
+osc.server.socket:setsockname(osc.server.host, osc.server.port)
+osc.server.socket:settimeout(0)
+
+-- call this in LÖVE update
+function osc.server:update(dt)
+
+ local message, from = osc.server.socket:receive(1024)
+ -- invoke handler function
+ if message ~= nil then
+ local success, result = pcall(decode, message)
+ if not success then
+ print("Error in decoding: \n" .. result)
+ else
+ success, result = pcall(handle, from, result)
+ if not success then
+ print("Error in your handler function: \n" .. result)
+ end
+ end
+ end
+ if message == "exit" then
+ return
+ end
+
+end
+
+
+-- use this to start the server in lua only (not with LÖVE!)
+function osc.server:start()
+ local length = 1024
+ while 1 do
+ local message, from = self.socket:receivefrom(1024)
+ -- invoke handler function
+ if message ~= nil then
+ local success, result = base.pcall(osc.decode, message)
+ if not success then
+ base.io.stderr:write("Error in decoding: \n" .. result)
+ else
+ success, result = base.pcall(self.handle, from, result)
+ if not success then
+ base.io.stderr:write("Error in your handler function: \n" .. result)
+ end
+ end
+ end
+ if message == "exit" then
+ return
+ end
+ end
+ end
+
+
+
+function osc.server:setHandler(hdle)
+ handle = hdle
+end
diff --git a/examples/lissajous/LICK/lib/loveosc/vstruct/CHANGES b/examples/lissajous/LICK/lib/loveosc/vstruct/CHANGES
new file mode 100755
index 0000000..ea42ce0
--- /dev/null
+++ b/examples/lissajous/LICK/lib/loveosc/vstruct/CHANGES
@@ -0,0 +1,30 @@
+1.0
+---
+Bugfixes to read error handling
+Ability to return unpacked values rather than tables
+
+1.0 beta 4
+----------
+Added the ability to say 's' with no width to read until EOF.
+Modified struct.unpack and struct.pack to return the number of bytes
+read/written as a second value. Note that this is not the same as the r/w
+pointer delta if seeks are involved.
+
+1.0 beta 3
+----------
+Lots of bugfixing and general cleanup
+Improved error reporting
+API name changes
+
+1.0 beta 2
+----------
+Added the counted string format "c".
+Added float and double support, courtesy of Peter "Corsix" Cawley.
+Updated the test framework.
+Fixed a bug in format m that could result in data loss when manipulating fields
+of 7 bytes or more width.
+
+
+1.0 beta 1
+----------
+Released to the world.
diff --git a/examples/lissajous/LICK/lib/loveosc/vstruct/COPYING b/examples/lissajous/LICK/lib/loveosc/vstruct/COPYING
new file mode 100755
index 0000000..430bce8
--- /dev/null
+++ b/examples/lissajous/LICK/lib/loveosc/vstruct/COPYING
@@ -0,0 +1,19 @@
+Copyright © 2008 Ben "ToxicFrog" Kelly
+FP module copyright © 2008 Peter "Corsix" Cawley
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/examples/lissajous/LICK/lib/loveosc/vstruct/README b/examples/lissajous/LICK/lib/loveosc/vstruct/README
new file mode 100755
index 0000000..e274888
--- /dev/null
+++ b/examples/lissajous/LICK/lib/loveosc/vstruct/README
@@ -0,0 +1,290 @@
+Contents
+========
+1. Overview
+2. API
+3. Warning!
+4. The Format String
+ Naming
+ Grouping
+ Repetition
+5. Format Specifiers
+6. Credits
+
+
+1. Overview
+===========
+VStruct is a library for Lua 5.1. It provides functions for manipulating binary
+data, in particular for unpacking binary files or byte buffers into Lua values
+and for packing Lua values back into files or buffers. Supported data types
+include:
+ - signed and unsigned integers of arbitrary byte width
+ - booleans and bitmasks
+ - plain and null-terminated strings
+ - fixed and floating point reals (the latter requires C module support)
+In addition, the library supports seeking, alignment, and byte order controls,
+repetition, grouping of data into tables, and naming of values within tables.
+
+
+
+2. API
+======
+exports:
+ vstruct.pack(fmt, [fd], data)
+ vstruct.unpack(fmt, , [unpacked])
+ vstruct.explode(int)
+ vstruct.implode(table)
+ vstruct.cursor(string)
+ vstruct.compile.read(format)
+ vstruct.compile.write(format)
+
+pack takes a format string and a table of data and packs the contents into a
+buffer. If the fd argument is present, it will write the data directly to it
+using standard file io methods (write and seek), and return the fd; otherwise
+it will construct and return a string. In either case it also returns (as a
+second value) the number of bytes written - note that if the format involved
+seeks, this is not the same as the amount by which the write pointer moved
+or the size of the packed string.
+
+unpack takes a format string and a buffer or file to unpack from, and returns
+the unpacked data as a table. It also returns (as a second value) the number of
+bytes read - note that if the format string involved seeks, this is not the same
+as the difference between read pointer positions. If the _unpacked_ argument is
+true, it will return the unpacked data as a series of values rather than as a
+table, equivalent to using the standard Lua function unpack() on the return
+value. Note that this means it will not return the number of bytes read as an
+additional value.
+
+explode converts a bitmask into a list of booleans, and implode does the
+converse. In such lists, list[1] is the least significant bit, and list[n] the
+most significant.
+
+cursor wraps a string in something that looks, at first glance, like a file.
+This permits strings to be wrapped and passed to the vstruct IO functions. The
+wrapped string supports :seek, and has limited support for :read (the only
+supported calling mode is :read(num_bytes)) and :write (as :write(buffer)).
+
+compile.read takes a format string and returns a function, which can later be
+passed a file (or file-like object - see vstruct.cursor) to perform a read
+operation. In effect, the following code:
+ f = vstruct.compile.read(fmt)
+ d = f(fd)
+Is equivalent to:
+ d = vstruct.unpack(fd, fmt)
+f can of course be called repeatedly, with different or the same fds each time.
+
+compile.write is the converse of compile.read. The emitted function expects a
+file and a table of data elements, so that:
+ f = vstruct.compile.write(fmt)
+ f(fd, data)
+Is equivalent to:
+ vstruct.pack(fd, fmt, data)
+As with compile.read, the emitted function is fully re-usable.
+
+
+3. Warning!
+===========
+When reading and writing numeric formats, vstruct is inherently limited by lua's
+number format, which is by default the IEEE 754 double. What this means in
+practice is that formats cipPu may be subject to data loss when read in widths
+of 7 bytes or more, if they contain more than 52 significant bits. (The same is
+true of numeric constants declared in Lua itself, of course, and other libraries
+which store values in lua numbers).
+Formats bfmsxz are unaffected by this, as they either do not use lua numbers or
+are guaranteed to fit inside them.
+
+4. The Format String
+====================
+The format string contains any number of endianness controls, seek controls,
+format specifiers, and grouping/naming sequences, seperated by whitespace,
+commas, or semicolons (or any mix thereof, although you are encouraged to choose
+one and stick to it for the sake of consistency). Each of these is detailed
+below.
+
+In the documentation below, the convention is that A represents an address and W
+a width in bytes. At present only base-10 numerals are supported.
+
+
+Naming
+------
+Under normal operation, when unpacking, the library simply stores unpacked
+values sequentially into a list, which is returned. Similarly, when packing, it
+expects a list of values which will be packed in order. However, values can be
+named, in which case the unpacked value will be stored in a field with that
+name, and when packing, it will use the value stored with that key. This is done
+by prefixing the format specifier with the name (which can be any sequence of
+letters, numbers, and _, provided it does not start with a number) followed by a
+':'. For example, the following format would generate a table with three keys,
+'x', 'y', and 'z':
+ "x:u4 y:u4 z:u4"
+And, when packing, would expect a table with those three keys and store their
+corresponding values.
+
+If the same name is specified multiple times, or is combined with repetition
+(see below), only the last read value is stored there.
+
+Named and anonymous values can be freely mixed; the named values will be
+assigned to their given fields and the anonymous ones to sequential indices.
+
+Grouping
+--------
+Rather than generating or expecting a flat table, the library can be instructed to
+create or read from a table containing subtables. This is done by surrounding the
+group of values you wish to be packed with '{' and '}' in the format string. For example,
+the following format string:
+ "{ u4 i4 } { s32 u4 }"
+Would, rather than generating a list of four values, generate a list containing two
+lists of two values each.
+Similarly, when packing, it would expect not a flat list, but a list of sublists, from
+which the values to be packed will be drawn.
+
+Groups can be named, so formats like:
+ "flags:m1 coords:{ x:u4 y:u4 z:u4 }"
+Are permitted and meaningful.
+
+
+Repetition
+----------
+A {} group can be repeated by prefixing or suffixing it with a count, seperated
+from the group by a '*'. For example:
+ "4 * { u4 }"
+ "{ u4 } * 4"
+ "{ u4 } { u4 } { u4 } { u4 }"
+Are all equivalent. Note that the whitespace in the above examples is optional.
+In cases where you want to repeat format specifiers without implying a grouping,
+you can use (). For example:
+ "4 * (u4 b1)"
+Is equivalent to:
+ "u4 b1 u4 b1 u4 b1 u4"
+Like grouping, these can be nested.
+
+
+5. Format Specifiers
+====================
+
+Endianness Controls
+-------------------
+The formats i, m, and u are affected by the endianness setting, which controls
+the order in which bytes are read and written within a field. The following
+characters in a format string adjust the endianness setting:
+
+<
+ Sets the endianness to little-endian (eg, Intel processors)
+>
+ Sets the endianness to big-endian (eg, PPC and Motorola processors)
+=
+ Sets the endianness to the native endianness.
+
+
+Seek Controls
+-------------
+These characters are used to seek to specific locations in the input or output.
+Note that they only work on buffers or file-like objects that support the seek()
+method; for streams which cannot be sought on, use the 'x' (skip/null-pad)
+data format instead.
+
+@A
+ Seek to absolute address A.
++A
+ Seek forward A bytes.
+-A
+ Seek backwards A bytes.
+aW
+ Align to word width W (ie, seek to the next address which is a multiple of W)
+
+
+Data Format Specifiers
+----------------------
+bW Boolean.
+ Read: as uW, but returns true if the result is non-zero and false otherwise.
+ Write: as uW with input 1 if true and 0 otherwise.
+
+cW Counted string.
+ Read: uW to determine the length of the string W', followed by sW'.
+ Write: the length of the string as uW, followed by the string itself.
+ The counted string is a common idiom where a string is immediately prefixed
+ with its length, as in:
+ size_t len;
+ char[] str;
+ The counted string format can be used to easily read and write these. The
+ width provided is the width of the len field, which is treated as an
+ unsigned int. Only the string itself is returned (when unpacking) or
+ required (when packing).
+ The len field is affected by endianness, as in format u.
+
+fW IEEE 754 floating point.
+ Valid widths are 4 (float) and 8 (double). No quads yet, sorry!
+ Affected by endianness.
+
+iW Signed integer.
+ Read: a signed integer of width W bytes.
+ Write: a signed integer of width W bytes.
+ Floating point values will be truncated.
+ Affected by endianness.
+
+mW Bitmask.
+ Read: as uW, but explodes the result into a list of booleans, one per bit.
+ Write: implodes the input value, then writes it as uW.
+ Affected by endianness.
+ See also: vstruct.implode, vstruct.explode.
+
+pW Signed fixed point rational.
+ Width is in the format "I.F"; the value before the dot is the number of
+ bytes in the integer part, and the value after, in the fractional part.
+ Read: a fixed point rational of I+F bytes.
+ Write: a fixed point rational of I+F bytes. Values which cannot be exactly
+ represented in the specified width are truncated.
+ Affected by endianness.
+
+PW Signed fixed point rational with bit-aligned subfields
+ Equivalent to pW, except that the decimal point does not need to be byte
+ aligned; for example, formats such as P20.12 are possible.
+ Note that underlying reads must still occur in byte multiples. Using a W
+ such that I+F is not a multiple of 8 is an error.
+
+sW String.
+ Read: reads exactly W bytes and returns them as a string. If W is omitted,
+ reads until EOF.
+ Write:
+ If W is omitted, uses the string length.
+ If W is shorter than the string length, truncates the string.
+ If W is greater than the string length, null pads the string.
+
+uW Unsigned integer.
+ Read: an unsigned integer of width W bytes.
+ Write: an unsigned integer of width W bytes.
+ Floating point values will be truncated.
+ Negative values will be taken absolute.
+ Affected by endianness.
+
+xW Skip/pad.
+ Read: read and discard the next W bytes.
+ Write: write W zero bytes.
+
+zW Null terminated string.
+ Read: reads exactly W bytes. Returns everything up to the first zero byte.
+ If W is omitted, reads up to the next zero byte.
+ Write: writes exactly W bytes.
+ If the input is shorter than W, zero pads the output.
+ If as long or longer, truncates to W-1 and writes a zero byte at the end.
+ If W is omitted, uses the string length plus one (ie, writes the string
+ out entire and then null terminates it).
+
+
+
+6. Credits
+==========
+ While most of the library code was written by me (Ben Kelly), the existence
+of this library owes itself to many others:
+ The floating point code was contributed by Peter Cawley on lua-l.
+ The original inspiration came from Roberto Ierusalimschy's "struct" library
+and Luiz Henrique de Figueiredo's "lpack" library, as well as the "struct"
+available in Python.
+ sanooj, from #lua, has done so much testing and bug reporting that at this
+point he's practically a co-author.
+ The overall library design and interface are the result of much discussion
+with rici, sanooj, Keffo, snogglethorpe, Spark, kozure, Vornicus, McMartin, and
+probably several others I've forgotten about on IRC (#lua on freenode and #code
+on nightstar).
+ Finally, without Looking Glass Studios to make System Shock, and Team TSSHP
+(in particular Jim "hairyjim" Cameron) to reverse engineer it, I wouldn't have
+had a reason to write this library in the first place.
diff --git a/examples/lissajous/LICK/lib/loveosc/vstruct/common.lua b/examples/lissajous/LICK/lib/loveosc/vstruct/common.lua
new file mode 100755
index 0000000..841b5c1
--- /dev/null
+++ b/examples/lissajous/LICK/lib/loveosc/vstruct/common.lua
@@ -0,0 +1,48 @@
+-- shared formats - seeking, endianness
+-- these should all return nil so that they do not mutate the data list
+-- Copyright © 2008 Ben "ToxicFrog" Kelly; see COPYING
+
+local common = {}
+
+-- determine if the host system is big-endian or not, by dumping an empty
+-- function and looking at the endianness flag
+-- this is kind of hackish
+local function bigendian()
+ return string.byte(string.dump(function() end)) == string.char(0x00)
+end
+common.is_bigendian = bigendian()
+
+-- seek controls
+function common.seekto(fd, w)
+ fd:seek("set", w)
+end
+
+function common.seekforward(fd, w)
+ fd:seek("cur", w)
+end
+
+function common.seekback(fd, w)
+ fd:seek("cur", -w)
+end
+
+function common.a(fd,w)
+ local a = fd:seek()
+ if a % w ~= 0 then
+ fd:seek("cur", w - (a % w))
+ end
+end
+
+-- endianness controls
+function common.littleendian(fd, w)
+ common.is_bigendian = false
+end
+
+function common.bigendian(fd, w)
+ common.is_bigendian = true
+end
+
+function common.hostendian(fd, w)
+ common.is_bigendian = bigendian()
+end
+
+return common
diff --git a/examples/lissajous/LICK/lib/loveosc/vstruct/compile.lua b/examples/lissajous/LICK/lib/loveosc/vstruct/compile.lua
new file mode 100755
index 0000000..942f743
--- /dev/null
+++ b/examples/lissajous/LICK/lib/loveosc/vstruct/compile.lua
@@ -0,0 +1,134 @@
+-- functions for turning a format string into a callable function
+-- they work by calling parse(), passing it the format string and
+-- a table of code generators appropriate for whether we are reading
+-- or writing.
+-- The resulting code is then prefixed with some setup code and postfixed
+-- with a return value and loadstring() is called on it to generate a function
+-- Copyright � 2008 Ben "ToxicFrog" Kelly; see COPYING
+
+local require,loadstring,setfenv,type,select,unpack,setmetatable
+ = require,loadstring,setfenv,type,select,unpack,setmetatable
+
+local print,assert,error,xpcall,pairs,where
+ = print,assert,error,xpcall,pairs,debug.traceback
+
+module((...))
+
+local parse = require(_PACKAGE.."parser")
+
+local function nulsafe_error(s)
+ return error(s:gsub('%z', '_'))
+end
+
+local function xpcall2(f, err, ...)
+ local args = {n=select('#', ...), ...}
+ return xpcall(function() return f(unpack(args, 1, args.n)) end, err)
+end
+
+local function err_generate(message, format, trace)
+ nulsafe_error([[
+struct: internal error in code generator
+This is an internal error in the struct library
+Please report it as a bug and include the following information:
+-- error message
+]]..message.."\n\n"..[[
+-- format string
+]]..format.."\n\n"..[[
+-- stack trace
+]]..trace)
+end
+
+local function err_compile(message, format, source)
+ nulsafe_error([[
+struct: syntax error in emitted lua source
+This is an internal error in the struct library
+Please report it as a bug and include the following information:
+-- loadstring error
+]]..message.."\n\n"..[[
+-- format string
+]]..format.."\n\n"..[[
+-- emitted source
+]]..source.."\n\n"..[[
+-- stack trace
+]])
+end
+
+local function err_execute(message, format, source, trace)
+ nulsafe_error([[
+struct: runtime error in generated function
+This is at some level an internal error in the struct library
+It could be a genuine error in the emitted code (in which case this is a code
+generation bug)
+Alternately, it could be that you gave it a malformed format string, a bad
+file descriptor, or data that does not match the given format (in which case
+it is an argument validation bug and you should be getting an error anyways).
+Please report this as a bug and include the following information:
+-- execution error
+]]..message.."\n\n"..[[
+-- format string
+]]..format.."\n\n"..[[
+-- emitted source
+]]..source.."\n\n"..[[
+-- stack trace
+]]..trace)
+end
+
+local function compile(format, gen, env)
+ local status,source = xpcall(function()
+ return parse(format, gen, true)
+ end,
+ function(message)
+ return { message, where("",2) }
+ end)
+
+ if not status then
+ if type(source[1]) == "function" then
+ error(source[1]()..source[2])
+ end
+ err_generate(source[1], format, source[2])
+ end
+
+ local fn,err = loadstring(source)
+
+ if not fn then
+ err_compile(err, format, source)
+ end
+
+ setfenv(fn, env)
+
+ local fn = function(...)
+ local status,ret,len = xpcall2(fn, function(message)
+ return { message, where("",2) }
+ end, ...)
+
+ -- call succeeded without errors
+ if status then return ret,len end
+
+ local message,where = ret[1],ret[2]
+
+ -- call generated a deliberate error; call the provided closure
+ -- it will either emit an error code or re-throw
+ if type(message) == "function" then return nil,message() end
+
+ -- call generated an internal error; re-throw with extra debug info
+ err_execute(message, format, source, where)
+ end
+
+ return fn
+end
+
+local gen_unpack = require(_PACKAGE.."gen_unpack")
+local io_unpack = require(_PACKAGE.."io_unpack")
+
+function _M.unpack(format)
+ return compile(format, gen_unpack, io_unpack)
+end
+
+local gen_pack = require(_PACKAGE.."gen_pack")
+local io_pack = require(_PACKAGE.."io_pack")
+
+function _M.pack(format)
+ return compile(format, gen_pack, io_pack)
+end
+
+return _M
diff --git a/examples/lissajous/LICK/lib/loveosc/vstruct/cursor.lua b/examples/lissajous/LICK/lib/loveosc/vstruct/cursor.lua
new file mode 100755
index 0000000..cd913af
--- /dev/null
+++ b/examples/lissajous/LICK/lib/loveosc/vstruct/cursor.lua
@@ -0,0 +1,80 @@
+-- cursor - a wrapper for strings that makes them look like files
+-- exports: seek read write
+-- read only supports numeric amounts
+-- Copyright © 2008 Ben "ToxicFrog" Kelly; see COPYING
+
+local cursor = {}
+
+-- like fseek
+-- seeking past the end of the string is permitted
+-- reads will return EOF, writes will fill in the intermediate space with nuls
+-- seeking past the start of the string is a soft error
+function cursor:seek(whence, offset)
+ whence = whence or "cur"
+ offset = offset or 0
+
+ if whence == "set" then
+ self.pos = offset
+ elseif whence == "cur" then
+ self.pos = self.pos + offset
+ elseif whence == "end" then
+ self.pos = #self.str + offset
+ else
+ error "bad argument #1 to seek"
+ end
+
+ if self.pos < 0 then
+ self.pos = 0
+ return nil,"attempt to seek prior to start of file"
+ end
+
+ return self.pos
+end
+
+-- read n bytes from the current position
+-- reads longer than the string can satisfy return as much as it can
+-- reads while the position is at the end return nil,"eof"
+function cursor:read(n)
+ if self.pos >= #self.str then
+ return nil,"eof"
+ end
+
+ if n == "*a" then
+ n = #self.str
+ end
+
+ local buf = self.str:sub(self.pos+1, self.pos + n)
+ self.pos = math.min(self.pos + n, #self.str)
+
+ return buf
+end
+
+-- write the contents of the buffer at the current position, overwriting
+-- any data already present
+-- if the write pointer is past the end of the string, also fill in the
+-- intermediate space with nuls
+function cursor:write(buf)
+ if self.pos > #self.str then
+ self.str = self.str .. string.char(0):rep(self.pos - #self.str)
+ end
+
+ self.str = self.str:sub(1, self.pos)
+ .. buf
+ .. self.str:sub(self.pos + #buf + 1, -1)
+ self.pos = self.pos + #buf
+
+ return self
+end
+
+function cursor:__call(source)
+ assert(type(source) == "string", "invalid first argument to cursor()")
+ return setmetatable(
+ { str = source, pos = 0 },
+ cursor)
+end
+
+cursor.__index = cursor
+
+setmetatable(cursor, cursor)
+
+return cursor
diff --git a/examples/lissajous/LICK/lib/loveosc/vstruct/fp.lua b/examples/lissajous/LICK/lib/loveosc/vstruct/fp.lua
new file mode 100755
index 0000000..5da81da
--- /dev/null
+++ b/examples/lissajous/LICK/lib/loveosc/vstruct/fp.lua
@@ -0,0 +1,121 @@
+-- floating point module
+-- Copyright © 2008 Peter "Corsix" Cawley and Ben "ToxicFrog" Kelly; see COPYING
+
+local fp = {}
+local name = (...):gsub('%.[^%.]+$', '')
+local struct = require (name)
+local common = require (name..".common")
+
+local function reader(data, size_exp, size_fraction)
+ local fraction, exponent, sign
+ local endian = common.is_bigendian and ">" or "<"
+
+ -- Split the unsigned integer into the 3 IEEE fields
+ local bits = struct.unpack(endian.."m"..#data, data, true)
+ local fraction = struct.implode({unpack(bits, 1, size_fraction)}, size_fraction)
+ local exponent = struct.implode({unpack(bits, size_fraction+1, size_fraction+size_exp)}, size_exp)
+ local sign = bits[#bits] and -1 or 1
+
+ -- special case: exponent is all 1s
+ if exponent == 2^size_exp-1 then
+ -- significand is 0? +- infinity
+ if fraction == 0 then
+ return sign * math.huge
+
+ -- otherwise it's NaN
+ else
+ return 0/0
+ end
+ end
+
+ -- restore the MSB of the significand, unless it's a subnormal number
+ if exponent ~= 0 then
+ fraction = fraction + (2 ^ size_fraction)
+ else
+ exponent = 1
+ end
+
+ -- remove the exponent bias
+ exponent = exponent - 2 ^ (size_exp - 1) + 1
+
+ -- Decrease the size of the exponent rather than make the fraction (0.5, 1]
+ exponent = exponent - size_fraction
+
+ return sign * math.ldexp(fraction, exponent)
+end
+
+local function writer(value, size_exp, size_fraction)
+ local fraction, exponent, sign
+ local width = (size_exp + size_fraction + 1)/8
+ local endian = common.is_bigendian and ">" or "<"
+ local bias = 2^(size_exp-1)-1
+
+ if value < 0
+ or 1/value == -math.huge then -- handle the case of -0
+ sign = true
+ value = -value
+ else
+ sign = false
+ end
+
+ -- special case: value is infinite
+ if value == math.huge then
+ exponent = bias+1
+ fraction = 0
+
+ -- special case: value is NaN
+ elseif value ~= value then
+ exponent = bias+1
+ fraction = 2^(size_fraction-1)
+
+ --special case: value is 0
+ elseif value == 0 then
+ exponent = -bias
+ fraction = 0
+
+ else
+ fraction,exponent = math.frexp(value)
+
+ -- subnormal number
+ if exponent+bias <= 1 then
+ fraction = fraction * 2^(size_fraction+(exponent+bias)-1)
+ exponent = -bias
+
+ else
+ -- remove the most significant bit from the fraction and adjust exponent
+ fraction = fraction - 0.5
+ exponent = exponent - 1
+
+ -- turn the fraction into an integer
+ fraction = fraction * 2^(size_fraction+1)
+ end
+ end
+
+
+ -- add the exponent bias
+ exponent = exponent + bias
+
+ local bits = struct.explode(fraction)
+ local bits_exp = struct.explode(exponent)
+ for i=1,size_exp do
+ bits[size_fraction+i] = bits_exp[i]
+ end
+ bits[size_fraction+size_exp+1] = sign
+
+ return struct.pack(endian.."m"..width, {bits})
+end
+
+-- Create readers and writers for the IEEE sizes
+fp.sizes = {
+ [4] = {1, 8, 23},
+ [8] = {1, 11, 52},
+}
+
+fp.r = {}
+fp.w = {}
+for width, sizes in pairs(fp.sizes) do
+ fp.r[width] = function(uint) return reader(uint, sizes[2], sizes[3]) end
+ fp.w[width] = function(valu) return writer(valu, sizes[2], sizes[3]) end
+end
+
+return fp
diff --git a/examples/lissajous/LICK/lib/loveosc/vstruct/gen_pack.lua b/examples/lissajous/LICK/lib/loveosc/vstruct/gen_pack.lua
new file mode 100755
index 0000000..9449c85
--- /dev/null
+++ b/examples/lissajous/LICK/lib/loveosc/vstruct/gen_pack.lua
@@ -0,0 +1,132 @@
+local require,table
+ = require,table
+
+module((...))
+local parse = require(_PACKAGE.."parser")
+
+local gen = {}
+
+gen.preamble = [[
+local fd,data = ...
+local stack = {}
+local index = 1
+local start = fd:seek()
+local len = 0
+
+local function push(key)
+ if not key then
+ key = index
+ index = index + 1
+ end
+
+ stack[#stack+1] = { index, data }
+ data = data[key]
+ index = 1
+end
+
+local function pop(key)
+ local saved = stack[#stack]
+ stack[#stack] = nil
+
+ index = saved[1]
+ data = saved[2]
+end
+
+local function update_len()
+ len = len + fd:seek() - start
+end
+
+local function update_start()
+ start = fd:seek()
+end
+
+hostendian()
+]]
+
+gen.postamble = [[
+
+update_len()
+return fd,len
+]]
+
+-- control:
+-- <>(fd, <>)
+function gen.control(token)
+ local tr = {
+ ["<"] = "littleendian";
+ [">"] = "bigendian";
+ ["="] = "hostendian";
+ ["+"] = "seekforward";
+ ["-"] = "seekback";
+ ["@"] = "seekto";
+ }
+ local fn = tr[token[1]] or token[1]
+
+ local args = token[2]:gsub('%.', ', ')
+ if #args == 0 then args = "nil" end
+
+ return "update_len(); "..fn.."(fd, "..args..")".."; update_start()"
+end
+
+-- atom:
+-- <>(fd, data[index], <>)
+-- ++index
+function gen.atom(token)
+ local fn = token[1]
+ local args = token[2]:gsub('%.', ', ')
+ if #args == 0 then args = "nil" end
+
+ return fn.."(fd, data[index], "..args..")\nindex = index+1"
+end
+
+-- table:
+-- push()
+-- <>
+-- pop()
+function gen.table(token)
+ return "push()\n"
+ ..parse(token[1]:sub(2,-2), gen)
+ .."\npop()"
+end
+
+-- group:
+-- <>
+function gen.group(token)
+ return parse(token[1]:sub(2,-2), gen)
+end
+
+-- named atom:
+-- <>(fd, data.<>, <>)
+function gen.name_atom(token)
+ local fn = token[2]
+ local args = token[3]:gsub('%.', ', ')
+ if #args == 0 then args = "nil" end
+
+ return fn.."(fd, data."..token[1]..", "..args..")"
+end
+
+-- named table:
+-- push(<>)
+-- <>
+-- pop()
+function gen.name_table(token)
+ return "push('"..token[1].."')\n"
+ ..parse(token[2]:sub(2,-2), gen)
+ .."\npop()"
+end
+
+function gen.prerepeat(token, get)
+ local next = get()
+ local src = gen[next.type](next, get)
+
+ return "for _idx=1,"..token[1].." do\n\n"..src.."\nend"
+end
+
+function gen.postrepeat(token, get, asl)
+ local src = table.remove(asl)
+
+ return "for _idx=1,"..token[1].." do\n\n"..src.."\nend"
+end
+
+return gen
+
diff --git a/examples/lissajous/LICK/lib/loveosc/vstruct/gen_unpack.lua b/examples/lissajous/LICK/lib/loveosc/vstruct/gen_unpack.lua
new file mode 100755
index 0000000..369cfc9
--- /dev/null
+++ b/examples/lissajous/LICK/lib/loveosc/vstruct/gen_unpack.lua
@@ -0,0 +1,117 @@
+local require,table
+ = require,table
+
+module((...))
+local parse = require(_PACKAGE.."parser")
+
+local gen = {}
+
+gen.preamble = [[
+local fd = (...)
+local stack = {}
+local pack = {}
+local start = fd:seek()
+local len = 0
+
+local function push()
+ stack[#stack+1],pack = pack,{}
+end
+
+local function pop(key)
+ local target = stack[#stack]
+ key = key or #target+1
+ target[key],pack = pack,target
+ stack[#stack] = nil
+end
+
+local function update_len()
+ len = len + fd:seek() - start
+end
+
+local function update_start()
+ start = fd:seek()
+end
+
+hostendian()
+]]
+
+gen.postamble = [[
+
+update_len()
+return pack,len
+]]
+
+-- control:
+-- <>(fd, <>)
+function gen.control(token)
+ local tr = {
+ ["<"] = "littleendian";
+ [">"] = "bigendian";
+ ["="] = "hostendian";
+ ["+"] = "seekforward";
+ ["-"] = "seekback";
+ ["@"] = "seekto";
+ }
+ local fn = tr[token[1]] or token[1]
+
+ local args = token[2]:gsub('%.', ', ')
+ if #args == 0 then args = "nil" end
+
+ return "update_len(); "..fn.."(fd, "..args..")".."; update_start()"
+end
+
+-- atom:
+-- pack[#pack+1] = <>(fd, <>)
+function gen.atom(token)
+ local fn = token[1]
+ local args = token[2]:gsub('%.', ', ')
+ if #args == 0 then args = "nil" end
+
+ return "pack[#pack+1] = "..fn.."(fd, "..args..")"
+end
+
+-- table:
+-- push()
+-- <>
+-- pop()
+function gen.table(token)
+ return "push()\n"
+ ..parse(token[1]:sub(2,-2), gen)
+ .."\npop()"
+end
+
+-- group:
+-- <>
+function gen.group(token)
+ return parse(token[1]:sub(2,-2), gen)
+end
+
+function gen.name_atom(token)
+ local fn = token[2]
+ local args = token[3]:gsub('%.', ', ')
+ if #args == 0 then args = "nil" end
+
+ return "pack."..token[1].." = "..fn.."(fd, "..args..")"
+end
+
+function gen.name_table(token)
+ return "push()\n"
+ ..parse(token[2]:sub(2,-2), gen)
+ .."\npop('"..token[1].."')\n"
+end
+
+function gen.prerepeat(token, get)
+ local next = get()
+ local src = gen[next.type](next, get)
+
+ return "for _idx=1,"..token[1].." do\n\n"..src.."\nend"
+end
+
+function gen.postrepeat(token, get, asl)
+ local src = table.remove(asl)
+
+ return "for _idx=1,"..token[1].." do\n\n"..src.."\nend"
+end
+
+return gen
+
diff --git a/examples/lissajous/LICK/lib/loveosc/vstruct/init.lua b/examples/lissajous/LICK/lib/loveosc/vstruct/init.lua
new file mode 100755
index 0000000..8910968
--- /dev/null
+++ b/examples/lissajous/LICK/lib/loveosc/vstruct/init.lua
@@ -0,0 +1,94 @@
+-- vstruct, the versatile struct library
+-- Copyright � 2008 Ben "ToxicFrog" Kelly; see COPYING
+
+local table,math,type,require,assert,_unpack = table,math,type,require,assert,unpack
+
+local print = print
+
+module((...))
+
+cursor = require (_NAME..".cursor")
+compile = require (_NAME..".compile")
+
+function math.trunc(n)
+ if n < 0 then
+ return math.ceil(n)
+ else
+ return math.floor(n)
+ end
+end
+
+-- turn an int into a list of booleans
+-- the length of the list will be the smallest number of bits needed to
+-- represent the int
+function explode(int, size)
+ assert(int, "struct.explode: missing argument")
+ size = size or 0
+
+ local mask = {}
+ while int ~= 0 or #mask < size do
+ table.insert(mask, int % 2 ~= 0)
+ int = math.trunc(int/2)
+ end
+ return mask
+end
+
+-- turn a list of booleans into an int
+-- the converse of explode
+function implode(mask, size)
+ size = size or #mask
+
+ local int = 0
+ for i=size,1,-1 do
+ int = int*2 + ((mask[i] and 1) or 0)
+ end
+ return int
+end
+
+-- given a source, which is either a string or a file handle,
+-- unpack it into individual data based on the format string
+function unpack(fmt, source, untable)
+ -- wrap it in a cursor so we can treat it like a file
+ if type(source) == 'string' then
+ source = cursor(source)
+ end
+
+ assert(fmt and source and type(fmt) == "string", "struct: invalid arguments to unpack")
+
+ -- the lexer will take our format string and generate code from it
+ -- it returns a function that when called with our source, will
+ -- unpack the data according to the format string and return all
+ -- values from said unpacking in a list
+ if untable then
+ --local t = compile.unpack(fmt)(source)
+ --print(t)
+ -- print(_unpack(t))
+ return _unpack((compile.unpack(fmt)(source)))
+ else
+ return compile.unpack(fmt)(source)
+ end
+end
+
+-- given a format string and a list of data, pack them
+-- if 'fd' is omitted, pack them into and return a string
+-- otherwise, write them directly to the given file
+function pack(fmt, fd, data)
+ local str_fd
+
+ if not data then
+ data = fd
+ fd = ""
+ end
+
+ if type(fd) == 'string' then
+ fd = cursor("")
+ str_fd = true
+ end
+
+ assert(fmt and fd and data and type(fmt) == "string", "struct: invalid arguments to pack")
+
+ local fd,len = compile.pack(fmt)(fd, data)
+ return (str_fd and fd.str) or fd,len
+end
+
+return struct
diff --git a/examples/lissajous/LICK/lib/loveosc/vstruct/io_pack.lua b/examples/lissajous/LICK/lib/loveosc/vstruct/io_pack.lua
new file mode 100755
index 0000000..a785f7e
--- /dev/null
+++ b/examples/lissajous/LICK/lib/loveosc/vstruct/io_pack.lua
@@ -0,0 +1,127 @@
+-- write formats
+-- return true if they have consumed a value from the input stream
+-- return false/nil otherwise (ie, the next value will be preserved
+-- for subsequent calls, eg skip/pad)
+-- Copyright © 2008 Ben "ToxicFrog" Kelly; see COPYING
+local require,error,setmetatable,string,print,math,unpack,io
+ = require,error,setmetatable,string,print,math,unpack,io
+
+module((...))
+
+local struct = require (_PACKAGE:sub(1,-2))
+local common = require (_PACKAGE.."common")
+local fp = require (_PACKAGE.."fp")
+
+local pack = setmetatable({}, { __index = common })
+
+-- boolean
+function pack.b(fd, d, w)
+ return pack.u(fd, (d and 1) or 0, w)
+end
+
+-- counted string
+-- a string immediately prefaced with its length as a uint
+function pack.c(fd, d, w)
+ pack.u(fd, #d, w)
+ return pack.s(fd, d)
+end
+
+-- floating point
+function pack.f(fd, d, w)
+ if not fp.w[w] then
+ error("struct.pack: illegal floating point width")
+ end
+-- local f = fp.w[w](d)
+-- print(f, type(f))
+ return pack.s(fd, fp.w[w](d), w)
+end
+
+-- signed int
+function pack.i(fd, d, w)
+ if d < 0 then
+ d = 2^(w*8) + d
+ end
+ return pack.u(fd, d, w)
+end
+
+-- bitmask
+-- we use a string here because using an unsigned will lose data on bitmasks
+-- wider than lua's native number format
+function pack.m(fd, d, w)
+ local buf = ""
+
+ for i=1,w*8,8 do
+ local bits = { unpack(d, i, i+7) }
+ local byte = string.char(struct.implode(bits, 8))
+ if pack.is_bigendian then
+ buf = byte..buf
+ else
+ buf = buf..byte
+ end
+ end
+ return pack.s(fd, buf, w)
+end
+
+-- fixed point bit aligned
+function pack.P(fd, d, dp, fp)
+ if (dp+fp) % 8 ~= 0 then
+ error "total width of fixed point value must be byte multiple"
+ end
+ return pack.i(fd, d * 2^fp, (dp+fp)/8)
+end
+
+-- fixed point byte aligned
+function pack.p(fd, d, dp, fp)
+ return pack.P(fd, d, dp*8, fp*8)
+end
+
+-- fixed length string
+-- length 0 is write string as is
+-- length >0 is write exactly w bytes, truncating or padding as needed
+function pack.s(fd, d, w)
+ w = w or #d
+ if w == 0 then return end
+
+ if #d < w then
+ d = d..string.char(0):rep(w-#d)
+ end
+
+ return fd:write(d:sub(1,w))
+end
+
+-- unsigned int
+function pack.u(fd, d, w)
+ local s = ""
+
+ for i=1,w do
+ if pack.is_bigendian then
+ s = string.char(d % 2^8) .. s
+ else
+ s = s .. string.char(d % 2^8)
+ end
+ d = math.trunc(d/2^8)
+ end
+
+ return pack.s(fd, s, w)
+end
+
+-- skip/pad
+-- this is technically a control format, so it has a different signature
+-- specifically, there is no "data" argument
+function pack.x(fd, w)
+ return pack.s(fd, "", w)
+end
+
+-- null terminated string
+-- w==nil is write string as is + termination
+-- w>0 is write exactly w bytes, truncating/padding and terminating
+function pack.z(fd, d, w)
+ w = w or #d+1
+ if #d >= w then
+ d = d:sub(1, w-1)
+ end
+
+ return pack.s(fd, d.."\0", w)
+end
+
+return pack
diff --git a/examples/lissajous/LICK/lib/loveosc/vstruct/io_unpack.lua b/examples/lissajous/LICK/lib/loveosc/vstruct/io_unpack.lua
new file mode 100755
index 0000000..916c321
--- /dev/null
+++ b/examples/lissajous/LICK/lib/loveosc/vstruct/io_unpack.lua
@@ -0,0 +1,165 @@
+-- read formats
+-- return a value if applicable, which will be packed
+-- otherwise return nil
+-- Copyright � 2008 Ben "ToxicFrog" Kelly; see COPYING
+
+-- load operations common to both unpack and pack, and set __index so that
+-- requests for, say, unpack.seekto will succeed
+local require,error,setmetatable,string,print
+ = require,error,setmetatable,string,print
+
+module((...))
+
+local struct = require (_PACKAGE:sub(1,-2))
+local common = require (_PACKAGE.."common")
+local fp = require (_PACKAGE.."fp")
+
+local unpack = setmetatable({}, { __index = common })
+
+-- boolean
+-- true if any bit is 1, false otherwise
+function unpack.b(fd, w)
+ return unpack.u(fd, w) ~= 0
+end
+
+-- counted string
+-- a string immediately prefaced with its length as a uint
+function unpack.c(fd, w)
+ w = unpack.u(fd, w)
+
+ return unpack.s(fd, w)
+end
+
+-- float
+-- this is callout to the floating-point read/write module, if installed
+function unpack.f(fd, w)
+ if not fp.r[w] then
+ error("struct.unpack: illegal floating point width")
+ end
+
+ return fp.r[w](unpack.s(fd,w))
+end
+
+-- utility functions for the i, m and u formats
+local function directions(w)
+ if unpack.is_bigendian then
+ return 1,w,1
+ else
+ return w,1,-1
+ end
+end
+
+local function pve_unpack(buf, w)
+ local i,sof,eof,dir = 0,directions(w)
+
+ for c=sof,eof,dir do
+ i = i * 2^8 + buf:byte(c)
+ end
+
+ return i
+end
+
+local function nve_unpack(buf, w)
+ local i,sof,eof,dir = 0,directions(w)
+
+ if buf:byte(sof) < 128 then
+ return pve_unpack(buf, w)
+ end
+
+ for c=sof,eof,dir do
+ i = i * 2^8 - (255 - buf:byte(c))
+ end
+
+ return i-1
+end
+
+-- signed int of w bytes
+function unpack.i(fd, w)
+ local buf = unpack.s(fd, w)
+
+ return nve_unpack(buf, w)
+end
+
+-- bitmask of w bytes
+-- we need to read and unpack it as a string, not an unsigned, because otherwise
+-- we're limited to 52 bits
+function unpack.m(fd, w)
+ local buf = unpack.s(fd, w)
+ local mask = {}
+
+ local sof,eof,dir = directions(w)
+
+ -- reverse it here because directions() returns numbers for MSB first,
+ -- and we want LSB first
+ for i=eof,sof,-dir do
+ local byte = buf:byte(i)
+ local bits = struct.explode(byte)
+ for j=1,8 do
+ mask[#mask+1] = bits[j] or false
+ end
+ end
+ return mask
+end
+
+-- fixed point bit aligned
+-- w is in the form d.f, where d is the number of bits in the integer part
+-- and f the number of bits in the fractional part
+function unpack.P(fd, dp, fp)
+ if (dp+fp) % 8 ~= 0 then
+ error "total width of fixed point value must be byte multiple"
+ end
+ return unpack.i(fd, (dp+fp)/8)/(2^fp)
+end
+
+-- fixed point byte aligned
+function unpack.p(fd, dp, fp)
+ return unpack.P(fd, dp*8, fp*8)
+end
+
+-- string
+-- reads exactly w bytes of data and returns them verbatim
+function unpack.s(fd, w)
+ if w == 0 then return "" end
+
+ local buf,err = fd:read(w or "*a")
+ if not buf then
+ error(function() return "read error: "..(err or "(unknown error)") end)
+ elseif #buf < w then
+ error(function() return "short read: wanted "..w.." bytes, got "..#buf end)
+ end
+ return buf
+end
+
+-- unsigned int
+function unpack.u(fd, w)
+ local buf,err = unpack.s(fd, w)
+
+ return pve_unpack(buf, w)
+end
+
+-- skip/pad
+-- reads w bytes and discards them
+function unpack.x(fd, w)
+ fd:read(w)
+ return true
+end
+
+-- null-terminated string
+-- if w is omitted, reads up to and including the first nul, and returns everything
+-- except that nul
+-- otherwise, reads exactly w bytes and returns everything up to the first nul
+function unpack.z(fd, w)
+ if w then
+ return unpack.s(fd, w):match('^%Z*')
+ end
+
+ local buf = ""
+ local c = unpack.s(fd, 1)
+ while #c > 0 and c ~= string.char(0) do
+ buf = buf..c
+ c = unpack.s(fd, 1)
+ end
+ return buf
+end
+
+return unpack
diff --git a/examples/lissajous/LICK/lib/loveosc/vstruct/lexer.lua b/examples/lissajous/LICK/lib/loveosc/vstruct/lexer.lua
new file mode 100755
index 0000000..9eb503e
--- /dev/null
+++ b/examples/lissajous/LICK/lib/loveosc/vstruct/lexer.lua
@@ -0,0 +1,54 @@
+local lexis = {}
+
+local function lexeme(name)
+ return function(pattern)
+ lexis[#lexis+1] = { name=name, pattern="^"..pattern }
+ end
+end
+
+lexeme (false) "%s+" -- whitespace
+lexeme "table" "(%b{})"
+lexeme "group" "(%b())"
+lexeme "name_atom" "([%a_][%w_]*)%:(%a)([%d.]*)"
+lexeme "name_table" "([%a_][%w_]*)%:(%b{})"
+lexeme "prerepeat" "(%d+)%s*%*"
+lexeme "postrepeat" "%*%s*(%d+)"
+lexeme "control" "([-+@<>=ax])([%d.]*)"
+lexeme "atom" "(%a)([%d.]*)"
+
+return function(source)
+ local orig = source
+ local index = 1
+
+ local function iter()
+ if #source == 0 then return nil end
+
+ for _,lexeme in ipairs(lexis) do
+ if source:match(lexeme.pattern) then
+ local result = { source:find(lexeme.pattern) }
+ local eof = table.remove(result, 2)
+ table.remove(result, 1)
+
+ source = source:sub(eof+1, -1)
+ index = index+eof
+
+ if lexeme.name then
+ result.type = lexeme.name
+ coroutine.yield(result)
+ end
+ return iter()
+ end
+ end
+ error (function() return "Error lexing format string [["
+ ..(orig)
+ .."]] at char "
+ ..index
+ .." ("
+ ..(source:sub(1,1))
+ ..")"
+ end)
+ end
+
+ return coroutine.wrap(iter)
+end
+
diff --git a/examples/lissajous/LICK/lib/loveosc/vstruct/parser.lua b/examples/lissajous/LICK/lib/loveosc/vstruct/parser.lua
new file mode 100755
index 0000000..122f68e
--- /dev/null
+++ b/examples/lissajous/LICK/lib/loveosc/vstruct/parser.lua
@@ -0,0 +1,35 @@
+-- parser for format strings
+-- you give it a format string, a table of code generators,
+-- and a flag indicating whether to apply the preamble/postable
+-- it gives you lua source
+
+local require,concat = require,table.concat
+
+local print = print
+
+module((...))
+
+local lex = require(_PACKAGE.."lexer")
+
+return function(source, codegen, prepost)
+ local asl = {}
+ local get = lex(source)
+
+ for token in get do
+ -- seperate statements because codegen may change #asl
+ local code = codegen[token.type](token, get, asl)
+ asl[#asl+1] = code
+ end
+
+ local source = concat(asl, "\n")
+
+ if prepost then
+ source = codegen.preamble
+ .. source
+ .. codegen.postamble
+ end
+
+ return source
+end
+
+
diff --git a/examples/lissajous/LICK/lib/object.lua b/examples/lissajous/LICK/lib/object.lua
new file mode 100644
index 0000000..c8d5350
--- /dev/null
+++ b/examples/lissajous/LICK/lib/object.lua
@@ -0,0 +1,282 @@
+-- OBJECT.lua
+-- object oriented livecoding library
+_internal_object_table = {}
+
+-- hump for classing
+local Class = require "LICK/lib/hump/.class"
+local hlpr = require "LICK/lib/hlpr"
+require "LICK/lib/loveosc"
+
+
+--[[
+ OBJECT
+--]]
+-- @Object: base class
+Object = Class(function(self)
+ -- TODO: Object base code
+ table.insert(_internal_object_table, self)
+end)
+
+function Object:update(dt)
+ -- TODO: insert typical update
+ -- print("updated")
+end
+
+--[[
+ SCOBJECT
+--]]
+
+-- @SCObject: bass class for supercollider communication
+SCObject = Class(function(self)
+ Object.construct(self)
+end)
+SCObject:inherit(Object)
+
+
+--[[
+ SCSYNTH
+--]]
+-- @SCSynth: supercollider synthesizer class
+SCSynth = Class(function(self, nodename, freq)
+ SCObject.construct(self)
+ self.nodename = nodename or "default"
+ self.freq = freq or 440
+ self.nodeid = 1000 + math.random(1000)
+end)
+SCSynth:inherit(SCObject)
+
+-- #set a control, TODO: variable lenght of argument-pairs
+function SCSynth:set(control, val)
+ local var = {
+ "#bundle",
+ os.time(),
+ {
+ "/n_set",
+ "i",
+ self.nodeid,
+ "s",
+ control,
+ "f",
+ val
+ }
+ }
+
+ osc.client:send(var)
+ --print("OUTGOING OSC MESSAGE")
+end
+
+--#sends an OSC message to the supercollider to start the synth
+function SCSynth:play()
+ local var = {
+ "#bundle",
+ os.time(),
+ {
+ "/s_new",
+ "s",
+ self.nodename,
+ "i",
+ self.nodeid,
+ "i",
+ 0,
+ "i",
+ 0,
+ "s",
+ "freq",
+ "f",
+ self.freq
+ }
+ }
+
+ osc.client:send(var)
+ --print("OUTGOING OSC MESSAGE")
+end
+
+--#frees the node on the supercollider server
+function SCSynth:free()
+ local var = {
+ "#bundle",
+ os.time()+0.8,
+ {
+ "/n_free",
+ "i",
+ self.nodeid,
+ "i",
+ 0
+ }
+ }
+
+ osc.client:send(var)
+ --print("OUTGOING OSC MESSAGE")
+end
+
+--[[
+ DRAWABLE
+--]]
+-- @Drawable: base class for all drawable stuff
+Drawable = Class(function(self, x, y, color)
+ self.color = color or hlpr.color("white",255)
+ -- call constructor of Object class
+ Object.construct(self)
+
+ self.position = Vector(x,y)
+ self.pos = self.position
+ self.x = self.position.x
+ self.y = self.position.y
+end)
+Drawable:inherit(Object)
+
+-- #can be called via wrapX(max) or wrapX(min,max)
+function Drawable:wrapX(min, max)
+ if min and max then
+ self:wrap("x", min, max)
+ elseif min and not max then
+ self:wrap("x", 0, min)
+ end
+end
+
+-- #can be called via wrapY(max) or wrapY(min,max)
+function Drawable:wrapY(min, max)
+ if min and max then
+ self:wrap("y", min, max)
+ elseif min and not max then
+ self:wrap("y", 0, min)
+ end
+end
+
+-- #internal wrapper
+function Drawable:wrap(str, min, max)
+ if str == "x" then
+ self.position.x = hlpr.wrap(self.position.x, min, max)
+ elseif str == "y" then
+ self.position.y = hlpr.wrap(self.position.y, min, max)
+ end
+end
+
+-- #supercollider style 'set'
+function Drawable:set(str, val)
+
+ if str == "x" then
+ self.position.x = val or self.position.x
+ elseif str == "y" then
+ self.position.y = val or self.position.y
+ end
+ -- TODO: add lots and lots and lots
+end
+
+-- #not yet implemented
+function Drawable:draw()
+ -- TODO: abstract draw code...
+end
+
+
+
+
+--[[
+ CIRCLE
+--]]
+-- @Circle: drawable circle
+Circle = Class(function(self, x, y, r, s, color)
+ self.r = r or 10
+ self.s = s or 16
+ -- call constructor of Drawable
+ Drawable.construct(self,x,y,color)
+end)
+Circle:inherit(Drawable)
+
+-- #draw the circle
+function Circle:draw(style)
+ if style ~= "fill" and style ~= "line" then
+ style = "line"
+ end
+ love.graphics.setColor(unpack(self.color))
+ love.graphics.circle(style, self.position.x, self.position.y, self.r, self.s)
+end
+
+
+
+----------------------------------------
+-- Experimental Objects
+----------------------------------------
+
+
+--[[
+ LINE
+--]]
+-- @Line: draw a line
+Line = Class(function(self, x, y, tx, ty, color) -- wats the dealio for polylines?
+ self.x = x or 0
+ self.y = y or 0
+ self.tx = tx or 0
+ self.ty = ty or 0
+ -- call constructor of Drawable
+ Drawable.construct(self, x, y, color)
+
+ end)
+Line:inherit(Drawable)
+-- TODO: FIX the :set("key", value) ... dunno how it works..!
+
+-- #draw the line
+function Line:draw(width, style)
+ local width=width or 1
+ if style ~= "smooth" and style ~= "rough" then
+ style = "smooth"
+ end
+ love.graphics.setLine(width, style)
+ love.graphics.setColor(unpack(self.color))
+ love.graphics.line(self.position.x, self.position.y, self.tx, self.ty)
+end
+
+
+--[[
+ IMAGE
+--]]
+-- @Image: Image from file
+Image = Class(function(self, file, x, y, color, size, orientation)
+ self.image = love.graphics.newImage(file)
+ -- put positions, size, orientation...
+
+ -- call constructor of Drawable
+ Drawable.construct(self,x,y,color)
+ end)
+Image:inherit(Drawable)
+
+-- #draw the image
+function Image:draw()
+ love.graphics.setColor(unpack(self.color))
+ love.graphics.draw(self.image, self.position.x, self.position.y)
+end
+
+--[[
+ POINT
+--]]
+-- @Point
+Point = Class(function(self, x, y, color, size, style)
+ local color=color or ""
+ local size=size or 1
+ local style=style or "smooth"
+
+ -- should this be here? or in the constructor?
+ self.size = size
+ self.style = style
+
+ -- call constructor of Drawable
+ Drawable.construct(self,x,y,color)
+ end)
+Point:inherit(Drawable)
+
+-- #draw the point
+function Point:draw()
+ love.graphics.setColor(unpack(self.color))
+ love.graphics.setPoint(self.size, self.style)
+ love.graphics.point(self.position.x, self.position.y)
+end
+
+
+-- EXAMPLE:
+-- (put in love.load):
+-- coco = Circle(300,300)
+-- (put in love.update):
+-- coco:set("x", 30)
+-- (put in love.draw):
+-- coco:draw("fill")
+
diff --git a/examples/lissajous/LICK/lick.lua b/examples/lissajous/LICK/lick.lua
new file mode 100644
index 0000000..05cede2
--- /dev/null
+++ b/examples/lissajous/LICK/lick.lua
@@ -0,0 +1,127 @@
+-- lick.lua
+--
+-- simple LIVECODING environment with löve, overwrites love.run, suppressing errors to the terminal/console
+
+
+
+lick = {}
+lick.file = "main.lua"
+lick.debug = false
+lick.reset = false
+lick.clearFlag = false
+
+function handle(err)
+ return "ERROR: " .. err
+end
+
+function lick.setFile(str)
+ live.file = str or "lick.lua"
+end
+
+-- Initialization
+function lick.load()
+ last_modified = 0
+end
+
+-- load the lickcoding file and execute the contained update function
+function lick.update(dt)
+ if love.filesystem.exists(lick.file) and last_modified < love.filesystem.getLastModified(lick.file) then
+ last_modified = love.filesystem.getLastModified(lick.file)
+ success, chunk = pcall(love.filesystem.load, lick.file)
+ if not success then
+ print(tostring(chunk))
+ lick.debugoutput = chunk .. "\n"
+
+ end
+ ok,err = xpcall(chunk, handle)
+ if not ok then
+ print(tostring(err))
+ if lick.debugoutput then
+ lick.debugoutput = (lick.debugoutput .."ERROR: ".. err .. "\n" )
+ else lick.debugoutput = err .. "\n" end
+ end
+ if ok then
+ print("CHUNK LOADED\n")
+ lick.debugoutput = nil
+ end
+ if lick.reset then
+ loadok, err = xpcall(love.load, handle)
+ if not loadok and not loadok_old then
+ print("ERROR: "..tostring(err))
+ if lick.debugoutput then
+ lick.debugoutput = (lick.debugoutput .."ERROR: ".. err .. "\n" )
+ else lick.debugoutput = err .. "\n" end
+ loadok_old = not loadok
+ end
+
+
+ end
+ end
+ updateok, err = pcall(love.update,dt)
+ if not updateok and not updateok_old then
+ print("ERROR: "..tostring(err))
+ if lick.debugoutput then
+ lick.debugoutput = (lick.debugoutput .."ERROR: ".. err .. "\n" )
+ else lick.debugoutput = err .. "\n" end
+ end
+
+ updateok_old = not updateok
+end
+
+function lick.draw()
+ drawok, err = xpcall(love.draw, handle)
+ if not drawok and not drawok_old then
+ print(tostring(err))
+ if lick.debugoutput then
+ lick.debugoutput = (lick.debugoutput .. err .. "\n" )
+ else lick.debugoutput = err .. "\n" end
+ end
+ if lick.debug and lick.debugoutput then
+ love.graphics.setColor(255,255,255,120)
+ love.graphics.print(lick.debugoutput, 0, 0)
+ end
+ drawok_old = not drawok
+end
+
+function love.run()
+
+ if love.load then love.load(arg) end
+ lick.load()
+ local dt = 0
+
+ -- Main loop time.
+ while true do
+ if love.timer then
+ love.timer.step()
+ dt = love.timer.getDelta()
+ end
+ -- if love.update then love.update(dt) end -- will pass 0 if love.timer is disabled
+ lick.update(dt)
+ if love.graphics then
+ if not lick.clearFlag then love.graphics.clear() end
+ -- if love.draw then love.draw() end
+ lick.draw()
+ end
+
+ -- Process events.
+ if love.event then
+ for e,a,b,c in love.event.poll() do
+ if e == "q" then
+ if not love.quit or not love.quit() then
+ if love.audio then
+ love.audio.stop()
+ end
+ return
+ end
+ end
+ love.handlers[e](a,b,c)
+ end
+ end
+
+ if love.timer then love.timer.sleep(1) end
+ if love.graphics then love.graphics.present() end
+
+ end
+
+end
+
diff --git a/examples/lissajous/conf.lua b/examples/lissajous/conf.lua
new file mode 100644
index 0000000..7a7b397
--- /dev/null
+++ b/examples/lissajous/conf.lua
@@ -0,0 +1,21 @@
+function love.conf(t)
+ t.modules.joystick = true -- Enable the joystick module (boolean)
+ t.modules.audio = true -- Enable the audio module (boolean)
+ t.modules.keyboard = true -- Enable the keyboard module (boolean)
+ t.modules.event = true -- Enable the event module (boolean)
+ t.modules.image = true -- Enable the image module (boolean)
+ t.modules.graphics = true -- Enable the graphics module (boolean)
+ t.modules.timer = true -- Enable the timer module (boolean)
+ t.modules.mouse = true -- Enable the mouse module (boolean)
+ t.modules.sound = true -- Enable the sound module (boolean)
+ t.modules.physics = true -- Enable the physics module (boolean)
+ t.console = false -- Attach a console (boolean, Windows only)
+ t.title = "live_testproject" -- The title of the window the game is in (string)
+ t.author = "Tilmann Hars" -- The author of the game (string)
+ t.screen.fullscreen = false -- Enable fullscreen (boolean)
+ t.screen.vsync = true -- Enable vertical sync (boolean)
+ t.screen.fsaa = 0 -- The number of FSAA-buffers (number)
+ t.screen.height = 600 -- The window height (number)
+ t.screen.width = 800 -- The window width (number)
+ t.version = 0 -- The LÖVE version this game was made for (number)
+end
diff --git a/examples/lissajous/main.lua b/examples/lissajous/main.lua
new file mode 100644
index 0000000..8e554eb
--- /dev/null
+++ b/examples/lissajous/main.lua
@@ -0,0 +1,56 @@
+require "LICK"
+require "LICK/lib"
+ez = require "LICK/lib/hlpr"
+lick.reset = true
+lick.clearFlag = true
+
+
+-- put in main.lua
+function love.load()
+
+ declare({
+ t = 0,
+ x = 0,
+ y = 0,
+ o1 = 0,
+ o2 = 0,
+ g1 = 0,
+ g2 = 0,
+ k = 0,
+ h = 0,
+ circle = Circle(200,200,1,32, ez.color("white"))
+ })
+
+
+end
+
+function love.update(dt)
+ circle.color = ez.color("green", 150)
+ h = 5 + 0.01
+ k = 1 + 0.0001
+end
+
+function love.draw()
+ ez.cls(20)
+ love.graphics.setBlendMode("alpha")
+
+ for i=1,500 do
+ t = t + 0.01
+ o1 = 1 * h
+ o2 = 2.5 * k
+ g1 = 400
+ g2 = 300
+ scale = 300
+ x = scale * sin(o1 * t) + g1
+ y = scale * sin(o2 * t) + g2
+ circle.pos.x = x
+ circle.pos.y = y
+
+
+ circle:draw("fill")
+ end
+ love.graphics.setBlendMode("multiplicative")
+
+
+end
+