Merge pull request #2144 from Memphiz/canotify
authorMemphiz <memphis@machzwo.de>
Thu, 31 Jan 2013 20:33:43 +0000 (12:33 -0800)
committerMemphiz <memphis@machzwo.de>
Thu, 31 Jan 2013 20:33:43 +0000 (12:33 -0800)
[AE/CA] - add and handle devicechange notification

59 files changed:
.gitignore
Makefile.in
addons/skin.confluence/720p/DialogAlbumInfo.xml
addons/skin.confluence/720p/DialogVideoInfo.xml
addons/skin.confluence/720p/MyWeather.xml
addons/skin.confluence/720p/SkinSettings.xml
addons/skin.confluence/720p/VideoOSD.xml
addons/skin.confluence/720p/script-globalsearch-main.xml
addons/skin.confluence/720p/weather/10DayForecast.xml
addons/skin.confluence/720p/weather/HourlyForecast.xml
addons/visualization.fishbmc/LICENSE [new file with mode: 0644]
addons/visualization.fishbmc/addon.xml [new file with mode: 0644]
addons/visualization.fishbmc/changelog.txt [new file with mode: 0644]
addons/visualization.fishbmc/icon.png [new file with mode: 0644]
addons/visualization.fishbmc/resources/language/English/strings.xml [new file with mode: 0644]
addons/visualization.fishbmc/resources/settings.xml [new file with mode: 0644]
addons/xbmc.addon/addon.xml
configure.in
media/Splash.png
tools/android/depends/libssh/android.patch
tools/android/packaging/xbmc/AndroidManifest.xml
tools/darwin/packaging/xbmc-atv2/mkdeb-xbmc-atv2.sh
tools/darwin/packaging/xbmc-ios/mkdeb-xbmc-ios.sh
xbmc/GUIInfoManager.h
xbmc/cores/omxplayer/OMXVideo.cpp
xbmc/cores/paplayer/PAPlayer.cpp
xbmc/guilib/GUIRSSControl.cpp
xbmc/guilib/GUIRSSControl.h
xbmc/music/dialogs/GUIDialogMusicInfo.cpp
xbmc/music/dialogs/GUIDialogMusicInfo.h
xbmc/music/dialogs/GUIDialogSongInfo.cpp
xbmc/network/AirPlayServer.cpp
xbmc/network/TCPServer.cpp
xbmc/osx/Info.plist
xbmc/video/dialogs/GUIDialogVideoInfo.cpp
xbmc/visualizations/fishBMC/Makefile.in [new file with mode: 0644]
xbmc/visualizations/fishBMC/analyst.c [new file with mode: 0644]
xbmc/visualizations/fishBMC/analyst.h [new file with mode: 0644]
xbmc/visualizations/fishBMC/audiobuffer.c [new file with mode: 0644]
xbmc/visualizations/fishBMC/audiobuffer.h [new file with mode: 0644]
xbmc/visualizations/fishBMC/blurengine.c [new file with mode: 0644]
xbmc/visualizations/fishBMC/blurengine.h [new file with mode: 0644]
xbmc/visualizations/fishBMC/cpudetect.c [new file with mode: 0644]
xbmc/visualizations/fishBMC/fische.c [new file with mode: 0644]
xbmc/visualizations/fishBMC/fische.h [new file with mode: 0644]
xbmc/visualizations/fishBMC/fische_internal.h [new file with mode: 0644]
xbmc/visualizations/fishBMC/fishbmc_addon.cpp [new file with mode: 0644]
xbmc/visualizations/fishBMC/fishbmc_directx.hpp [new file with mode: 0644]
xbmc/visualizations/fishBMC/fishbmc_opengl.hpp [new file with mode: 0644]
xbmc/visualizations/fishBMC/screenbuffer.c [new file with mode: 0644]
xbmc/visualizations/fishBMC/screenbuffer.h [new file with mode: 0644]
xbmc/visualizations/fishBMC/vector.c [new file with mode: 0644]
xbmc/visualizations/fishBMC/vector.h [new file with mode: 0644]
xbmc/visualizations/fishBMC/vectorfield.c [new file with mode: 0644]
xbmc/visualizations/fishBMC/vectorfield.h [new file with mode: 0644]
xbmc/visualizations/fishBMC/wavepainter.c [new file with mode: 0644]
xbmc/visualizations/fishBMC/wavepainter.h [new file with mode: 0644]
xbmc/win32/XBMC_PC.rc
xbmc/windowing/windows/WinEventsWin32.cpp

index 9b4f7f0..56fdf28 100644 (file)
@@ -122,6 +122,7 @@ config.log
 /addons/visualization.waveform/Waveform.vis
 /addons/visualization.waveform/Waveform_win32.vis
 /addons/visualization.itunes/iTunes.mvis
+/addons/visualization.fishbmc/fishbmc.vis
 /addons/script.module.pil/
 /addons/pvr.*
 
@@ -1222,6 +1223,7 @@ xbmc/visualizations/EGLHelpers/Makefile
 /xbmc/visualizations/XBMCProjectM/libprojectM/CMakeFiles/
 /xbmc/visualizations/XBMCProjectM/libprojectM/cmake_install.cmake
 /xbmc/visualizations/XBMCProjectM/libprojectM/config.inp
+/xbmc/visualizations/fishBMC/Makefile
 
 /xbmc/win32/git_rev.h
 
index 39dc6f9..d7ee22a 100644 (file)
@@ -194,7 +194,8 @@ ifneq (@DISABLE_RSXS@,1)
 endif
 
 VIS_DIRS=xbmc/visualizations/OpenGLSpectrum \
-         xbmc/visualizations/WaveForm
+         xbmc/visualizations/WaveForm \
+         xbmc/visualizations/fishBMC
 
 ifneq (@DISABLE_PROJECTM@,1)
   VIS_DIRS+= xbmc/visualizations/XBMCProjectM
index 888b01a..a9ed8ef 100644 (file)
                                                        <item>
                                                                <label>$LOCALIZE[557]:</label>
                                                                <label2>$INFO[ListItem.Artist]</label2>
-                                                               <onclick>-</onclick>
+                                                               <onclick>noop</onclick>
                                                                <visible>!IsEmpty(ListItem.Artist)</visible>
                                                        </item>
                                                        <item>
                                                                <label>$LOCALIZE[515]:</label>
                                                                <label2>$INFO[ListItem.Genre]</label2>
-                                                               <onclick>-</onclick>
+                                                               <onclick>noop</onclick>
                                                                <visible>!IsEmpty(ListItem.Genre)</visible>
                                                        </item>
                                                        <item>
                                                                <label>$LOCALIZE[563]:</label>
                                                                <label2>$INFO[ListItem.Rating]</label2>
-                                                               <onclick>-</onclick>
+                                                               <onclick>noop</onclick>
                                                                <visible>!IsEmpty(ListItem.Rating)</visible>
                                                        </item>
                                                        <item>
                                                                <label>$LOCALIZE[175]:</label>
                                                                <label2>$INFO[ListItem.Property(Album_Mood)]</label2>
-                                                               <onclick>-</onclick>
+                                                               <onclick>noop</onclick>
                                                                <visible>!IsEmpty(ListItem.Property(Album_Mood))</visible>
                                                        </item>
                                                        <item>
                                                                <label>$LOCALIZE[176]:</label>
                                                                <label2>$INFO[ListItem.Property(Album_Style)]</label2>
-                                                               <onclick>-</onclick>
+                                                               <onclick>noop</onclick>
                                                                <visible>!IsEmpty(ListItem.Property(Album_Style))</visible>
                                                        </item>
                                                        <item>
                                                                <label>$LOCALIZE[21895]:</label>
                                                                <label2>$INFO[ListItem.Property(Album_Theme)]</label2>
-                                                               <onclick>-</onclick>
+                                                               <onclick>noop</onclick>
                                                                <visible>!IsEmpty(ListItem.Property(Album_Theme))</visible>
                                                        </item>
                                                        <item>
                                                                <label>146</label>
                                                                <label2>$INFO[ListItem.Property(Album_Type)]</label2>
-                                                               <onclick>-</onclick>
+                                                               <onclick>noop</onclick>
                                                                <visible>!IsEmpty(ListItem.Property(Album_Type))</visible>
                                                        </item>
                                                        <item>
                                                                <label>$LOCALIZE[21899]:</label>
                                                                <label2>$INFO[ListItem.Property(Album_Label)]</label2>
-                                                               <onclick>-</onclick>
+                                                               <onclick>noop</onclick>
                                                                <visible>!IsEmpty(ListItem.Property(Album_Label))</visible>
                                                        </item>
                                                        <item>
                                                                <label>$LOCALIZE[562]:</label>
                                                                <label2>$INFO[ListItem.Year]</label2>
-                                                               <onclick>-</onclick>
+                                                               <onclick>noop</onclick>
                                                                <visible>!IsEmpty(ListItem.Year)</visible>
                                                        </item>
                                                </content>
                                                        <item>
                                                                <label>$LOCALIZE[21893]:</label>
                                                                <label2>$INFO[ListItem.Property(Artist_Born)]</label2>
-                                                               <onclick>-</onclick>
+                                                               <onclick>noop</onclick>
                                                                <visible>!IsEmpty(ListItem.Property(Artist_Born))</visible>
                                                        </item>
                                                        <item>
                                                                <label>$LOCALIZE[21894]:</label>
                                                                <label2>$INFO[ListItem.Property(Artist_Formed)]</label2>
-                                                               <onclick>-</onclick>
+                                                               <onclick>noop</onclick>
                                                                <visible>!IsEmpty(ListItem.Property(Artist_Formed))</visible>
                                                        </item>
                                                        <item>
                                                                <label>$LOCALIZE[515]:</label>
                                                                <label2>$INFO[ListItem.Genre]</label2>
-                                                               <onclick>-</onclick>
+                                                               <onclick>noop</onclick>
                                                                <visible>!IsEmpty(ListItem.Genre)</visible>
                                                        </item>
                                                        <item>
                                                                <label>$LOCALIZE[175]:</label>
                                                                <label2>$INFO[ListItem.Property(Artist_Mood)]</label2>
-                                                               <onclick>-</onclick>
+                                                               <onclick>noop</onclick>
                                                                <visible>!IsEmpty(ListItem.Property(Artist_Mood))</visible>
                                                        </item>
                                                        <item>
                                                                <label>$LOCALIZE[176]:</label>
                                                                <label2>$INFO[ListItem.Property(Artist_Style)]</label2>
-                                                               <onclick>-</onclick>
+                                                               <onclick>noop</onclick>
                                                                <visible>!IsEmpty(ListItem.Property(Artist_Style))</visible>
                                                        </item>
                                                        <item>
                                                                <label>$LOCALIZE[21892]:</label>
                                                                <label2>$INFO[ListItem.Property(Artist_Instrument)]</label2>
-                                                               <onclick>-</onclick>
+                                                               <onclick>noop</onclick>
                                                                <visible>!IsEmpty(ListItem.Property(Artist_Instrument))</visible>
                                                        </item>
                                                        <item>
                                                                <label>$LOCALIZE[21897]:</label>
                                                                <label2>$INFO[ListItem.Property(Artist_Died)]</label2>
-                                                               <onclick>-</onclick>
+                                                               <onclick>noop</onclick>
                                                                <visible>!IsEmpty(ListItem.Property(Artist_Died))</visible>
                                                        </item>
                                                        <item>
                                                                <label>$LOCALIZE[21896]:</label>
                                                                <label2>$INFO[ListItem.Property(Artist_Disbanded)]</label2>
-                                                               <onclick>-</onclick>
+                                                               <onclick>noop</onclick>
                                                                <visible>!IsEmpty(ListItem.Property(Artist_Disbanded))</visible>
                                                        </item>
                                                        <item>
                                                                <label>$LOCALIZE[21898]:</label>
                                                                <label2>$INFO[ListItem.Property(Artist_YearsActive)]</label2>
-                                                               <onclick>-</onclick>
+                                                               <onclick>noop</onclick>
                                                                <visible>!IsEmpty(ListItem.Property(Artist_YearsActive))</visible>
                                                        </item>
                                                </content>
                </control>
                <include>Clock</include>
        </controls>
-</window>
\ No newline at end of file
+</window>
index 5c349d3..b62a25a 100644 (file)
                                                        <item>
                                                                <label>$LOCALIZE[20376]:</label>
                                                                <label2>$INFO[ListItem.OriginalTitle]</label2>
-                                                               <onclick>-</onclick>
+                                                               <onclick>noop</onclick>
                                                                <visible>!IsEmpty(ListItem.OriginalTitle) + !stringcompare(ListItem.OriginalTitle,Listitem.Title)</visible>
                                                        </item>
                                                        <item>
                                                        <item>
                                                                <label>$LOCALIZE[20417]:</label>
                                                                <label2>$INFO[ListItem.Writer]</label2>
-                                                               <onclick>-</onclick>
+                                                               <onclick>noop</onclick>
                                                                <visible>!IsEmpty(ListItem.Writer)</visible>
                                                        </item>
                                                        <item>
                                                                <label>$LOCALIZE[572]:</label>
                                                                <label2>$INFO[ListItem.Studio]</label2>
-                                                               <onclick>-</onclick>
+                                                               <onclick>noop</onclick>
                                                                <visible>!IsEmpty(ListItem.Studio)</visible>
                                                        </item>
                                                        <item>
                                                                <label>$LOCALIZE[515]:</label>
                                                                <label2>$INFO[ListItem.Genre]</label2>
-                                                               <onclick>-</onclick>
+                                                               <onclick>noop</onclick>
                                                                <visible>!IsEmpty(ListItem.Genre)</visible>
                                                        </item>
                                                        <item>
                                                                <label>$LOCALIZE[562]:</label>
                                                                <label2>$INFO[ListItem.Year]</label2>
-                                                               <onclick>-</onclick>
+                                                               <onclick>noop</onclick>
                                                                <visible>!IsEmpty(ListItem.Year)</visible>
                                                        </item>
                                                        <item>
                                                                <label>$LOCALIZE[2050]:</label>
                                                                <label2>$INFO[ListItem.Duration] $LOCALIZE[12391]</label2>
-                                                               <onclick>-</onclick>
+                                                               <onclick>noop</onclick>
                                                                <visible>!IsEmpty(ListItem.Duration)</visible>
                                                        </item>
                                                        <item>
                                                                <label>$LOCALIZE[563]:</label>
                                                                <label2>$INFO[ListItem.RatingAndVotes]</label2>
-                                                               <onclick>-</onclick>
+                                                               <onclick>noop</onclick>
                                                                <visible>!IsEmpty(ListItem.RatingAndVotes)</visible>
                                                        </item>
                                                        <item>
                                                                <label>$LOCALIZE[202]:</label>
                                                                <label2>$INFO[ListItem.TagLine]</label2>
-                                                               <onclick>-</onclick>
+                                                               <onclick>noop</onclick>
                                                                <visible>!IsEmpty(ListItem.TagLine)</visible>
                                                        </item>
                                                        <item>
                                                                <label>$LOCALIZE[203]:</label>
                                                                <label2>$INFO[ListItem.PlotOutline]</label2>
-                                                               <onclick>-</onclick>
+                                                               <onclick>noop</onclick>
                                                                <visible>!IsEmpty(ListItem.PlotOutline)</visible>
                                                        </item>
                                                        <item>
                                                                <label>$LOCALIZE[20074]:</label>
                                                                <label2>$INFO[ListItem.mpaa]</label2>
-                                                               <onclick>-</onclick>
+                                                               <onclick>noop</onclick>
                                                                <visible>!IsEmpty(ListItem.mpaa)</visible>
                                                        </item>
                                                        <item>
                                                                <label>$LOCALIZE[15311]</label>
                                                                <label2>$INFO[ListItem.FilenameAndPath]</label2>
-                                                               <onclick>-</onclick>
+                                                               <onclick>noop</onclick>
                                                                <visible>!IsEmpty(ListItem.FilenameAndPath)</visible>
                                                        </item>
                                                </content>
                                                        <item>
                                                                <label>$LOCALIZE[20360]:</label>
                                                                <label2>$INFO[listitem.episode] [COLOR=grey] ($INFO[ListItem.Property(WatchedEpisodes),, $LOCALIZE[16102]] - $INFO[ListItem.Property(UnWatchedEpisodes), , $LOCALIZE[16101]])[/COLOR]</label2>
-                                                               <onclick>-</onclick>
+                                                               <onclick>noop</onclick>
                                                                <visible>!IsEmpty(ListItem.Episode)</visible>
                                                        </item>
                                                        <item>
                                                                <label>$LOCALIZE[31322]:</label>
                                                                <label2>$INFO[ListItem.Premiered]</label2>
-                                                               <onclick>-</onclick>
+                                                               <onclick>noop</onclick>
                                                                <visible>!IsEmpty(ListItem.Premiered)</visible>
                                                        </item>
                                                        <item>
                                                                <label>$LOCALIZE[515]:</label>
                                                                <label2>$INFO[ListItem.Genre]</label2>
-                                                               <onclick>-</onclick>
+                                                               <onclick>noop</onclick>
                                                                <visible>!IsEmpty(ListItem.Genre)</visible>
                                                        </item>
                                                        <item>
                                                                <label>$LOCALIZE[562]:</label>
                                                                <label2>$INFO[ListItem.Year]</label2>
-                                                               <onclick>-</onclick>
+                                                               <onclick>noop</onclick>
                                                                <visible>!IsEmpty(ListItem.Year)</visible>
                                                        </item>
                                                        <item>
                                                                <label>$LOCALIZE[563]:</label>
                                                                <label2>$INFO[ListItem.Rating]</label2>
-                                                               <onclick>-</onclick>
+                                                               <onclick>noop</onclick>
                                                                <visible>!IsEmpty(ListItem.Rating)</visible>
                                                        </item>
                                                        <item>
                                                                <label>$LOCALIZE[15311]</label>
                                                                <label2>$INFO[ListItem.FilenameAndPath]</label2>
-                                                               <onclick>-</onclick>
+                                                               <onclick>noop</onclick>
                                                                <visible>!IsEmpty(ListItem.FilenameAndPath)</visible>
                                                        </item>
                                                </content>
                                                        <item>
                                                                <label>$LOCALIZE[20364]:</label>
                                                                <label2>$INFO[ListItem.TVShowTitle]</label2>
-                                                               <onclick>-</onclick>
+                                                               <onclick>noop</onclick>
                                                                <visible>!IsEmpty(ListItem.TVShowTitle)</visible>
                                                        </item>
                                                        <item>
                                                                <label>$LOCALIZE[20373]:</label>
                                                                <label2>$INFO[ListItem.Season]</label2>
-                                                               <onclick>-</onclick>
+                                                               <onclick>noop</onclick>
                                                                <visible>!IsEmpty(ListItem.Season)</visible>
                                                        </item>
                                                        <item>
                                                                <label>$LOCALIZE[20359]:</label>
                                                                <label2>$INFO[ListItem.Episode]</label2>
-                                                               <onclick>-</onclick>
+                                                               <onclick>noop</onclick>
                                                                <visible>!IsEmpty(ListItem.Episode)</visible>
                                                        </item>
                                                        <item>
                                                                <label>$LOCALIZE[31322]:</label>
                                                                <label2>$INFO[ListItem.Premiered]</label2>
-                                                               <onclick>-</onclick>
+                                                               <onclick>noop</onclick>
                                                                <visible>!IsEmpty(ListItem.Premiered)</visible>
                                                        </item>
                                                        <item>
                                                                <label>$LOCALIZE[515]:</label>
                                                                <label2>$INFO[ListItem.Genre]</label2>
-                                                               <onclick>-</onclick>
+                                                               <onclick>noop</onclick>
                                                                <visible>!IsEmpty(ListItem.Genre)</visible>
                                                        </item>
                                                        <item>
                                                        <item>
                                                                <label>$LOCALIZE[20417]:</label>
                                                                <label2>$INFO[ListItem.Writer]</label2>
-                                                               <onclick>-</onclick>
+                                                               <onclick>noop</onclick>
                                                                <visible>!IsEmpty(ListItem.Writer)</visible>
                                                        </item>
                                                        <item>
                                                                <label>$LOCALIZE[562]:</label>
                                                                <label2>$INFO[ListItem.Year]</label2>
-                                                               <onclick>-</onclick>
+                                                               <onclick>noop</onclick>
                                                                <visible>!IsEmpty(ListItem.Year)</visible>
                                                        </item>
                                                        <item>
                                                                <label>$LOCALIZE[2050]:</label>
                                                                <label2>$INFO[ListItem.Duration] $LOCALIZE[12391]</label2>
-                                                               <onclick>-</onclick>
+                                                               <onclick>noop</onclick>
                                                                <visible>!IsEmpty(ListItem.Duration)</visible>
                                                        </item>
                                                        <item>
                                                                <label>$LOCALIZE[563]:</label>
                                                                <label2>$INFO[ListItem.Rating]</label2>
-                                                               <onclick>-</onclick>
+                                                               <onclick>noop</onclick>
                                                                <visible>!IsEmpty(ListItem.Rating)</visible>
                                                        </item>
                                                        <item>
                                                                <label>$LOCALIZE[15311]</label>
                                                                <label2>$INFO[ListItem.FilenameAndPath]</label2>
-                                                               <onclick>-</onclick>
+                                                               <onclick>noop</onclick>
                                                                <visible>!IsEmpty(ListItem.FilenameAndPath)</visible>
                                                        </item>
                                                </content>
                                                        <item>
                                                                <label>$LOCALIZE[557]:</label>
                                                                <label2>$INFO[ListItem.Artist]</label2>
-                                                               <onclick>-</onclick>
+                                                               <onclick>noop</onclick>
                                                                <visible>!IsEmpty(ListItem.Artist)</visible>
                                                        </item>
                                                        <item>
                                                                <label>$LOCALIZE[558]:</label>
                                                                <label2>$INFO[ListItem.Album]</label2>
-                                                               <onclick>-</onclick>
+                                                               <onclick>noop</onclick>
                                                                <visible>!IsEmpty(ListItem.Album)</visible>
                                                        </item>
                                                        <item>
                                                                <label>$LOCALIZE[515]:</label>
                                                                <label2>$INFO[ListItem.Genre]</label2>
-                                                               <onclick>-</onclick>
+                                                               <onclick>noop</onclick>
                                                                <visible>!IsEmpty(ListItem.Genre)</visible>
                                                        </item>
                                                        <item>
                                                                <label>$LOCALIZE[572]:</label>
                                                                <label2>$INFO[ListItem.Studio]</label2>
-                                                               <onclick>-</onclick>
+                                                               <onclick>noop</onclick>
                                                                <visible>!IsEmpty(ListItem.Studio)</visible>
                                                        </item>
                                                        <item>
                                                                <label>$LOCALIZE[20417]:</label>
                                                                <label2>$INFO[ListItem.Writer]</label2>
-                                                               <onclick>-</onclick>
+                                                               <onclick>noop</onclick>
                                                                <visible>!IsEmpty(ListItem.Writer)</visible>
                                                        </item>
                                                        <item>
                                                                <label>$LOCALIZE[20339]:</label>
                                                                <label2>$INFO[ListItem.Director]</label2>
-                                                               <onclick>-</onclick>
+                                                               <onclick>noop</onclick>
                                                                <visible>!IsEmpty(ListItem.Director)</visible>
                                                        </item>
                                                        <item>
                                                                <label>$LOCALIZE[562]:</label>
                                                                <label2>$INFO[ListItem.Year]</label2>
-                                                               <onclick>-</onclick>
+                                                               <onclick>noop</onclick>
                                                                <visible>!IsEmpty(ListItem.Year)</visible>
                                                        </item>
                                                        <item>
                                                                <label>$LOCALIZE[2050]:</label>
                                                                <label2>$INFO[ListItem.Duration] $LOCALIZE[12391]</label2>
-                                                               <onclick>-</onclick>
+                                                               <onclick>noop</onclick>
                                                                <visible>!IsEmpty(ListItem.Duration)</visible>
                                                        </item>
                                                        <item>
                                                                <label>$LOCALIZE[15311]</label>
                                                                <label2>$INFO[ListItem.FilenameAndPath]</label2>
-                                                               <onclick>-</onclick>
+                                                               <onclick>noop</onclick>
                                                                <visible>!IsEmpty(ListItem.FilenameAndPath)</visible>
                                                        </item>
                                                </content>
index 1b7f02d..76b6683 100644 (file)
                                                <item>
                                                        <label>$LOCALIZE[31909]</label>
                                                        <icon>-</icon>
-                                                       <onclick>-</onclick>
+                                                       <onclick>noop</onclick>
                                                        <visible>!Weather.IsFetched</visible>
                                                </item>
                                                <item>
                                                        <property name="LowTemp">$INFO[Window.Property(Day0.LowTemp)]</property>
                                                        <property name="Outlook">$INFO[Window.Property(Day0.Outlook)]</property>
                                                        <property name="TempUnits">$INFO[System.TemperatureUnits]</property>
-                                                       <onclick>-</onclick>
+                                                       <onclick>noop</onclick>
                                                        <visible>Weather.IsFetched + !IsEmpty(Window.Property(Day0.Title))</visible>
                                                </item>
                                                <item>
                                                        <property name="LowTemp">$INFO[Window.Property(Day1.LowTemp)]</property>
                                                        <property name="Outlook">$INFO[Window.Property(Day1.Outlook)]</property>
                                                        <property name="TempUnits">$INFO[System.TemperatureUnits]</property>
-                                                       <onclick>-</onclick>
+                                                       <onclick>noop</onclick>
                                                        <visible>Weather.IsFetched + !IsEmpty(Window.Property(Day1.Title))</visible>
                                                </item>
                                                <item>
                                                        <property name="LowTemp">$INFO[Window.Property(Day2.LowTemp)]</property>
                                                        <property name="Outlook">$INFO[Window.Property(Day2.Outlook)]</property>
                                                        <property name="TempUnits">$INFO[System.TemperatureUnits]</property>
-                                                       <onclick>-</onclick>
+                                                       <onclick>noop</onclick>
                                                        <visible>Weather.IsFetched + !IsEmpty(Window.Property(Day2.Title))</visible>
                                                </item>
                                                <item>
                                                        <property name="LowTemp">$INFO[Window.Property(Day3.LowTemp)]</property>
                                                        <property name="Outlook">$INFO[Window.Property(Day3.Outlook)]</property>
                                                        <property name="TempUnits">$INFO[System.TemperatureUnits]</property>
-                                                       <onclick>-</onclick>
+                                                       <onclick>noop</onclick>
                                                        <visible>Weather.IsFetched + !IsEmpty(Window.Property(Day3.Title))</visible>
                                                </item>
                                                <item>
                                                        <property name="LowTemp">$INFO[Window.Property(Day4.LowTemp)]</property>
                                                        <property name="Outlook">$INFO[Window.Property(Day4.Outlook)]</property>
                                                        <property name="TempUnits">$INFO[System.TemperatureUnits]</property>
-                                                       <onclick>-</onclick>
+                                                       <onclick>noop</onclick>
                                                        <visible>Weather.IsFetched + !IsEmpty(Window.Property(Day4.Title))</visible>
                                                </item>
                                                <item>
                                                        <property name="LowTemp">$INFO[Window.Property(Day5.LowTemp)]</property>
                                                        <property name="Outlook">$INFO[Window.Property(Day5.Outlook)]</property>
                                                        <property name="TempUnits">$INFO[System.TemperatureUnits]</property>
-                                                       <onclick>-</onclick>
+                                                       <onclick>noop</onclick>
                                                        <visible>Weather.IsFetched + !IsEmpty(Window.Property(Day5.Title))</visible>
                                                </item>
                                                <item>
                                                        <property name="LowTemp">$INFO[Window.Property(Day6.LowTemp)]</property>
                                                        <property name="Outlook">$INFO[Window.Property(Day6.Outlook)]</property>
                                                        <property name="TempUnits">$INFO[System.TemperatureUnits]</property>
-                                                       <onclick>-</onclick>
+                                                       <onclick>noop</onclick>
                                                        <visible>Weather.IsFetched + !IsEmpty(Window.Property(Day6.Title))</visible>
                                                </item>
                                                <item>
                                                        <property name="LowTemp">$INFO[Window.Property(Day7.LowTemp)]</property>
                                                        <property name="Outlook">$INFO[Window.Property(Day7.Outlook)]</property>
                                                        <property name="TempUnits">$INFO[System.TemperatureUnits]</property>
-                                                       <onclick>-</onclick>
+                                                       <onclick>noop</onclick>
                                                        <visible>Weather.IsFetched + !IsEmpty(Window.Property(Day7.Title))</visible>
                                                </item>
                                                <item>
                                                        <property name="LowTemp">$INFO[Window.Property(Day8.LowTemp)]</property>
                                                        <property name="Outlook">$INFO[Window.Property(Day8.Outlook)]</property>
                                                        <property name="TempUnits">$INFO[System.TemperatureUnits]</property>
-                                                       <onclick>-</onclick>
+                                                       <onclick>noop</onclick>
                                                        <visible>Weather.IsFetched + !IsEmpty(Window.Property(Day8.Title))</visible>
                                                </item>
                                                <item>
                                                        <property name="LowTemp">$INFO[Window.Property(Day9.LowTemp)]</property>
                                                        <property name="Outlook">$INFO[Window.Property(Day9.Outlook)]</property>
                                                        <property name="TempUnits">$INFO[System.TemperatureUnits]</property>
-                                                       <onclick>-</onclick>
+                                                       <onclick>noop</onclick>
                                                        <visible>Weather.IsFetched + !IsEmpty(Window.Property(Day9.Title))</visible>
                                                </item>
                                        </content>
index 0783e0d..08937da 100644 (file)
                                        <item id="1">
                                                <label>128</label>
                                                <label2>5</label2>
-                                               <onclick>-</onclick>
+                                               <onclick>noop</onclick>
                                        </item>
                                        <item id="2">
                                                <label>513</label>
                                                <label2>31112</label2>
-                                               <onclick>-</onclick>
+                                               <onclick>noop</onclick>
                                        </item>
                                        <item id="3">
                                                <label>31102</label>
                                                <label2>31112</label2>
-                                               <onclick>-</onclick>
+                                               <onclick>noop</onclick>
                                        </item>
                                        <item id="4">
                                                <label>24000</label>
                                                <label2>31200</label2>
-                                               <onclick>-</onclick>
+                                               <onclick>noop</onclick>
                                        </item>
                                </content>
                        </control>
index b114a5e..ccbceb4 100644 (file)
                                <onclick>Close</onclick>
                                <onclick>XBMC.RunScript($INFO[Skin.String(SubtitleScript_Path)])</onclick>
                                <altclick>Skin.SetAddon(SubtitleScript_Path,xbmc.python.subtitles)</altclick>
-                               <altclick>Close</altclick>
-                               <altclick>XBMC.RunScript($INFO[Skin.String(SubtitleScript_Path)])</altclick>
+                               <altclick condition="Window.IsVisible(VideoOSD)">Dialog.Close(VideoOSD)</altclick>
+                               <altclick condition="!IsEmpty(Skin.String(SubtitleScript_Path))">XBMC.RunScript($INFO[Skin.String(SubtitleScript_Path)])</altclick>
                                <usealttexture>IsEmpty(Skin.String(SubtitleScript_Path))</usealttexture>
                        </control>
                        <control type="button" id="251">
index 7de118c..3a520f3 100644 (file)
                                                <item id="1">
                                                        <label>$LOCALIZE[342]</label>
                                                        <label2>$LOCALIZE[31206] $INFO[Control.GetLabel(110)] $LOCALIZE[31025]</label2>
-                                                       <onclick>-</onclick>
+                                                       <onclick>noop</onclick>
                                                        <visible>Control.IsVisible(119)</visible>
                                                </item>
                                                <item id="2">
                                                        <label>$LOCALIZE[20343]</label>
                                                        <label2>$LOCALIZE[31206] $INFO[Control.GetLabel(120)] $LOCALIZE[31025]</label2>
-                                                       <onclick>-</onclick>
+                                                       <onclick>noop</onclick>
                                                        <visible>Control.IsVisible(129)</visible>
                                                </item>
                                                <item id="3">
                                                        <label>$LOCALIZE[33054]</label>
                                                        <label2>$LOCALIZE[31206] $INFO[Control.GetLabel(130)] $LOCALIZE[31025]</label2>
-                                                       <onclick>-</onclick>
+                                                       <onclick>noop</onclick>
                                                        <visible>Control.IsVisible(139)</visible>
                                                </item>
                                                <item id="4">
                                                        <label>$LOCALIZE[20360]</label>
                                                        <label2>$LOCALIZE[31206] $INFO[Control.GetLabel(140)] $LOCALIZE[31025]</label2>
-                                                       <onclick>-</onclick>
+                                                       <onclick>noop</onclick>
                                                        <visible>Control.IsVisible(149)</visible>
                                                </item>
                                                <item id="5">
                                                        <label>$LOCALIZE[20389]</label>
                                                        <label2>$LOCALIZE[31206] $INFO[Control.GetLabel(150)] $LOCALIZE[31025]</label2>
-                                                       <onclick>-</onclick>
+                                                       <onclick>noop</onclick>
                                                        <visible>Control.IsVisible(159)</visible>
                                                </item>
                                                <item id="6">
                                                        <label>$LOCALIZE[133]</label>
                                                        <label2>$LOCALIZE[31206] $INFO[Control.GetLabel(160)] $LOCALIZE[31025]</label2>
-                                                       <onclick>-</onclick>
+                                                       <onclick>noop</onclick>
                                                        <visible>Control.IsVisible(169)</visible>
                                                </item>
                                                <item id="7">
                                                        <label>$LOCALIZE[132]</label>
                                                        <label2>$LOCALIZE[31206] $INFO[Control.GetLabel(170)] $LOCALIZE[31025]</label2>
-                                                       <onclick>-</onclick>
+                                                       <onclick>noop</onclick>
                                                        <visible>Control.IsVisible(179)</visible>
                                                </item>
                                                <item id="8">
                                                        <label>$LOCALIZE[134]</label>
                                                        <label2>$LOCALIZE[31206] $INFO[Control.GetLabel(180)] $LOCALIZE[31025]</label2>
-                                                       <onclick>-</onclick>
+                                                       <onclick>noop</onclick>
                                                        <visible>Control.IsVisible(189)</visible>
                                                </item>
                                                <item id="10">
index a3e7695..36d64e3 100644 (file)
                                <content>
                                        <item>
                                                <icon>$LOCALIZE[31909]</icon>
-                                               <onclick>-</onclick>
+                                               <onclick>noop</onclick>
                                                <visible>IsEmpty(Window.Property(Daily.IsFetched))</visible>
                                        </item>
                                        <item>
                                                <label2>$INFO[Window.Property(Daily.1.HighTemperature),[COLOR=grey2]$LOCALIZE[419] :[/COLOR][B] ,[/B]]  $INFO[Window.Property(Daily.1.LowTemperature),[COLOR=grey2]$LOCALIZE[418] :[/COLOR][B] ,[/B]][CR]$INFO[Window.Property(Daily.1.Precipitation),[COLOR=grey2]$LOCALIZE[33022] :[/COLOR][B] ,[/B]]</label2>
                                                <thumb>$INFO[Window.Property(Daily.1.OutlookIcon)]</thumb>
                                                <icon>$INFO[Window.Property(Daily.1.Outlook),[COLOR=grey2]$LOCALIZE[33030]: [/COLOR]][CR][COLOR=grey2]$LOCALIZE[383]: [/COLOR]$INFO[Window.Property(Daily.1.WindSpeed)] $INFO[Window.Property(Daily.1.WindDirection)]</icon>
-                                               <onclick>-</onclick>
+                                               <onclick>noop</onclick>
                                                <visible>!IsEmpty(Window.Property(Daily.IsFetched))</visible>
                                        </item>
                                        <item>
                                                <label2>$INFO[Window.Property(Daily.2.HighTemperature),[COLOR=grey2]$LOCALIZE[419] :[/COLOR][B] ,[/B]]  $INFO[Window.Property(Daily.2.LowTemperature),[COLOR=grey2]$LOCALIZE[418] :[/COLOR][B] ,[/B]][CR]$INFO[Window.Property(Daily.2.Precipitation),[COLOR=grey2]$LOCALIZE[33022] :[/COLOR][B] ,[/B]]</label2>
                                                <thumb>$INFO[Window.Property(Daily.2.OutlookIcon)]</thumb>
                                                <icon>$INFO[Window.Property(Daily.2.Outlook),[COLOR=grey2]$LOCALIZE[33030]: [/COLOR]][CR][COLOR=grey2]$LOCALIZE[383]: [/COLOR]$INFO[Window.Property(Daily.2.WindSpeed)] $INFO[Window.Property(Daily.2.WindDirection)]</icon>
-                                               <onclick>-</onclick>
+                                               <onclick>noop</onclick>
                                                <visible>!IsEmpty(Window.Property(Daily.IsFetched))</visible>
                                        </item>
                                        <item>
                                                <label2>$INFO[Window.Property(Daily.3.HighTemperature),[COLOR=grey2]$LOCALIZE[419] :[/COLOR][B] ,[/B]]  $INFO[Window.Property(Daily.3.LowTemperature),[COLOR=grey2]$LOCALIZE[418] :[/COLOR][B] ,[/B]][CR]$INFO[Window.Property(Daily.3.Precipitation),[COLOR=grey2]$LOCALIZE[33022] :[/COLOR][B] ,[/B]]</label2>
                                                <thumb>$INFO[Window.Property(Daily.3.OutlookIcon)]</thumb>
                                                <icon>$INFO[Window.Property(Daily.3.Outlook),[COLOR=grey2]$LOCALIZE[33030]: [/COLOR]][CR][COLOR=grey2]$LOCALIZE[383]: [/COLOR]$INFO[Window.Property(Daily.3.WindSpeed)] $INFO[Window.Property(Daily.3.WindDirection)]</icon>
-                                               <onclick>-</onclick>
+                                               <onclick>noop</onclick>
                                                <visible>!IsEmpty(Window.Property(Daily.IsFetched))</visible>
                                        </item>
                                        <item>
                                                <label2>$INFO[Window.Property(Daily.4.HighTemperature),[COLOR=grey2]$LOCALIZE[419] :[/COLOR][B] ,[/B]]  $INFO[Window.Property(Daily.4.LowTemperature),[COLOR=grey2]$LOCALIZE[418] :[/COLOR][B] ,[/B]][CR]$INFO[Window.Property(Daily.4.Precipitation),[COLOR=grey2]$LOCALIZE[33022] :[/COLOR][B] ,[/B]]</label2>
                                                <thumb>$INFO[Window.Property(Daily.4.OutlookIcon)]</thumb>
                                                <icon>$INFO[Window.Property(Daily.4.Outlook),[COLOR=grey2]$LOCALIZE[33030]: [/COLOR]][CR][COLOR=grey2]$LOCALIZE[383]: [/COLOR]$INFO[Window.Property(Daily.4.WindSpeed)] $INFO[Window.Property(Daily.4.WindDirection)]</icon>
-                                               <onclick>-</onclick>
+                                               <onclick>noop</onclick>
                                                <visible>!IsEmpty(Window.Property(Daily.IsFetched))</visible>
                                        </item>
                                        <item>
                                                <label2>$INFO[Window.Property(Daily.5.HighTemperature),[COLOR=grey2]$LOCALIZE[419] :[/COLOR][B] ,[/B]]  $INFO[Window.Property(Daily.5.LowTemperature),[COLOR=grey2]$LOCALIZE[418] :[/COLOR][B] ,[/B]][CR]$INFO[Window.Property(Daily.5.Precipitation),[COLOR=grey2]$LOCALIZE[33022] :[/COLOR][B] ,[/B]]</label2>
                                                <thumb>$INFO[Window.Property(Daily.5.OutlookIcon)]</thumb>
                                                <icon>$INFO[Window.Property(Daily.5.Outlook),[COLOR=grey2]$LOCALIZE[33030]: [/COLOR]][CR][COLOR=grey2]$LOCALIZE[383]: [/COLOR]$INFO[Window.Property(Daily.5.WindSpeed)] $INFO[Window.Property(Daily.5.WindDirection)]</icon>
-                                               <onclick>-</onclick>
+                                               <onclick>noop</onclick>
                                                <visible>!IsEmpty(Window.Property(Daily.IsFetched))</visible>
                                        </item>
                                        <item>
                                                <label2>$INFO[Window.Property(Daily.6.HighTemperature),[COLOR=grey2]$LOCALIZE[419] :[/COLOR][B] ,[/B]]  $INFO[Window.Property(Daily.6.LowTemperature),[COLOR=grey2]$LOCALIZE[418] :[/COLOR][B] ,[/B]][CR]$INFO[Window.Property(Daily.6.Precipitation),[COLOR=grey2]$LOCALIZE[33022] :[/COLOR][B] ,[/B]]</label2>
                                                <thumb>$INFO[Window.Property(Daily.6.OutlookIcon)]</thumb>
                                                <icon>$INFO[Window.Property(Daily.6.Outlook),[COLOR=grey2]$LOCALIZE[33030]: [/COLOR]][CR][COLOR=grey2]$LOCALIZE[383]: [/COLOR]$INFO[Window.Property(Daily.6.WindSpeed)] $INFO[Window.Property(Daily.6.WindDirection)]</icon>
-                                               <onclick>-</onclick>
+                                               <onclick>noop</onclick>
                                                <visible>!IsEmpty(Window.Property(Daily.IsFetched))</visible>
                                        </item>
                                        <item>
                                                <label2>$INFO[Window.Property(Daily.7.HighTemperature),[COLOR=grey2]$LOCALIZE[419] :[/COLOR][B] ,[/B]]  $INFO[Window.Property(Daily.7.LowTemperature),[COLOR=grey2]$LOCALIZE[418] :[/COLOR][B] ,[/B]][CR]$INFO[Window.Property(Daily.7.Precipitation),[COLOR=grey2]$LOCALIZE[33022] :[/COLOR][B] ,[/B]]</label2>
                                                <thumb>$INFO[Window.Property(Daily.7.OutlookIcon)]</thumb>
                                                <icon>$INFO[Window.Property(Daily.7.Outlook),[COLOR=grey2]$LOCALIZE[33030]: [/COLOR]][CR][COLOR=grey2]$LOCALIZE[383]: [/COLOR]$INFO[Window.Property(Daily.7.WindSpeed)] $INFO[Window.Property(Daily.7.WindDirection)]</icon>
-                                               <onclick>-</onclick>
+                                               <onclick>noop</onclick>
                                                <visible>!IsEmpty(Window.Property(Daily.IsFetched))</visible>
                                        </item>
                                        <item>
                                                <label2>$INFO[Window.Property(Daily.8.HighTemperature),[COLOR=grey2]$LOCALIZE[419] :[/COLOR][B] ,[/B]]  $INFO[Window.Property(Daily.8.LowTemperature),[COLOR=grey2]$LOCALIZE[418] :[/COLOR][B] ,[/B]][CR]$INFO[Window.Property(Daily.8.Precipitation),[COLOR=grey2]$LOCALIZE[33022] :[/COLOR][B] ,[/B]]</label2>
                                                <thumb>$INFO[Window.Property(Daily.8.OutlookIcon)]</thumb>
                                                <icon>$INFO[Window.Property(Daily.8.Outlook),[COLOR=grey2]$LOCALIZE[33030]: [/COLOR]][CR][COLOR=grey2]$LOCALIZE[383]: [/COLOR]$INFO[Window.Property(Daily.8.WindSpeed)] $INFO[Window.Property(Daily.8.WindDirection)]</icon>
-                                               <onclick>-</onclick>
+                                               <onclick>noop</onclick>
                                                <visible>!IsEmpty(Window.Property(Daily.IsFetched))</visible>
                                        </item>
                                        <item>
                                                <label2>$INFO[Window.Property(Daily.9.HighTemperature),[COLOR=grey2]$LOCALIZE[419] :[/COLOR][B] ,[/B]]  $INFO[Window.Property(Daily.9.LowTemperature),[COLOR=grey2]$LOCALIZE[418] :[/COLOR][B] ,[/B]][CR]$INFO[Window.Property(Daily.9.Precipitation),[COLOR=grey2]$LOCALIZE[33022] :[/COLOR][B] ,[/B]]</label2>
                                                <thumb>$INFO[Window.Property(Daily.9.OutlookIcon)]</thumb>
                                                <icon>$INFO[Window.Property(Daily.9.Outlook),[COLOR=grey2]$LOCALIZE[33030]: [/COLOR]][CR][COLOR=grey2]$LOCALIZE[383]: [/COLOR]$INFO[Window.Property(Daily.9.WindSpeed)] $INFO[Window.Property(Daily.9.WindDirection)]</icon>
-                                               <onclick>-</onclick>
+                                               <onclick>noop</onclick>
                                                <visible>!IsEmpty(Window.Property(Daily.IsFetched))</visible>
                                        </item>
                                        <item>
                                                <label2>$INFO[Window.Property(Daily.10.HighTemperature),[COLOR=grey2]$LOCALIZE[419] :[/COLOR][B] ,[/B]]  $INFO[Window.Property(Daily.10.LowTemperature),[COLOR=grey2]$LOCALIZE[418] :[/COLOR][B] ,[/B]][CR]$INFO[Window.Property(Daily.10.Precipitation),[COLOR=grey2]$LOCALIZE[33022] :[/COLOR][B] ,[/B]]</label2>
                                                <thumb>$INFO[Window.Property(Daily.10.OutlookIcon)]</thumb>
                                                <icon>$INFO[Window.Property(Daily.10.Outlook),[COLOR=grey2]$LOCALIZE[33030]: [/COLOR]][CR][COLOR=grey2]$LOCALIZE[383]: [/COLOR]$INFO[Window.Property(Daily.10.WindSpeed)] $INFO[Window.Property(Daily.10.WindDirection)]</icon>
-                                               <onclick>-</onclick>
+                                               <onclick>noop</onclick>
                                                <visible>!IsEmpty(Window.Property(Daily.IsFetched))</visible>
                                        </item>
                                </content>
index b2b367f..c8c6cbb 100644 (file)
                                <content>
                                        <item>
                                                <icon>$LOCALIZE[31909]</icon>
-                                               <onclick>-</onclick>
+                                               <onclick>noop</onclick>
                                                <visible>IsEmpty(Window.Property(Hourly.IsFetched))</visible>
                                        </item>
                                        <item>
                                                <label2>$INFO[Window.Property(Hourly.1.Temperature),[COLOR=grey2]$LOCALIZE[419] :[/COLOR][B] ,[/B]]  $INFO[Window.Property(Hourly.1.FeelsLike),[COLOR=grey2]$LOCALIZE[402] :[/COLOR][B] ,[/B]][CR]$INFO[Window.Property(Hourly.1.Humidity),[COLOR=grey2]$LOCALIZE[406] :[/COLOR][B] ,[/B]][CR]$INFO[Window.Property(Hourly.1.ChancePrecipitation),[COLOR=grey2]$LOCALIZE[31908] :[/COLOR][B] ,[/B]]</label2>
                                                <thumb>$INFO[Window.Property(Hourly.1.OutlookIcon)]</thumb>
                                                <icon>$INFO[Window.Property(Hourly.1.Outlook),[COLOR=grey2]$LOCALIZE[33030]: [/COLOR]][CR][COLOR=grey2]$LOCALIZE[383]: [/COLOR]$INFO[Window.Property(Hourly.1.WindSpeed)] $INFO[Window.Property(Hourly.1.WindDirection)]</icon>
-                                               <onclick>-</onclick>
+                                               <onclick>noop</onclick>
                                                <visible>!IsEmpty(Window.Property(Hourly.IsFetched))</visible>
                                        </item>
                                        <item>
                                                <label2>$INFO[Window.Property(Hourly.2.Temperature),[COLOR=grey2]$LOCALIZE[419] :[/COLOR][B] ,[/B]]  $INFO[Window.Property(Hourly.2.FeelsLike),[COLOR=grey2]$LOCALIZE[402] :[/COLOR][B] ,[/B]][CR]$INFO[Window.Property(Hourly.2.Humidity),[COLOR=grey2]$LOCALIZE[406] :[/COLOR][B] ,[/B]][CR]$INFO[Window.Property(Hourly.2.ChancePrecipitation),[COLOR=grey2]$LOCALIZE[31908] :[/COLOR][B] ,[/B]]</label2>
                                                <thumb>$INFO[Window.Property(Hourly.2.OutlookIcon)]</thumb>
                                                <icon>$INFO[Window.Property(Hourly.2.Outlook),[COLOR=grey2]$LOCALIZE[33030]: [/COLOR]][CR][COLOR=grey2]$LOCALIZE[383]: [/COLOR]$INFO[Window.Property(Hourly.2.WindSpeed)] $INFO[Window.Property(Hourly.2.WindDirection)]</icon>
-                                               <onclick>-</onclick>
+                                               <onclick>noop</onclick>
                                                <visible>!IsEmpty(Window.Property(Hourly.IsFetched))</visible>
                                        </item>
                                        <item>
                                                <label2>$INFO[Window.Property(Hourly.3.Temperature),[COLOR=grey2]$LOCALIZE[419] :[/COLOR][B] ,[/B]]  $INFO[Window.Property(Hourly.3.FeelsLike),[COLOR=grey2]$LOCALIZE[402] :[/COLOR][B] ,[/B]][CR]$INFO[Window.Property(Hourly.3.Humidity),[COLOR=grey2]$LOCALIZE[406] :[/COLOR][B] ,[/B]][CR]$INFO[Window.Property(Hourly.3.ChancePrecipitation),[COLOR=grey2]$LOCALIZE[31908] :[/COLOR][B] ,[/B]]</label2>
                                                <thumb>$INFO[Window.Property(Hourly.3.OutlookIcon)]</thumb>
                                                <icon>$INFO[Window.Property(Hourly.3.Outlook),[COLOR=grey2]$LOCALIZE[33030]: [/COLOR]][CR][COLOR=grey2]$LOCALIZE[383]: [/COLOR]$INFO[Window.Property(Hourly.3.WindSpeed)] $INFO[Window.Property(Hourly.3.WindDirection)]</icon>
-                                               <onclick>-</onclick>
+                                               <onclick>noop</onclick>
                                                <visible>!IsEmpty(Window.Property(Hourly.IsFetched))</visible>
                                        </item>
                                        <item>
                                                <label2>$INFO[Window.Property(Hourly.4.Temperature),[COLOR=grey2]$LOCALIZE[419] :[/COLOR][B] ,[/B]]  $INFO[Window.Property(Hourly.4.FeelsLike),[COLOR=grey2]$LOCALIZE[402] :[/COLOR][B] ,[/B]][CR]$INFO[Window.Property(Hourly.4.Humidity),[COLOR=grey2]$LOCALIZE[406] :[/COLOR][B] ,[/B]][CR]$INFO[Window.Property(Hourly.4.ChancePrecipitation),[COLOR=grey2]$LOCALIZE[31908] :[/COLOR][B] ,[/B]]</label2>
                                                <thumb>$INFO[Window.Property(Hourly.4.OutlookIcon)]</thumb>
                                                <icon>$INFO[Window.Property(Hourly.4.Outlook),[COLOR=grey2]$LOCALIZE[33030]: [/COLOR]][CR][COLOR=grey2]$LOCALIZE[383]: [/COLOR]$INFO[Window.Property(Hourly.4.WindSpeed)] $INFO[Window.Property(Hourly.4.WindDirection)]</icon>
-                                               <onclick>-</onclick>
+                                               <onclick>noop</onclick>
                                                <visible>!IsEmpty(Window.Property(Hourly.IsFetched))</visible>
                                        </item>
                                        <item>
                                                <label2>$INFO[Window.Property(Hourly.5.Temperature),[COLOR=grey2]$LOCALIZE[419] :[/COLOR][B] ,[/B]]  $INFO[Window.Property(Hourly.5.FeelsLike),[COLOR=grey2]$LOCALIZE[402] :[/COLOR][B] ,[/B]][CR]$INFO[Window.Property(Hourly.5.Humidity),[COLOR=grey2]$LOCALIZE[406] :[/COLOR][B] ,[/B]][CR]$INFO[Window.Property(Hourly.5.ChancePrecipitation),[COLOR=grey2]$LOCALIZE[31908] :[/COLOR][B] ,[/B]]</label2>
                                                <thumb>$INFO[Window.Property(Hourly.5.OutlookIcon)]</thumb>
                                                <icon>$INFO[Window.Property(Hourly.5.Outlook),[COLOR=grey2]$LOCALIZE[33030]: [/COLOR]][CR][COLOR=grey2]$LOCALIZE[383]: [/COLOR]$INFO[Window.Property(Hourly.5.WindSpeed)] $INFO[Window.Property(Hourly.5.WindDirection)]</icon>
-                                               <onclick>-</onclick>
+                                               <onclick>noop</onclick>
                                                <visible>!IsEmpty(Window.Property(Hourly.IsFetched))</visible>
                                        </item>
                                        <item>
                                                <label2>$INFO[Window.Property(Hourly.6.Temperature),[COLOR=grey2]$LOCALIZE[419] :[/COLOR][B] ,[/B]]  $INFO[Window.Property(Hourly.6.FeelsLike),[COLOR=grey2]$LOCALIZE[402] :[/COLOR][B] ,[/B]][CR]$INFO[Window.Property(Hourly.6.Humidity),[COLOR=grey2]$LOCALIZE[406] :[/COLOR][B] ,[/B]][CR]$INFO[Window.Property(Hourly.6.ChancePrecipitation),[COLOR=grey2]$LOCALIZE[31908] :[/COLOR][B] ,[/B]]</label2>
                                                <thumb>$INFO[Window.Property(Hourly.6.OutlookIcon)]</thumb>
                                                <icon>$INFO[Window.Property(Hourly.6.Outlook),[COLOR=grey2]$LOCALIZE[33030]: [/COLOR]][CR][COLOR=grey2]$LOCALIZE[383]: [/COLOR]$INFO[Window.Property(Hourly.6.WindSpeed)] $INFO[Window.Property(Hourly.6.WindDirection)]</icon>
-                                               <onclick>-</onclick>
+                                               <onclick>noop</onclick>
                                                <visible>!IsEmpty(Window.Property(Hourly.IsFetched))</visible>
                                        </item>
                                        <item>
                                                <label2>$INFO[Window.Property(Hourly.7.Temperature),[COLOR=grey2]$LOCALIZE[419] :[/COLOR][B] ,[/B]]  $INFO[Window.Property(Hourly.7.FeelsLike),[COLOR=grey2]$LOCALIZE[402] :[/COLOR][B] ,[/B]][CR]$INFO[Window.Property(Hourly.7.Humidity),[COLOR=grey2]$LOCALIZE[406] :[/COLOR][B] ,[/B]][CR]$INFO[Window.Property(Hourly.7.ChancePrecipitation),[COLOR=grey2]$LOCALIZE[31908] :[/COLOR][B] ,[/B]]</label2>
                                                <thumb>$INFO[Window.Property(Hourly.7.OutlookIcon)]</thumb>
                                                <icon>$INFO[Window.Property(Hourly.7.Outlook),[COLOR=grey2]$LOCALIZE[33030]: [/COLOR]][CR][COLOR=grey2]$LOCALIZE[383]: [/COLOR]$INFO[Window.Property(Hourly.7.WindSpeed)] $INFO[Window.Property(Hourly.7.WindDirection)]</icon>
-                                               <onclick>-</onclick>
+                                               <onclick>noop</onclick>
                                                <visible>!IsEmpty(Window.Property(Hourly.IsFetched))</visible>
                                        </item>
                                        <item>
                                                <label2>$INFO[Window.Property(Hourly.8.Temperature),[COLOR=grey2]$LOCALIZE[419] :[/COLOR][B] ,[/B]]  $INFO[Window.Property(Hourly.8.FeelsLike),[COLOR=grey2]$LOCALIZE[402] :[/COLOR][B] ,[/B]][CR]$INFO[Window.Property(Hourly.8.Humidity),[COLOR=grey2]$LOCALIZE[406] :[/COLOR][B] ,[/B]][CR]$INFO[Window.Property(Hourly.8.ChancePrecipitation),[COLOR=grey2]$LOCALIZE[31908] :[/COLOR][B] ,[/B]]</label2>
                                                <thumb>$INFO[Window.Property(Hourly.8.OutlookIcon)]</thumb>
                                                <icon>$INFO[Window.Property(Hourly.8.Outlook),[COLOR=grey2]$LOCALIZE[33030]: [/COLOR]][CR][COLOR=grey2]$LOCALIZE[383]: [/COLOR]$INFO[Window.Property(Hourly.8.WindSpeed)] $INFO[Window.Property(Hourly.8.WindDirection)]</icon>
-                                               <onclick>-</onclick>
+                                               <onclick>noop</onclick>
                                                <visible>!IsEmpty(Window.Property(Hourly.IsFetched))</visible>
                                        </item>
                                        <item>
                                                <label2>$INFO[Window.Property(Hourly.9.Temperature),[COLOR=grey2]$LOCALIZE[419] :[/COLOR][B] ,[/B]]  $INFO[Window.Property(Hourly.9.FeelsLike),[COLOR=grey2]$LOCALIZE[402] :[/COLOR][B] ,[/B]][CR]$INFO[Window.Property(Hourly.9.Humidity),[COLOR=grey2]$LOCALIZE[406] :[/COLOR][B] ,[/B]][CR]$INFO[Window.Property(Hourly.9.ChancePrecipitation),[COLOR=grey2]$LOCALIZE[31908] :[/COLOR][B] ,[/B]]</label2>
                                                <thumb>$INFO[Window.Property(Hourly.9.OutlookIcon)]</thumb>
                                                <icon>$INFO[Window.Property(Hourly.9.Outlook),[COLOR=grey2]$LOCALIZE[33030]: [/COLOR]][CR][COLOR=grey2]$LOCALIZE[383]: [/COLOR]$INFO[Window.Property(Hourly.9.WindSpeed)] $INFO[Window.Property(Hourly.9.WindDirection)]</icon>
-                                               <onclick>-</onclick>
+                                               <onclick>noop</onclick>
                                                <visible>!IsEmpty(Window.Property(Hourly.IsFetched))</visible>
                                        </item>
                                        <item>
                                                <label2>$INFO[Window.Property(Hourly.10.Temperature),[COLOR=grey2]$LOCALIZE[419] :[/COLOR][B] ,[/B]]  $INFO[Window.Property(Hourly.10.FeelsLike),[COLOR=grey2]$LOCALIZE[402] :[/COLOR][B] ,[/B]][CR]$INFO[Window.Property(Hourly.10.Humidity),[COLOR=grey2]$LOCALIZE[406] :[/COLOR][B] ,[/B]][CR]$INFO[Window.Property(Hourly.10.ChancePrecipitation),[COLOR=grey2]$LOCALIZE[31908] :[/COLOR][B] ,[/B]]</label2>
                                                <thumb>$INFO[Window.Property(Hourly.10.OutlookIcon)]</thumb>
                                                <icon>$INFO[Window.Property(Hourly.10.Outlook),[COLOR=grey2]$LOCALIZE[33030]: [/COLOR]][CR][COLOR=grey2]$LOCALIZE[383]: [/COLOR]$INFO[Window.Property(Hourly.10.WindSpeed)] $INFO[Window.Property(Hourly.10.WindDirection)]</icon>
-                                               <onclick>-</onclick>
+                                               <onclick>noop</onclick>
                                                <visible>!IsEmpty(Window.Property(Hourly.IsFetched))</visible>
                                        </item>
                                        <item>
                                                <label2>$INFO[Window.Property(Hourly.11.Temperature),[COLOR=grey2]$LOCALIZE[419] :[/COLOR][B] ,[/B]]  $INFO[Window.Property(Hourly.11.FeelsLike),[COLOR=grey2]$LOCALIZE[402] :[/COLOR][B] ,[/B]][CR]$INFO[Window.Property(Hourly.11.Humidity),[COLOR=grey2]$LOCALIZE[406] :[/COLOR][B] ,[/B]][CR]$INFO[Window.Property(Hourly.11.ChancePrecipitation),[COLOR=grey2]$LOCALIZE[31908] :[/COLOR][B] ,[/B]]</label2>
                                                <thumb>$INFO[Window.Property(Hourly.11.OutlookIcon)]</thumb>
                                                <icon>$INFO[Window.Property(Hourly.11.Outlook),[COLOR=grey2]$LOCALIZE[33030]: [/COLOR]][CR][COLOR=grey2]$LOCALIZE[383]: [/COLOR]$INFO[Window.Property(Hourly.11.WindSpeed)] $INFO[Window.Property(Hourly.11.WindDirection)]</icon>
-                                               <onclick>-</onclick>
+                                               <onclick>noop</onclick>
                                                <visible>!IsEmpty(Window.Property(Hourly.IsFetched))</visible>
                                        </item>
                                        <item>
                                                <label2>$INFO[Window.Property(Hourly.12.Temperature),[COLOR=grey2]$LOCALIZE[419] :[/COLOR][B] ,[/B]]  $INFO[Window.Property(Hourly.12.FeelsLike),[COLOR=grey2]$LOCALIZE[402] :[/COLOR][B] ,[/B]][CR]$INFO[Window.Property(Hourly.12.Humidity),[COLOR=grey2]$LOCALIZE[406] :[/COLOR][B] ,[/B]][CR]$INFO[Window.Property(Hourly.12.ChancePrecipitation),[COLOR=grey2]$LOCALIZE[31908] :[/COLOR][B] ,[/B]]</label2>
                                                <thumb>$INFO[Window.Property(Hourly.12.OutlookIcon)]</thumb>
                                                <icon>$INFO[Window.Property(Hourly.12.Outlook),[COLOR=grey2]$LOCALIZE[33030]: [/COLOR]][CR][COLOR=grey2]$LOCALIZE[383]: [/COLOR]$INFO[Window.Property(Hourly.12.WindSpeed)] $INFO[Window.Property(Hourly.12.WindDirection)]</icon>
-                                               <onclick>-</onclick>
+                                               <onclick>noop</onclick>
                                                <visible>!IsEmpty(Window.Property(Hourly.IsFetched))</visible>
                                        </item>
                                </content>
diff --git a/addons/visualization.fishbmc/LICENSE b/addons/visualization.fishbmc/LICENSE
new file mode 100644 (file)
index 0000000..67594b4
--- /dev/null
@@ -0,0 +1,282 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+
diff --git a/addons/visualization.fishbmc/addon.xml b/addons/visualization.fishbmc/addon.xml
new file mode 100644 (file)
index 0000000..0b877a3
--- /dev/null
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<addon
+  id="visualization.fishbmc"
+  version="4.0.1"
+  name="FishBMC"
+  provider-name="26elf">
+  <extension
+    point="xbmc.player.musicviz"
+    library_linux="fishbmc.vis"
+    library_osx="fishbmc.vis"/>
+  <extension point="xbmc.addon.metadata">
+    <summary lang="en">Visualisation showing Waves and Blur Effects</summary>
+    <description lang="en">fishBMC is based on fische, a standalone sound visualisation tool. The basic principle is: draw the waveform and smear the drawing along predefined vectors. However fische also incorporates advanced beat detection, which really guarantees a great visual experience.</description>
+    <disclaimer>If this breaks anything, the pieces remain yours.</disclaimer>
+    <platform>linux osx</platform>
+  </extension>
+</addon>
diff --git a/addons/visualization.fishbmc/changelog.txt b/addons/visualization.fishbmc/changelog.txt
new file mode 100644 (file)
index 0000000..4e00936
--- /dev/null
@@ -0,0 +1,3 @@
+2011-02-26:
+       Initial release for XBMC 11, based on fische 4
+
diff --git a/addons/visualization.fishbmc/icon.png b/addons/visualization.fishbmc/icon.png
new file mode 100644 (file)
index 0000000..f631341
Binary files /dev/null and b/addons/visualization.fishbmc/icon.png differ
diff --git a/addons/visualization.fishbmc/resources/language/English/strings.xml b/addons/visualization.fishbmc/resources/language/English/strings.xml
new file mode 100644 (file)
index 0000000..dee2f09
--- /dev/null
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<strings>
+    <!-- settings labels -->
+    <string id="30000">Detail [CPU intensive]</string>
+    <string id="30001">Low</string>
+    <string id="30002">Normal</string>
+    <string id="30003">High</string>
+    <string id="30004">Extreme</string>
+    <string id="30005">Nervous Mode [more mode changes]</string>
+    <string id="30006">Speed [skip some frames]</string>
+    <string id="30007">Very Low</string>
+    <string id="30008">Low</string>
+    <string id="30009">Normal</string>
+    <string id="30010">High</string>
+    <string id="30011">Use a Persistence File [faster startup]</string>
+</strings>
diff --git a/addons/visualization.fishbmc/resources/settings.xml b/addons/visualization.fishbmc/resources/settings.xml
new file mode 100644 (file)
index 0000000..7874b96
--- /dev/null
@@ -0,0 +1,6 @@
+<settings>
+<setting id="detail" label="30000" type="enum" lvalues="30001|30002|30003|30004" default="2"/>
+<setting id="divisor" label="30006" type="enum" lvalues="30007|30008|30009|30010" default="2"/>
+<setting id="nervous" label="30005" type="bool" default="false"/>
+<setting id="filemode" label="30011" type="bool" default="false"/>
+</settings>
index db32072..6a199bc 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<addon id="xbmc.addon" version="12.0.0" provider-name="Team XBMC">
+<addon id="xbmc.addon" version="12.9.1" provider-name="Team XBMC">
   <backwards-compatibility abi="12.0"/>
   <requires>
     <import addon="xbmc.core" version="0.1.0"/>
index cf84ebb..fb0a4c5 100644 (file)
@@ -2,7 +2,7 @@
 # Process this file with autoconf to produce a configure script.
 
 AC_PREREQ(2.59)
-AC_INIT([xbmc], [12.0rc3], [http://trac.xbmc.org])
+AC_INIT([xbmc], [12.9.1], [http://trac.xbmc.org])
 AC_CONFIG_HEADERS([xbmc/config.h])
 AH_TOP([#pragma once])
 m4_include([m4/ax_python_devel.m4])
@@ -2374,6 +2374,7 @@ OUTPUT_FILES="Makefile \
     xbmc/visualizations/XBMCProjectM/Makefile \
     xbmc/visualizations/Goom/Makefile \
     xbmc/visualizations/OpenGLSpectrum/Makefile \
+    xbmc/visualizations/fishBMC/Makefile \
     xbmc/visualizations/WaveForm/Makefile \
     lib/addons/library.xbmc.addon/Makefile \
     lib/addons/library.xbmc.gui/Makefile \
index b4a18d1..013c951 100644 (file)
Binary files a/media/Splash.png and b/media/Splash.png differ
index c76e648..2e64d05 100644 (file)
@@ -16,7 +16,7 @@
  
  char *ssh_get_user_home_dir(void) {
 +#if defined(__ANDROID__)
-+  return NULL;
++  return strdup(getenv("HOME"));
 +#else
    char *szPath = NULL;
    struct passwd pwd;
index dab566a..185245f 100644 (file)
@@ -2,8 +2,8 @@
 <!-- BEGIN_INCLUDE(manifest) -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="org.xbmc.xbmc"
-    android:versionCode="5"
-    android:versionName="12.0-RC3" >
+    android:versionCode="7"
+    android:versionName="13.0-ALPHA1" >
 
     <!-- This is the platform API where NativeActivity was introduced. -->
     <uses-sdk android:minSdkVersion="9" />
index f9da109..44a98cf 100755 (executable)
@@ -44,8 +44,8 @@ fi
 
 PACKAGE=org.xbmc.xbmc-atv2
 
-VERSION=12.0
-REVISION=0~rc3
+VERSION=13.0
+REVISION=0~alpha1
 ARCHIVE=${PACKAGE}_${VERSION}-${REVISION}_iphoneos-arm.deb
 
 echo Creating $PACKAGE package version $VERSION revision $REVISION
index 8da52e0..4829275 100755 (executable)
@@ -45,8 +45,8 @@ fi
 
 PACKAGE=org.xbmc.xbmc-ios
 
-VERSION=12.0
-REVISION=0~rc3
+VERSION=13.0
+REVISION=0~alpha1
 ARCHIVE=${PACKAGE}_${VERSION}-${REVISION}_iphoneos-arm.deb
 
 echo Creating $PACKAGE package version $VERSION revision $REVISION
index fbd72f0..8956542 100644 (file)
@@ -502,9 +502,9 @@ namespace INFO
 #define CONTROL_GROUP_HAS_FOCUS     29999
 #define CONTROL_HAS_FOCUS           30000
 
-#define VERSION_MAJOR 12
+#define VERSION_MAJOR 13
 #define VERSION_MINOR 0
-#define VERSION_TAG "-RC3"
+#define VERSION_TAG "-ALPHA1"
 
 #define LISTITEM_START              35000
 #define LISTITEM_THUMB              (LISTITEM_START)
index 9215fd9..45e10fe 100644 (file)
 #define OMX_MPEG2V_DECODER      OMX_VIDEO_DECODER
 #define OMX_VC1_DECODER         OMX_VIDEO_DECODER
 #define OMX_WMV3_DECODER        OMX_VIDEO_DECODER
+#define OMX_VP6_DECODER         OMX_VIDEO_DECODER
 #define OMX_VP8_DECODER         OMX_VIDEO_DECODER
+#define OMX_THEORA_DECODER      OMX_VIDEO_DECODER
+#define OMX_MJPEG_DECODER       OMX_VIDEO_DECODER
 
 #define MAX_TEXT_LENGTH 1024
 
@@ -145,6 +148,7 @@ bool COMXVideo::NaluFormatStartCodes(enum CodecID codec, uint8_t *in_extradata,
 
 bool COMXVideo::Open(CDVDStreamInfo &hints, OMXClock *clock, bool deinterlace, bool hdmi_clock_sync)
 {
+  bool vflip = false;
   Close();
 
   OMX_ERRORTYPE omx_err   = OMX_ErrorNone;
@@ -248,6 +252,18 @@ bool COMXVideo::Open(CDVDStreamInfo &hints, OMXClock *clock, bool deinterlace, b
       m_codingType = OMX_VIDEO_CodingMPEG4;
       m_video_codec_name = "omx-h263";
       break;
+    case CODEC_ID_VP6:
+      // this form is encoded upside down
+      vflip = true;
+      // fall through
+    case CODEC_ID_VP6F:
+    case CODEC_ID_VP6A:
+      // (role name) video_decoder.vp6
+      // VP6
+      decoder_name = OMX_VP6_DECODER;
+      m_codingType = OMX_VIDEO_CodingVP6;
+      m_video_codec_name = "omx-vp6";
+    break;
     case CODEC_ID_VP8:
       // (role name) video_decoder.vp8
       // VP8
@@ -255,6 +271,21 @@ bool COMXVideo::Open(CDVDStreamInfo &hints, OMXClock *clock, bool deinterlace, b
       m_codingType = OMX_VIDEO_CodingVP8;
       m_video_codec_name = "omx-vp8";
     break;
+    case CODEC_ID_THEORA:
+      // (role name) video_decoder.theora
+      // theora
+      decoder_name = OMX_THEORA_DECODER;
+      m_codingType = OMX_VIDEO_CodingTheora;
+      m_video_codec_name = "omx-theora";
+    break;
+    case CODEC_ID_MJPEG:
+    case CODEC_ID_MJPEGB:
+      // (role name) video_decoder.mjpg
+      // mjpg
+      decoder_name = OMX_MJPEG_DECODER;
+      m_codingType = OMX_VIDEO_CodingMJPEG;
+      m_video_codec_name = "omx-mjpeg";
+    break;
     case CODEC_ID_VC1:
     case CODEC_ID_WMV3:
       // (role name) video_decoder.vc1
@@ -594,6 +625,8 @@ bool COMXVideo::Open(CDVDStreamInfo &hints, OMXClock *clock, bool deinterlace, b
       configDisplay.transform = OMX_DISPLAY_ROT0;
       break;
   }
+  if (vflip)
+      configDisplay.transform = OMX_DISPLAY_MIRROR_ROT180;
 
   omx_err = m_omx_render.SetConfig(OMX_IndexConfigDisplayRegion, &configDisplay);
   if(omx_err != OMX_ErrorNone)
index 5a99843..fd4e1a7 100644 (file)
@@ -354,7 +354,15 @@ bool PAPlayer::QueueNextFileEx(const CFileItem &file, bool fadeIn/* = true */)
   si->m_playNextAtFrame = 0;
   si->m_playNextTriggered = false;
 
-  PrepareStream(si);
+  if (!PrepareStream(si))
+  {
+    CLog::Log(LOGINFO, "PAPlayer::QueueNextFileEx - Error preparing stream");
+    
+    si->m_decoder.Destroy();
+    delete si;
+    m_callback.OnQueueNextItem();
+    return false;
+  }
 
   /* add the stream to the list */
   CExclusiveLock lock(m_streamsLock);
index c7243ef..fd5f2a9 100644 (file)
@@ -40,6 +40,7 @@ CGUIRSSControl::CGUIRSSControl(int parentID, int controlID, float posX, float po
 
   m_pReader = NULL;
   m_rtl = false;
+  m_stopped = false;
   ControlType = GUICONTROL_RSS;
 }
 
@@ -52,6 +53,7 @@ CGUIRSSControl::CGUIRSSControl(const CGUIRSSControl &from)
   m_strRSSTags = from.m_strRSSTags;
   m_pReader = NULL;
   m_rtl = from.m_rtl;
+  m_stopped = from.m_stopped;
   ControlType = GUICONTROL_RSS;
 }
 
@@ -73,6 +75,16 @@ void CGUIRSSControl::SetUrls(const vector<string> &vecUrl, bool rtl)
     m_scrollInfo.pixelSpeed *= -1;
 }
 
+void CGUIRSSControl::OnFocus()
+{
+  m_stopped = true;
+}
+
+void CGUIRSSControl::OnUnFocus()
+{
+  m_stopped = false;
+}
+
 void CGUIRSSControl::SetIntervals(const vector<int>& vecIntervals)
 {
   m_vecIntervals = vecIntervals;
@@ -130,6 +142,12 @@ void CGUIRSSControl::Render()
       colors.push_back(m_label.textColor);
       colors.push_back(m_headlineColor);
       colors.push_back(m_channelColor);
+
+      if ( m_stopped )
+        m_scrollInfo.SetSpeed(0);
+      else
+        m_scrollInfo.SetSpeed(m_label.scrollSpeed);
+
       m_label.font->DrawScrollingText(m_posX, m_posY, colors, m_label.shadowColor, m_feed, 0, m_width, m_scrollInfo);
     }
 
index f5862bc..a8f19f9 100644 (file)
@@ -62,12 +62,15 @@ public:
   virtual void Render();
   virtual void OnFeedUpdate(const vecText &feed);
   virtual void OnFeedRelease();
-  virtual bool CanFocus() const { return false; };
+  virtual bool CanFocus() const { return true; };
   virtual CRect CalcRenderRegion() const;
 
   void SetIntervals(const std::vector<int>& vecIntervals);
   void SetUrls(const std::vector<std::string>& vecUrl, bool rtl);
 
+  virtual void OnFocus();
+  virtual void OnUnFocus();
+
 protected:
   virtual bool UpdateColors();
 
@@ -86,5 +89,6 @@ protected:
   std::vector<int> m_vecIntervals;
   bool m_rtl;
   CScrollInfo m_scrollInfo;
+  bool m_stopped;
 };
 #endif
index c546f64..d5b1f01 100644 (file)
@@ -40,6 +40,7 @@
 #include "utils/StringUtils.h"
 #include "TextureCache.h"
 #include "music/MusicThumbLoader.h"
+#include "filesystem/Directory.h"
 
 using namespace std;
 using namespace XFILE;
@@ -416,6 +417,7 @@ void CGUIDialogMusicInfo::OnGetThumb()
   CStdString result;
   bool flip=false;
   VECSOURCES sources(g_settings.m_musicSources);
+  AddItemPathToFileBrowserSources(sources, *m_albumItem);
   g_mediaManager.GetLocalDrives(sources);
   if (!CGUIDialogFileBrowser::ShowAndGetImage(items, sources, g_localizeStrings.Get(1030), result, &flip))
     return;   // user cancelled
@@ -578,3 +580,20 @@ CFileItemPtr CGUIDialogMusicInfo::GetCurrentListItem(int offset)
   return m_albumItem;
 }
 
+void CGUIDialogMusicInfo::AddItemPathToFileBrowserSources(VECSOURCES &sources, const CFileItem &item)
+{
+  CStdString itemDir;
+
+  if (item.HasMusicInfoTag() && item.GetMusicInfoTag()->GetType() == "song")
+    itemDir = URIUtils::GetParentPath(item.GetMusicInfoTag()->GetURL());
+  else
+    itemDir = item.GetPath();
+
+  if (!itemDir.IsEmpty() && CDirectory::Exists(itemDir))
+  {
+    CMediaSource itemSource;
+    itemSource.strName = g_localizeStrings.Get(36041);
+    itemSource.strPath = itemDir;
+    sources.push_back(itemSource);
+  }
+}
index 4bac7b3..b28720b 100644 (file)
@@ -24,6 +24,7 @@
 #include "music/Song.h"
 #include "music/Artist.h"
 #include "music/Album.h"
+#include "FileItem.h"
 
 class CFileItem;
 class CFileItemList;
@@ -44,6 +45,7 @@ public:
   virtual bool HasListItems() const { return true; };
   virtual CFileItemPtr GetCurrentListItem(int offset = 0);
   const CFileItemList& CurrentDirectory() const { return *m_albumSongs; };
+  static void AddItemPathToFileBrowserSources(VECSOURCES &sources, const CFileItem &item);
 protected:
   virtual void OnInitWindow();
   void Update();
index 8dbff8c..a2d8b11 100644 (file)
@@ -37,6 +37,8 @@
 #include "guilib/LocalizeStrings.h"
 #include "TextureCache.h"
 #include "music/Album.h"
+#include "storage/MediaManager.h"
+#include "GUIDialogMusicInfo.h"
 
 using namespace XFILE;
 
@@ -286,7 +288,10 @@ void CGUIDialogSongInfo::OnGetThumb()
   }
 
   CStdString result;
-  if (!CGUIDialogFileBrowser::ShowAndGetImage(items, g_settings.m_musicSources, g_localizeStrings.Get(1030), result))
+  VECSOURCES sources(g_settings.m_musicSources);
+  CGUIDialogMusicInfo::AddItemPathToFileBrowserSources(sources, *m_song);
+  g_mediaManager.GetLocalDrives(sources);
+  if (!CGUIDialogFileBrowser::ShowAndGetImage(items, sources, g_localizeStrings.Get(1030), result))
     return;   // user cancelled
 
   if (result == "thumb://Current")
index fd7f755..9ca61f3 100644 (file)
@@ -253,7 +253,15 @@ void CAirPlayServer::Process()
         newconnection.m_socket = accept(m_ServerSocket, &newconnection.m_cliaddr, &newconnection.m_addrlen);
 
         if (newconnection.m_socket == INVALID_SOCKET)
-          CLog::Log(LOGERROR, "AIRPLAY Server: Accept of new connection failed");
+        {
+          CLog::Log(LOGERROR, "AIRPLAY Server: Accept of new connection failed: %d", errno);
+          if (EBADF == errno)
+          {
+            Sleep(1000);
+            Initialize();
+            break;
+          }
+        }
         else
         {
           CLog::Log(LOGINFO, "AIRPLAY Server: New connection added");
index 1a2ab65..7ee73b1 100644 (file)
@@ -182,7 +182,15 @@ void CTCPServer::Process()
           newconnection->m_socket = accept(*it, (sockaddr*)&newconnection->m_cliaddr, &newconnection->m_addrlen);
 
           if (newconnection->m_socket == INVALID_SOCKET)
-            CLog::Log(LOGERROR, "JSONRPC Server: Accept of new connection failed");
+          {
+            CLog::Log(LOGERROR, "JSONRPC Server: Accept of new connection failed: %d", errno);
+            if (EBADF == errno)
+            {
+              Sleep(1000);
+              Initialize();
+              break;
+            }
+          }
           else
           {
             CLog::Log(LOGINFO, "JSONRPC Server: New connection added");
index b344525..b5dcda4 100644 (file)
@@ -9,7 +9,7 @@
        <key>CFBundleExecutable</key>
        <string>XBMC</string>
        <key>CFBundleGetInfoString</key>
-       <string>12.0.rc3</string>
+       <string>13.0.alpha1</string>
        <key>CFBundleIconFile</key>
        <string>xbmc.icns</string>
        <key>CFBundleIdentifier</key>
@@ -19,7 +19,7 @@
        <key>CFBundlePackageType</key>
        <string>APPL</string>
        <key>CFBundleShortVersionString</key>
-       <string>12.0.rc3</string>
+       <string>13.0.alpha1</string>
        <key>CFBundleVersion</key>
        <string>r####</string>
        <key>CFBundleSignature</key>
index 79cc3db..35d2923 100644 (file)
@@ -641,109 +641,111 @@ void CGUIDialogVideoInfo::OnGetArt()
   if (type.empty())
     return; // cancelled
 
+  // TODO: this can be removed once these are unified.
   if (type == "fanart")
-  { // TODO: this can be removed once these are unified.
     OnGetFanart();
-    return;
-  }
-
-  CFileItemList items;
-
-  // Current thumb
-  if (m_movieItem->HasArt(type))
-  {
-    CFileItemPtr item(new CFileItem("thumb://Current", false));
-    item->SetArt("thumb", m_movieItem->GetArt(type));
-    item->SetLabel(g_localizeStrings.Get(13512));
-    items.Add(item);
-  }
-  else if ((type == "poster" || type == "banner") && currentArt.find("thumb") != currentArt.end())
-  { // add the 'thumb' type in
-    CFileItemPtr item(new CFileItem("thumb://Thumb", false));
-    item->SetArt("thumb", currentArt["thumb"]);
-    item->SetLabel(g_localizeStrings.Get(13512));
-    items.Add(item);
-  }
-
-  // Grab the thumbnails from the web
-  vector<CStdString> thumbs;
-  int season = (m_movieItem->GetVideoInfoTag()->m_type == "season") ? m_movieItem->GetVideoInfoTag()->m_iSeason : -1;
-  m_movieItem->GetVideoInfoTag()->m_strPictureURL.GetThumbURLs(thumbs, type, season);
-
-  for (unsigned int i = 0; i < thumbs.size(); ++i)
+  else
   {
-    CStdString strItemPath;
-    strItemPath.Format("thumb://Remote%i", i);
-    CFileItemPtr item(new CFileItem(strItemPath, false));
-    item->SetArt("thumb", thumbs[i]);
-    item->SetIconImage("DefaultPicture.png");
-    item->SetLabel(g_localizeStrings.Get(13513));
+    CFileItemList items;
 
-    // TODO: Do we need to clear the cached image?
-    //    CTextureCache::Get().ClearCachedImage(thumb);
-    items.Add(item);
-  }
+    // Current thumb
+    if (m_movieItem->HasArt(type))
+    {
+      CFileItemPtr item(new CFileItem("thumb://Current", false));
+      item->SetArt("thumb", m_movieItem->GetArt(type));
+      item->SetLabel(g_localizeStrings.Get(13512));
+      items.Add(item);
+    }
+    else if ((type == "poster" || type == "banner") && currentArt.find("thumb") != currentArt.end())
+    { // add the 'thumb' type in
+      CFileItemPtr item(new CFileItem("thumb://Thumb", false));
+      item->SetArt("thumb", currentArt["thumb"]);
+      item->SetLabel(g_localizeStrings.Get(13512));
+      items.Add(item);
+    }
 
-  CStdString localThumb = CVideoThumbLoader::GetLocalArt(*m_movieItem, type);
-  if (!localThumb.empty())
-  {
-    CFileItemPtr item(new CFileItem("thumb://Local", false));
-    item->SetArt("thumb", localThumb);
-    item->SetLabel(g_localizeStrings.Get(13514));
-    items.Add(item);
-  }
-  else
-  { // no local thumb exists, so we are just using the IMDb thumb or cached thumb
-    // which is probably the IMDb thumb.  These could be wrong, so allow the user
-    // to delete the incorrect thumb
-    CFileItemPtr item(new CFileItem("thumb://None", false));
-    item->SetIconImage("DefaultVideo.png");
-    item->SetLabel(g_localizeStrings.Get(13515));
-    items.Add(item);
-  }
+    // Grab the thumbnails from the web
+    vector<CStdString> thumbs;
+    int season = (m_movieItem->GetVideoInfoTag()->m_type == "season") ? m_movieItem->GetVideoInfoTag()->m_iSeason : -1;
+    m_movieItem->GetVideoInfoTag()->m_strPictureURL.GetThumbURLs(thumbs, type, season);
 
-  CStdString result;
-  VECSOURCES sources(g_settings.m_videoSources);
-  AddItemPathToFileBrowserSources(sources, *m_movieItem);
-  g_mediaManager.GetLocalDrives(sources);
-  if (!CGUIDialogFileBrowser::ShowAndGetImage(items, sources, g_localizeStrings.Get(13511), result))
-    return;   // user cancelled
+    for (unsigned int i = 0; i < thumbs.size(); ++i)
+    {
+      CStdString strItemPath;
+      strItemPath.Format("thumb://Remote%i", i);
+      CFileItemPtr item(new CFileItem(strItemPath, false));
+      item->SetArt("thumb", thumbs[i]);
+      item->SetIconImage("DefaultPicture.png");
+      item->SetLabel(g_localizeStrings.Get(13513));
+
+      // TODO: Do we need to clear the cached image?
+      //    CTextureCache::Get().ClearCachedImage(thumb);
+      items.Add(item);
+    }
 
-  if (result == "thumb://Current")
-    return;   // user chose the one they have
+    CStdString localThumb = CVideoThumbLoader::GetLocalArt(*m_movieItem, type);
+    if (!localThumb.empty())
+    {
+      CFileItemPtr item(new CFileItem("thumb://Local", false));
+      item->SetArt("thumb", localThumb);
+      item->SetLabel(g_localizeStrings.Get(13514));
+      items.Add(item);
+    }
+    else
+    { // no local thumb exists, so we are just using the IMDb thumb or cached thumb
+      // which is probably the IMDb thumb.  These could be wrong, so allow the user
+      // to delete the incorrect thumb
+      CFileItemPtr item(new CFileItem("thumb://None", false));
+      item->SetIconImage("DefaultVideo.png");
+      item->SetLabel(g_localizeStrings.Get(13515));
+      items.Add(item);
+    }
 
-  CStdString newThumb;
-  if (result.Left(14) == "thumb://Remote")
-  {
-    int number = atoi(result.Mid(14));
-    newThumb = thumbs[number];
-  }
-  else if (result == "thumb://Thumb")
-    newThumb = currentArt["thumb"];
-  else if (result == "thumb://Local")
-    newThumb = localThumb;
-  else if (CFile::Exists(result))
-    newThumb = result;
-  else // none
-    newThumb.clear();
-
-  // update thumb in the database
-  CVideoDatabase db;
-  if (db.Open())
-  {
-    db.SetArtForItem(m_movieItem->GetVideoInfoTag()->m_iDbId, m_movieItem->GetVideoInfoTag()->m_type, type, newThumb);
-    db.Close();
-  }
-  CUtil::DeleteVideoDatabaseDirectoryCache(); // to get them new thumbs to show
-  m_movieItem->SetArt(type, newThumb);
-  if (m_movieItem->HasProperty("set_folder_thumb"))
-  { // have a folder thumb to set as well
-    VIDEO::CVideoInfoScanner::ApplyThumbToFolder(m_movieItem->GetProperty("set_folder_thumb").asString(), newThumb);
+    CStdString result;
+    VECSOURCES sources(g_settings.m_videoSources);
+    AddItemPathToFileBrowserSources(sources, *m_movieItem);
+    g_mediaManager.GetLocalDrives(sources);
+    if (CGUIDialogFileBrowser::ShowAndGetImage(items, sources, g_localizeStrings.Get(13511), result) &&
+        result != "thumb://Current") // user didn't choose the one they have
+    {
+      CStdString newThumb;
+      if (result.Left(14) == "thumb://Remote")
+      {
+        int number = atoi(result.Mid(14));
+        newThumb = thumbs[number];
+      }
+      else if (result == "thumb://Thumb")
+        newThumb = currentArt["thumb"];
+      else if (result == "thumb://Local")
+        newThumb = localThumb;
+      else if (CFile::Exists(result))
+        newThumb = result;
+      else // none
+        newThumb.clear();
+
+      // update thumb in the database
+      CVideoDatabase db;
+      if (db.Open())
+      {
+        db.SetArtForItem(m_movieItem->GetVideoInfoTag()->m_iDbId, m_movieItem->GetVideoInfoTag()->m_type, type, newThumb);
+        db.Close();
+      }
+      CUtil::DeleteVideoDatabaseDirectoryCache(); // to get them new thumbs to show
+      m_movieItem->SetArt(type, newThumb);
+      if (m_movieItem->HasProperty("set_folder_thumb"))
+      { // have a folder thumb to set as well
+        VIDEO::CVideoInfoScanner::ApplyThumbToFolder(m_movieItem->GetProperty("set_folder_thumb").asString(), newThumb);
+      }
+      m_hasUpdatedThumb = true;
+    }
   }
-  m_hasUpdatedThumb = true;
 
   // Update our screen
   Update();
+
+  // re-open the art selection dialog as we come back from
+  // the image selection dialog
+  OnGetArt();
 }
 
 // Allow user to select a Fanart
diff --git a/xbmc/visualizations/fishBMC/Makefile.in b/xbmc/visualizations/fishBMC/Makefile.in
new file mode 100644 (file)
index 0000000..0c2141e
--- /dev/null
@@ -0,0 +1,32 @@
+ARCH=@ARCH@
+CXXFLAGS=-fPIC
+
+SLIB = @abs_top_srcdir@/addons/visualization.fishbmc/fishbmc.vis
+OBJS = analyst.o \
+  audiobuffer.o \
+  blurengine.o \
+  cpudetect.o \
+  fische.o \
+  fishbmc_addon.o \
+  screenbuffer.o \
+  vector.o \
+  vectorfield.o \
+  wavepainter.o
+
+  DEFINES += -DHAS_SDL
+  DEFINES += -DHAS_SDL_OPENGL
+  ifeq ($(findstring osx,$(ARCH)), osx)
+    LDFLAGS += -framework OpenGL
+  else
+    LDFLAGS += -lGL
+  endif
+
+
+$(SLIB): $(OBJS)
+ifeq ($(findstring osx,$(ARCH)), osx)
+       $(CXX) $(CXXFLAGS) $(LDFLAGS) -bundle -o $(SLIB) $(OBJS)
+else
+       $(CXX) $(CXXFLAGS) $(LDFLAGS) -shared -o $(SLIB) $(OBJS)
+endif
+
+include @abs_top_srcdir@/Makefile.include
diff --git a/xbmc/visualizations/fishBMC/analyst.c b/xbmc/visualizations/fishBMC/analyst.c
new file mode 100644 (file)
index 0000000..483f202
--- /dev/null
@@ -0,0 +1,193 @@
+#include "fische_internal.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef DEBUG
+#include <stdio.h>
+#endif
+
+enum {_FISCHE__WAITING_, _FISCHE__MAYBEWAITING_, _FISCHE__BEAT_};
+
+int
+_fische__compare_int_fast16_t_ (void const* value1, void const* value2)
+{
+    return (* (int_fast16_t*) value1 - * (int_fast16_t*) value2);
+}
+
+double
+_fische__guess_frames_per_beat_ (uint_fast16_t* beat_gap_history)
+{
+    uint_fast16_t gap_history_sorted[30];
+
+    memcpy (gap_history_sorted, beat_gap_history, 30 * sizeof (uint_fast16_t));
+    qsort (gap_history_sorted, 30, sizeof (uint_fast16_t), _fische__compare_int_fast16_t_);
+
+    uint_fast16_t guess = gap_history_sorted[14];
+
+    double result = 0;
+    int count = 0;
+
+    uint_fast8_t i;
+    for (i = 0; i < 30; ++ i) {
+        if (abs (gap_history_sorted[i] - guess) <= 2) {
+            result += gap_history_sorted[i];
+            ++ count;
+        }
+    }
+
+    return result / count;
+}
+
+double
+_fische__get_audio_level_ (double* data, uint_fast32_t data_size)
+{
+    double E = 0;
+
+    uint_fast32_t i;
+    for (i = 0; i < data_size; ++ i) {
+        E += fabs (* (data + i));
+    }
+
+    if (E <= 0) E = 1e-9;
+    E /= data_size;
+
+    return log10 (E) * 10;
+}
+
+struct fische__analyst*
+fische__analyst_new (struct fische* parent) {
+
+    struct fische__analyst* retval = malloc (sizeof (struct fische__analyst));
+    retval->priv = malloc (sizeof (struct _fische__analyst_));
+
+    struct _fische__analyst_* P = retval->priv;
+
+    P->fische = parent;
+    P->bghist_head = 0;
+    P->intensity_moving_avg = 0;
+    P->intensity_std_dev = 0;
+    P->last_beat_frame = 0;
+    P->moving_avg_03 = 0;
+    P->moving_avg_30 = 0;
+    P->state = _FISCHE__WAITING_;
+    P->std_dev = 0;
+
+    P->beat_gap_history = malloc (30 * sizeof (uint_fast16_t));
+    memset (P->beat_gap_history, '\0', 30 * sizeof (uint_fast16_t));
+
+    retval->frames_per_beat = 0;
+    retval->relative_energy = 1;
+
+    return retval;
+}
+
+void
+fische__analyst_free (struct fische__analyst* self)
+{
+    if (!self)
+        return;
+
+    free (self->priv->beat_gap_history);
+    free (self->priv);
+    free (self);
+}
+
+int_fast8_t
+fische__analyst_analyse (struct fische__analyst* self,
+                         double* data,
+                         uint_fast16_t size)
+{
+    if (!size)
+        return -1;
+
+    struct _fische__analyst_* P = self->priv;
+
+    double dezibel = _fische__get_audio_level_ (data, size * 2);
+
+    if (P->moving_avg_30 == 0)
+        P->moving_avg_30 = dezibel;
+    else
+        P->moving_avg_30 = P->moving_avg_30 * 0.9667 + dezibel * 0.0333;
+
+    P->std_dev = P->std_dev * 0.9667 + fabs (dezibel - P->moving_avg_30) * 0.0333;
+
+    uint_fast32_t frameno = P->fische->frame_counter;
+    if ( (frameno - P->last_beat_frame) > 90) {
+        self->frames_per_beat = 0;
+        memset (P->beat_gap_history, '\0', 30 * sizeof (uint_fast16_t));
+        P->bghist_head = 0;
+    }
+
+    self->relative_energy = P->moving_avg_03 / P->moving_avg_30;
+
+    double relative_intensity = 0;
+    double new_frames_per_beat;
+
+    switch (P->state) {
+        case _FISCHE__WAITING_:
+            // don't bother if intensity too low
+            if (dezibel < P->moving_avg_30 + P->std_dev)
+                break;
+
+            // initialisation fallbacks
+            if (P->std_dev == 0)
+                relative_intensity = 1; // avoid div by 0
+            else
+                relative_intensity = (dezibel - P->moving_avg_30) / P->std_dev;
+
+            if (P->intensity_moving_avg == 0)
+                P->intensity_moving_avg = relative_intensity; // initial assignment
+            else
+                P->intensity_moving_avg = P->intensity_moving_avg * 0.95 + relative_intensity * 0.05;
+
+            // update intensity standard deviation
+            P->intensity_std_dev = P->intensity_std_dev * 0.95 + fabs (P->intensity_moving_avg - relative_intensity) * 0.05;
+
+            // we DO have a beat
+            P->state = _FISCHE__BEAT_;
+
+            // update beat gap history
+            P->beat_gap_history[P->bghist_head++] = frameno - P->last_beat_frame;
+            if (P->bghist_head == 30)
+                P->bghist_head = 0;
+
+            // remember this as the last beat
+            P->last_beat_frame = frameno;
+
+            // reset the short-term moving average
+            P->moving_avg_03 = dezibel;
+
+            // try a guess at the tempo
+            new_frames_per_beat = _fische__guess_frames_per_beat_ (P->beat_gap_history);
+            if ( (self->frames_per_beat) && (self->frames_per_beat / new_frames_per_beat < 1.2) && (new_frames_per_beat / self->frames_per_beat < 1.2))
+                self->frames_per_beat = (self->frames_per_beat * 2 + new_frames_per_beat) / 3;
+            else
+                self->frames_per_beat = new_frames_per_beat;
+
+            // return based on relative beat intensity
+            if (relative_intensity > P->intensity_moving_avg + 3 * P->intensity_std_dev)
+                return 4;
+            if (relative_intensity > P->intensity_moving_avg + 2 * P->intensity_std_dev)
+                return 3;
+            if (relative_intensity > P->intensity_moving_avg + 1 * P->intensity_std_dev)
+                return 2;
+
+            return 1;
+
+        case _FISCHE__BEAT_:
+        case _FISCHE__MAYBEWAITING_:
+            // update short term moving average
+            P->moving_avg_03 = P->moving_avg_03 * 0.6667 + dezibel * 0.3333;
+
+            // needs to be low enough twice to exit BEAT state
+            if (P->moving_avg_03 < P->moving_avg_30 + P->std_dev) {
+                P->state = P->state == _FISCHE__MAYBEWAITING_ ? _FISCHE__WAITING_ : _FISCHE__MAYBEWAITING_;
+                return 0;
+            }
+    }
+
+    // report level too low
+    if (dezibel < -45) return -1;
+    return 0;
+}
diff --git a/xbmc/visualizations/fishBMC/analyst.h b/xbmc/visualizations/fishBMC/analyst.h
new file mode 100644 (file)
index 0000000..1d1037f
--- /dev/null
@@ -0,0 +1,40 @@
+#ifndef ANALYST_H
+#define ANALYST_H
+
+#include <stdint.h>
+
+struct fische;
+struct _fische__analyst_;
+struct fische__analyst;
+
+
+
+struct fische__analyst* fische__analyst_new (struct fische* parent);
+void                    fische__analyst_free (struct fische__analyst* self);
+
+int_fast8_t             fische__analyst_analyse (struct fische__analyst* self, double* data, uint_fast16_t size);
+
+
+
+struct _fische__analyst_ {
+    uint_fast8_t    state;
+    double          moving_avg_30;
+    double          moving_avg_03;
+    double          std_dev;
+    double          intensity_moving_avg;
+    double          intensity_std_dev;
+    uint_fast32_t   last_beat_frame;
+    uint_fast16_t*  beat_gap_history;
+    uint_fast8_t    bghist_head;
+
+    struct fische*    fische;
+};
+
+struct fische__analyst {
+    double relative_energy;
+    double frames_per_beat;
+
+    struct _fische__analyst_* priv;
+};
+
+#endif
diff --git a/xbmc/visualizations/fishBMC/audiobuffer.c b/xbmc/visualizations/fishBMC/audiobuffer.c
new file mode 100644 (file)
index 0000000..de0ee8c
--- /dev/null
@@ -0,0 +1,181 @@
+#include "fische_internal.h"
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef DEBUG
+#include <stdio.h>
+#endif
+
+struct fische__audiobuffer*
+fische__audiobuffer_new (struct fische* parent) {
+
+    struct fische__audiobuffer* retval = malloc (sizeof (struct fische__audiobuffer));
+    retval->priv = malloc (sizeof (struct _fische__audiobuffer_));
+    struct _fische__audiobuffer_* P = retval->priv;
+
+    P->fische = parent;
+    P->buffer = 0;
+    P->buffer_size = 0;
+    P->format = parent->audio_format;
+    P->is_locked = 0;
+    P->puts = 0;
+    P->gets = 0;
+    P->last_get = 0;
+
+    retval->front_sample_count = 0;
+    retval->front_samples = 0;
+    retval->back_sample_count = 0;
+    retval->back_samples = 0;
+
+    return retval;
+}
+
+void
+fische__audiobuffer_free (struct fische__audiobuffer* self)
+{
+    if (!self)
+        return;
+
+    fische__audiobuffer_lock( self );
+
+    free (self->priv->buffer);
+    free (self->priv);
+    free (self);
+}
+
+void
+fische__audiobuffer_insert (struct fische__audiobuffer* self, const void* data, uint_fast32_t size)
+{
+    struct _fische__audiobuffer_* P = self->priv;
+
+    if (P->buffer_size > 44100)
+        return;
+
+    uint_fast8_t width = 1;
+
+    switch (P->format) {
+        case FISCHE_AUDIOFORMAT_DOUBLE:
+            width = 8;
+            break;
+        case FISCHE_AUDIOFORMAT_FLOAT:
+        case FISCHE_AUDIOFORMAT_S32:
+        case FISCHE_AUDIOFORMAT_U32:
+            width = 4;
+            break;
+        case FISCHE_AUDIOFORMAT_S16:
+        case FISCHE_AUDIOFORMAT_U16:
+            width = 2;
+    }
+
+    uint_fast32_t old_bufsize = P->buffer_size;
+    P->buffer_size += size / width;
+    P->buffer = realloc (P->buffer, P->buffer_size * sizeof (double));
+
+    uint_fast32_t i;
+    for (i = 0; i < size / width; ++ i) {
+        double* dest = (P->buffer + old_bufsize + i);
+
+        switch (P->format) {
+            case FISCHE_AUDIOFORMAT_FLOAT:
+                *dest = * ( (float*) data + i);
+                break;
+            case FISCHE_AUDIOFORMAT_DOUBLE:
+                *dest = * ( (double*) data + i);
+                break;
+            case FISCHE_AUDIOFORMAT_S32:
+                *dest = * ( (int32_t*) data + i);
+                *dest /= INT32_MAX;
+                break;
+            case FISCHE_AUDIOFORMAT_U32:
+                *dest = * ( (uint32_t*) data + i);
+                *dest -= INT32_MAX;
+                *dest /= INT32_MAX;
+                break;
+            case FISCHE_AUDIOFORMAT_S16:
+                *dest = * ( (int16_t*) data + i);
+                *dest /= INT16_MAX;
+                break;
+            case FISCHE_AUDIOFORMAT_U16:
+                *dest = * ( (uint16_t*) data + i);
+                *dest -= INT16_MAX;
+                *dest /= INT16_MAX;
+                break;
+            case FISCHE_AUDIOFORMAT_S8:
+                *dest = * ( (int8_t*) data + i);
+                *dest /= INT8_MAX;
+                break;
+            case FISCHE_AUDIOFORMAT_U8:
+                *dest = * ( (uint8_t*) data + i);
+                *dest /= INT8_MAX;
+                *dest /= INT8_MAX;
+                break;
+        }
+    }
+
+    ++ P->puts;
+}
+
+void
+fische__audiobuffer_get (struct fische__audiobuffer* self)
+{
+    struct _fische__audiobuffer_* P = self->priv;
+
+    if (P->buffer_size == 0)
+        return;
+
+    double* new_start = P->buffer + P->last_get * 2;
+    P->buffer_size -= P->last_get * 2;
+
+    // pop used data off front
+    memmove (P->buffer, new_start, P->buffer_size * sizeof (double));
+    P->buffer = realloc (P->buffer, P->buffer_size * sizeof (double));
+
+    if (!P->puts)
+        return;
+
+    // fallback for first get
+    if (P->gets == 0) {
+        P->gets = 3;
+        P->puts = 1;
+    }
+
+    // get/put ratio
+    double d_ratio = ( (double) P->gets ) / P->puts;
+    uint_fast8_t ratio = ceil( d_ratio );
+
+    // how many samples to return
+    uint_fast32_t n_samples = P->buffer_size / 2 / ratio;
+
+    // set return data size and remember
+    self->front_sample_count = n_samples;
+    self->back_sample_count = n_samples;
+    P->last_get = n_samples;
+
+    // set export buffer
+    self->front_samples = P->buffer;
+    self->back_samples = P->buffer + P->buffer_size - n_samples * 2;
+
+    // increment get counter
+    ++ P->gets;
+}
+
+void
+fische__audiobuffer_lock (struct fische__audiobuffer* self)
+{
+    #ifdef __GNUC__
+    while ( !__sync_bool_compare_and_swap( &self->priv->is_locked, 0, 1 ) )
+        usleep( 1 );
+    #else
+    while( self->priv->is_locked )
+        usleep( 1 );
+    self->priv->is_locked = 1;
+    #endif
+}
+
+void
+fische__audiobuffer_unlock (struct fische__audiobuffer* self)
+{
+    self->priv->is_locked = 0;
+}
diff --git a/xbmc/visualizations/fishBMC/audiobuffer.h b/xbmc/visualizations/fishBMC/audiobuffer.h
new file mode 100644 (file)
index 0000000..7bf1657
--- /dev/null
@@ -0,0 +1,43 @@
+#ifndef AUDIOBUFFER_H
+#define AUDIOBUFFER_H
+
+#include <stdint.h>
+
+struct fische;
+struct _fische__audiobuffer_;
+struct fische__audiobuffer;
+
+
+
+struct fische__audiobuffer* fische__audiobuffer_new (struct fische* parent);
+void                        fische__audiobuffer_free (struct fische__audiobuffer* self);
+
+void                        fische__audiobuffer_insert (struct fische__audiobuffer* self, const void* data, uint_fast32_t size);
+void                        fische__audiobuffer_lock (struct fische__audiobuffer* self);
+void                        fische__audiobuffer_unlock (struct fische__audiobuffer* self);
+void                        fische__audiobuffer_get (struct fische__audiobuffer* self);
+
+
+
+struct _fische__audiobuffer_ {
+    double*         buffer;
+    uint_fast32_t   buffer_size;
+    uint_fast8_t    format;
+    uint_fast8_t    is_locked;
+    uint_fast32_t   puts;
+    uint_fast32_t   gets;
+    uint_fast32_t   last_get;
+
+    struct fische*    fische;
+};
+
+struct fische__audiobuffer {
+    double* front_samples;
+    uint_fast16_t front_sample_count;
+    double* back_samples;
+    uint_fast16_t back_sample_count;
+
+    struct _fische__audiobuffer_* priv;
+};
+
+#endif
diff --git a/xbmc/visualizations/fishBMC/blurengine.c b/xbmc/visualizations/fishBMC/blurengine.c
new file mode 100644 (file)
index 0000000..13100f0
--- /dev/null
@@ -0,0 +1,169 @@
+#include "fische_internal.h"
+
+#include <pthread.h>
+#include <unistd.h>
+
+#ifdef DEBUG
+#include <stdio.h>
+#endif
+
+void*
+blur_worker (void* arg)
+{
+    struct _fische__blurworker_* params = arg;
+
+    uint_fast16_t const width = params->width;
+    uint_fast16_t const width_x2 = 2 * width;
+    uint_fast16_t const y_start = params->y_start;
+    uint_fast16_t const y_end = params->y_end;
+
+    uint32_t source_component[4];
+
+    uint_fast16_t const two_lines = 2 * width;
+    uint_fast16_t const one_line = width;
+    uint_fast16_t const two_columns    = 2;
+
+    uint_fast16_t x, y;
+    int_fast8_t vector_x, vector_y;
+
+    while (!params->kill) {
+
+        if (!params->work) {
+            usleep (1);
+            continue;
+        }
+
+        uint32_t* source = params->source;
+        uint32_t* source_pixel;
+
+        uint32_t* destination = params->destination;
+        uint32_t* destination_pixel = destination + y_start * width;
+
+        int8_t* vectors = (int8_t*) params->vectors;
+        int8_t*        vector_pointer = vectors + y_start * width_x2;
+
+        // vertical loop
+        for (y = y_start; y < y_end; y ++) {
+            // horizontal loop
+            for (x = 0; x < width; x ++) {
+
+                // read the motion vector (actually its opposite)
+                vector_x = * (vector_pointer + 0);
+                vector_y = * (vector_pointer + 1);
+
+                // point to the pixel at [present + motion vector]
+                source_pixel = source + (y + vector_y) * width + x + vector_x;
+
+                // read the pixels at [source + (2,1)]   [source + (-2,1)]   [source + (0,-2)]
+                // shift them right by 2 and remove the bits that overflow each byte
+                source_component[0] = (* (source_pixel + one_line - two_columns) >> 2) & 0x3f3f3f3f;
+                source_component[1] = (* (source_pixel + one_line + two_columns) >> 2) & 0x3f3f3f3f;
+                source_component[2] = (* (source_pixel - two_lines) >> 2) & 0x3f3f3f3f;
+                source_component[3] = (* (source_pixel) >> 2) & 0x3f3f3f3f;
+
+                // add those four components and write to the destination
+                // increment destination pointer
+                * (destination_pixel ++) = source_component[0]
+                                           + source_component[1]
+                                           + source_component[2]
+                                           + source_component[3];
+
+                // increment vector source pointer
+                vector_pointer += 2;
+            }
+        }
+
+        // mark work as done
+        params->work = 0;
+    }
+
+    return 0;
+}
+
+struct fische__blurengine*
+fische__blurengine_new (struct fische* parent) {
+
+    struct fische__blurengine* retval = malloc (sizeof (struct fische__blurengine));
+    retval->priv = malloc (sizeof (struct _fische__blurengine_));
+    struct _fische__blurengine_* P = retval->priv;
+
+    P->fische = parent;
+    P->width = parent->width;
+    P->height = parent->height;
+    P->threads = parent->used_cpus;
+    P->sourcebuffer = FISCHE_PRIVATE(P)->screenbuffer->pixels;
+    P->destinationbuffer = malloc (P->width * P->height * sizeof (uint32_t));
+
+    uint_fast8_t i;
+    for (i = 0; i < P->threads; ++ i) {
+        P->worker[i].source = P->sourcebuffer;
+        P->worker[i].destination = P->destinationbuffer;
+        P->worker[i].vectors = 0;
+        P->worker[i].width = P->width;
+        P->worker[i].y_start = (i * P->height) / P->threads;
+        P->worker[i].y_end = ( (i + 1) * P->height) / P->threads;
+        P->worker[i].kill = 0;
+        P->worker[i].work = 0;
+
+        pthread_create (&P->worker[i].thread_id, NULL, blur_worker, &P->worker[i]);
+    }
+
+    return retval;
+}
+
+void
+fische__blurengine_free (struct fische__blurengine* self)
+{
+    if (!self)
+        return;
+
+    struct _fische__blurengine_* P = self->priv;
+
+    uint_fast8_t i;
+    for (i = 0; i < P->threads; ++ i) {
+        P->worker[i].kill = 1;
+        pthread_join (P->worker[i].thread_id, NULL);
+    }
+
+    free (self->priv->destinationbuffer);
+    free (self->priv);
+    free (self);
+}
+
+void
+fische__blurengine_blur (struct fische__blurengine* self, uint16_t* vectors)
+{
+    struct _fische__blurengine_* P = self->priv;
+    uint_fast8_t i;
+    for (i = 0; i < P->threads; ++ i) {
+        P->worker[i].source = P->sourcebuffer;
+        P->worker[i].destination = P->destinationbuffer;
+        P->worker[i].vectors = vectors;
+        P->worker[i].work = 1;
+    }
+}
+
+void
+fische__blurengine_swapbuffers (struct fische__blurengine* self)
+{
+    struct _fische__blurengine_* P = self->priv;
+
+    // wait for all workers to finish
+    uint_fast8_t work = 1;
+    while (work) {
+
+        work = 0;
+        uint_fast8_t i;
+        for (i = 0; i < P->threads; ++ i) {
+            work += P->worker[i].work;
+        }
+
+        if (work)
+            usleep (1);
+    }
+
+    uint32_t* t = P->destinationbuffer;
+    P->destinationbuffer = P->sourcebuffer;
+    P->sourcebuffer = t;
+    FISCHE_PRIVATE(P)->screenbuffer->pixels = t;
+}
diff --git a/xbmc/visualizations/fishBMC/blurengine.h b/xbmc/visualizations/fishBMC/blurengine.h
new file mode 100644 (file)
index 0000000..dd03ca8
--- /dev/null
@@ -0,0 +1,51 @@
+#ifndef BLURENGINE_H
+#define BLURENGINE_H
+
+#include <stdint.h>
+#include <pthread.h>
+
+struct fische;
+
+struct _fische__blurworker_;
+struct _fische__blurengine_;
+struct fische__blurengine;
+
+
+
+struct fische__blurengine*  fische__blurengine_new (struct fische* parent);
+void                        fische__blurengine_free (struct fische__blurengine* self);
+
+void                        fische__blurengine_blur (struct fische__blurengine* self, uint16_t* vectors);
+void                        fische__blurengine_swapbuffers (struct fische__blurengine* self);
+
+
+
+struct _fische__blurworker_ {
+    pthread_t       thread_id;
+    uint32_t*       source;
+    uint32_t*       destination;
+    uint_fast16_t   width;
+    uint_fast16_t   y_start;
+    uint_fast16_t   y_end;
+    uint16_t*       vectors;
+    uint_fast8_t    work;
+    uint_fast8_t    kill;
+};
+
+struct _fische__blurengine_ {
+    int_fast16_t        width;
+    int_fast16_t        height;
+    uint_fast8_t        threads;
+    uint32_t*           sourcebuffer;
+    uint32_t*           destinationbuffer;
+
+    struct _fische__blurworker_ worker[8];
+
+    struct fische*    fische;
+};
+
+struct fische__blurengine {
+    struct _fische__blurengine_* priv;
+};
+
+#endif
diff --git a/xbmc/visualizations/fishBMC/cpudetect.c b/xbmc/visualizations/fishBMC/cpudetect.c
new file mode 100644 (file)
index 0000000..5daee6a
--- /dev/null
@@ -0,0 +1,80 @@
+#include "fische_internal.h"
+
+#include <string.h>
+
+#if defined(__x86_64__)
+
+void
+_fische__host_get_cpuid_ (uint32_t t, uint32_t* eax, uint32_t* ebx, uint32_t* ecx, uint32_t* edx)
+{
+    asm ("pushq %%rbx\n\t"
+         "movl %%esi, %%ebx\n\t"
+         "cpuid\n\t"
+         "movl %%ebx, %%esi\n\t"
+         "popq %%rbx"
+         : "=a" (*eax)
+         , "=S" (*ebx)
+         , "=c" (*ecx)
+         , "=d" (*edx)
+         : "a" (t)
+         , "c" (0)
+         , "S" (0)
+         , "d" (0));
+}
+
+#elif defined(__i386__)
+
+void
+_fische__host_get_cpuid_ (uint32_t t, uint32_t* eax, uint32_t* ebx, uint32_t* ecx, uint32_t* edx)
+{
+    asm ("pushl %%ebx\n\t"
+         "movl %%esi, %%ebx\n\t"
+         "cpuid\n\t"
+         "movl %%ebx, %%esi\n\t"
+         "popl %%ebx"
+         : "=a" (*eax)
+         , "=S" (*ebx)
+         , "=c" (*ecx)
+         , "=d" (*edx)
+         : "a" (t)
+         , "c" (0)
+         , "S" (0)
+         , "d" (0));
+}
+
+#endif
+
+uint_fast8_t
+_fische__cpu_detect_()
+{
+
+#if defined(__i386__) || defined(__x86_64__)
+    int n = 1;
+    uint32_t eax, ebx, ecx, edx;
+    _fische__host_get_cpuid_ (0x0, &eax, &ebx, &ecx, &edx);
+
+    char cpuid[13];
+    memcpy (cpuid, &ebx, 4);
+    memcpy (cpuid + 4, &edx, 4);
+    memcpy (cpuid + 8, &ecx, 4);
+    cpuid[12] = '\0';
+
+    if (!strcmp (cpuid, "AuthenticAMD")) {
+        _fische__host_get_cpuid_ (0x80000000, &eax, &ebx, &ecx, &edx);
+        if (eax < 0x80000008) return 1;
+        _fische__host_get_cpuid_ (0x80000008, &eax, &ebx, &ecx, &edx);
+        n = (ecx & 0xff) + 1;
+
+    } else { /* if it's not AMD, it's most likely Intel */
+        _fische__host_get_cpuid_ (0x00000000, &eax, &ebx, &ecx, &edx);
+        if (eax < 4) return 1;
+        _fische__host_get_cpuid_ (0x4, &eax, &ebx, &ecx, &edx);
+        n = (eax >> 26) + 1;
+    }
+
+    return n;
+
+#else /* don't have cpuid */
+    return 1;
+#endif
+}
diff --git a/xbmc/visualizations/fishBMC/fische.c b/xbmc/visualizations/fishBMC/fische.c
new file mode 100644 (file)
index 0000000..b9b65a1
--- /dev/null
@@ -0,0 +1,296 @@
+#include "fische_internal.h"
+
+#include <string.h>
+#include <pthread.h>
+#include <unistd.h>
+
+#ifdef DEBUG
+#include <stdio.h>
+#endif
+
+void*
+create_vectors (void* arg)
+{
+    struct fische* F = arg;
+    struct _fische__internal_ * P = F->priv;
+    P->vectorfield = fische__vectorfield_new (F,
+                     &P->init_progress,
+                     &P->init_cancel);
+    return 0;
+}
+
+void*
+indicate_busy (void* arg)
+{
+    struct fische* F = arg;
+    struct _fische__internal_ * P = F->priv;
+    struct fische__screenbuffer* sbuf = P->screenbuffer;
+
+    fische__point center;
+    center.x = sbuf->priv->width / 2;
+    center.y = sbuf->priv->height / 2;
+    double dim = (center.x > center.y) ? center.y / 2 : center.x / 2;
+
+    double last = -1;
+
+    while ( (P->init_progress < 1) && (!P->init_cancel)) {
+
+        if ( (P->init_progress < 0) || (P->init_progress == last)) {
+            usleep (10000);
+            continue;
+        }
+
+        last = P->init_progress;
+        double angle = P->init_progress * -2 * 3.1415 + 3.0415;
+
+        fische__vector c1;
+        c1.x = sin (angle) * dim;
+        c1.y = cos (angle) * dim;
+
+        fische__vector c2;
+        c2.x = sin (angle + 0.1) * dim;
+        c2.y = cos (angle + 0.1) * dim;
+
+        fische__vector e1 = fische__vector_single (&c1);
+        fische__vector_mul (&e1, dim / 2);
+        fische__vector e2 = fische__vector_single (&c2);
+        fische__vector_mul (&e2, dim / 2);
+
+        fische__vector c3 = c2;
+        fische__vector_sub (&c3, &e2);
+        fische__vector c4 = c1;
+        fische__vector_sub (&c4, &e1);
+
+        fische__vector_mul (&c1, F->scale);
+        fische__vector_mul (&c2, F->scale);
+        fische__vector_mul (&c3, F->scale);
+        fische__vector_mul (&c4, F->scale);
+
+        fische__vector_add (&c1, &center);
+        fische__vector_add (&c2, &center);
+        fische__vector_add (&c3, &center);
+        fische__vector_add (&c4, &center);
+
+        fische__screenbuffer_lock (sbuf);
+        fische__screenbuffer_line (sbuf, c1.x, c1.y, c2.x, c2.y, 0xffffffff);
+        fische__screenbuffer_line (sbuf, c2.x, c2.y, c3.x, c3.y, 0xffffffff);
+        fische__screenbuffer_line (sbuf, c3.x, c3.y, c4.x, c4.y, 0xffffffff);
+        fische__screenbuffer_line (sbuf, c4.x, c4.y, c1.x, c1.y, 0xffffffff);
+        fische__screenbuffer_unlock (sbuf);
+    }
+
+    return 0;
+}
+
+struct fische *
+fische_new() {
+    struct fische* retval = malloc (sizeof (struct fische));
+
+    retval->used_cpus = _fische__cpu_detect_();
+    if (retval->used_cpus > 8)
+        retval->used_cpus = 8;
+
+    retval->frame_counter = 0;
+    retval->audio_format = FISCHE_AUDIOFORMAT_FLOAT;
+    retval->pixel_format = FISCHE_PIXELFORMAT_0xAABBGGRR;
+    retval->width = 512;
+    retval->height = 256;
+    retval->read_vectors = 0;
+    retval->write_vectors = 0;
+    retval->on_beat = 0;
+    retval->nervous_mode = 0;
+    retval->blur_mode = FISCHE_BLUR_SLICK;
+    retval->line_style = FISCHE_LINESTYLE_ALPHA_SIMULATION;
+    retval->scale = 1;
+    retval->amplification = 0;
+    retval->priv = 0;
+    retval->error_text = "no error";
+
+    return retval;
+}
+
+int
+fische_start (struct fische* handle)
+{
+    // plausibility checks
+    if ( (handle->used_cpus > 8) || (handle->used_cpus < 1)) {
+        handle->error_text = "CPU count out of range (1 <= used_cpus <= 8)";
+        return 1;
+    }
+
+    if (handle->audio_format >= _FISCHE__AUDIOFORMAT_LAST_) {
+        handle->error_text = "audio format invalid";
+        return 1;
+    }
+
+    if (handle->line_style >= _FISCHE__LINESTYLE_LAST_) {
+        handle->error_text = "line style invalid";
+        return 1;
+    }
+
+    if (handle->frame_counter != 0) {
+        handle->error_text = "frame counter garbled";
+        return 1;
+    }
+
+    if ( (handle->amplification < -10) || (handle->amplification > 10)) {
+        handle->error_text = "amplification value out of range (-10 <= amplification <= 10)";
+        return 1;
+    }
+
+    if ( (handle->height < 16) || (handle->height > 2048)) {
+        handle->error_text = "height value out of range (16 <= height <= 2048)";
+        return 1;
+    }
+
+    if ( (handle->width < 16) || (handle->width > 2048)) {
+        handle->error_text = "width value out of range (16 <= width <= 2048)";
+        return 1;
+    }
+
+    if (handle->width % 4 != 0) {
+        handle->error_text = "width value invalid (must be a multiple of four)";
+        return 1;
+    }
+
+    if (handle->pixel_format >= _FISCHE__PIXELFORMAT_LAST_) {
+        handle->error_text = "pixel format invalid";
+        return 1;
+    }
+
+    if ( (handle->scale < 0.5) || (handle->scale > 2)) {
+        handle->error_text = "scale value out of range (0.5 <= scale <= 2.0)";
+        return 1;
+    }
+
+    if (handle->blur_mode >= _FISCHE__BLUR_LAST_) {
+        handle->error_text = "blur option invalid";
+        return 1;
+    }
+
+    // initialize private struct
+    handle->priv = malloc (sizeof (struct _fische__internal_));
+    memset (handle->priv, '\0', sizeof (struct _fische__internal_));
+    struct _fische__internal_* P = handle->priv;
+
+    P->init_progress = -1;
+
+    P->analyst = fische__analyst_new (handle);
+    P->screenbuffer = fische__screenbuffer_new (handle);
+    P->wavepainter = fische__wavepainter_new (handle);
+    P->blurengine = fische__blurengine_new (handle);
+    P->audiobuffer = fische__audiobuffer_new (handle);
+
+    // start vector creation and busy indicator threads
+    pthread_t vector_thread;
+    pthread_create (&vector_thread, NULL, create_vectors, handle);
+    pthread_detach (vector_thread);
+
+    pthread_t busy_thread;
+    pthread_create (&busy_thread, NULL, indicate_busy, handle);
+    pthread_detach (busy_thread);
+
+    return 0;
+}
+
+uint32_t*
+fische_render (struct fische* handle)
+{
+    struct _fische__internal_* P = handle->priv;
+
+    // only if init completed
+    if (P->init_progress >= 1) {
+
+        // analyse sound data
+        fische__audiobuffer_lock (P->audiobuffer);
+        fische__audiobuffer_get (P->audiobuffer);
+        int_fast8_t analysis = fische__analyst_analyse (P->analyst, P->audiobuffer->back_samples, P->audiobuffer->back_sample_count);
+
+        // act accordingly
+        if (handle->nervous_mode) {
+            if (analysis >= 2)
+                fische__wavepainter_change_shape (P->wavepainter);
+            if (analysis >= 1)
+                fische__vectorfield_change (P->vectorfield);
+        } else {
+            if (analysis >= 1)
+                fische__wavepainter_change_shape (P->wavepainter);
+            if (analysis >= 2)
+                fische__vectorfield_change (P->vectorfield);
+        }
+
+        if (analysis >= 3) {
+            fische__wavepainter_beat (P->wavepainter, P->analyst->frames_per_beat);
+        }
+        if (analysis >= 4) {
+            if (handle->on_beat)
+                handle->on_beat (P->analyst->frames_per_beat);
+        }
+
+        P->audio_valid = analysis >= 0 ? 1 : 0;
+
+        fische__wavepainter_change_color (P->wavepainter, P->analyst->frames_per_beat, P->analyst->relative_energy);
+
+
+        // wait for blurring to be finished
+        // and swap buffers
+        fische__screenbuffer_lock (P->screenbuffer);
+        fische__blurengine_swapbuffers (P->blurengine);
+        fische__screenbuffer_unlock (P->screenbuffer);
+
+        // draw waves
+        if (P->audio_valid)
+            fische__wavepainter_paint (P->wavepainter, P->audiobuffer->front_samples, P->audiobuffer->front_sample_count);
+
+        // start blurring for the next frame
+        fische__blurengine_blur (P->blurengine, P->vectorfield->field);
+
+        fische__audiobuffer_unlock (P->audiobuffer);
+    }
+
+    handle->frame_counter ++;
+
+    return P->screenbuffer->pixels;
+}
+
+void
+fische_free (struct fische* handle)
+{
+    if (!handle)
+        return;
+
+    struct _fische__internal_* P = handle->priv;
+
+    if (handle->priv) {
+        // tell init threads to quit
+        P->init_cancel = 1;
+
+        // wait for init threads to quit
+        while (P->init_progress < 1)
+            usleep (10);
+
+        fische__audiobuffer_free (P->audiobuffer);
+        fische__blurengine_free (P->blurengine);
+        fische__vectorfield_free (P->vectorfield);
+        fische__wavepainter_free (P->wavepainter);
+        fische__screenbuffer_free (P->screenbuffer);
+        fische__analyst_free (P->analyst);
+
+        free (handle->priv);
+    }
+
+    free (handle);
+}
+
+void
+fische_audiodata (struct fische* handle, const void* data, size_t data_size)
+{
+    struct _fische__internal_* P = handle->priv;
+
+    if (NULL == P->audiobuffer)
+        return;
+
+    fische__audiobuffer_lock (P->audiobuffer);
+    fische__audiobuffer_insert (P->audiobuffer, data, data_size);
+    fische__audiobuffer_unlock (P->audiobuffer);
+}
diff --git a/xbmc/visualizations/fishBMC/fische.h b/xbmc/visualizations/fishBMC/fische.h
new file mode 100644 (file)
index 0000000..b4bc68c
--- /dev/null
@@ -0,0 +1,149 @@
+#ifndef FISCHE_H
+#define FISCHE_H
+
+/* int types */
+#include <stdint.h>
+/* size_t */
+#include <stdlib.h>
+
+typedef struct fische {
+
+    /* 16 <= width <= 2048
+     * DEFAULT: 512
+     * constant after fische_start() */
+    uint16_t    width;
+
+    /* 16 <= height <= 2048
+     * DEFAULT: 256
+     * constant after fische_start() */
+    uint16_t    height;
+
+    /* 1 <= used_cpus <= 8
+     * DEFAULT: all available (autodetect)
+     * constant after fische_start() */
+    uint8_t     used_cpus;
+
+    /* true (!=0) or false (0)
+     * DEFAULT: 0 */
+    uint8_t     nervous_mode;
+
+    /* see below (audio format enum)
+     * DEFAULT: FISCHE_AUDIOFORMAT_FLOAT
+     * constant after fische_start() */
+    uint8_t     audio_format;
+
+    /* see below (pixel format enum)
+     * DEFAULT: FISCHE_PIXELFORMAT_0xAABBGGRR
+     * constant after fische_start() */
+    uint8_t     pixel_format;
+
+    /* see below (blur mode enum)
+     * DEFAULT: FISCHE_BLUR_SLICK
+     * constant after fische_start() */
+    uint8_t     blur_mode;
+
+    /* see below (line style enum)
+     * DEFAULT: FISCHE_LINESTYLE_ALPHA_SIMULATION */
+    uint8_t     line_style;
+
+    /* 0.5 <= scale <= 2.0
+     * DEFAULT: 1.0
+     * constant after fische_start() */
+    double      scale;
+
+    /* -10 <= amplification <= 10
+     * DEFAULT: 0 */
+    double      amplification;
+
+    /* if non-NULL,
+     * fische calls this to read vector fields from an external source
+     * takes a void** for data placement
+     * returns the number of bytes read */
+    size_t (*read_vectors) (void**);
+
+    /* if non-NULL,
+     * fische calls this to write vector field data to an external sink
+     * takes a void* and the number of bytes to be written */
+    void (*write_vectors) (const void*, size_t);
+
+    /* if non-NULL,
+     * fische calls this on major beats that are not handled internally
+     * takes frames per beat */
+    void (*on_beat) (double);
+
+    /* read only */
+    uint32_t    frame_counter;
+
+    /* read only */
+    char*       error_text;
+
+    void*       priv;
+
+} FISCHE;
+
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+
+    /* creates a new FISCHE object
+     * and initialzes it with default values */
+    FISCHE*     fische_new();
+
+    /* starts FISCHE */
+    int         fische_start (FISCHE* handle);
+
+    /* makes the next frame available */
+    uint32_t*   fische_render (FISCHE* handle);
+
+    /* destructs the FISCHE object */
+    void        fische_free (FISCHE* handle);
+
+    /* inserts audio data */
+    void        fische_audiodata (FISCHE* handle, const void* data, size_t data_size);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+
+/* audio sample formats */
+enum {FISCHE_AUDIOFORMAT_U8,
+      FISCHE_AUDIOFORMAT_S8,
+      FISCHE_AUDIOFORMAT_U16,
+      FISCHE_AUDIOFORMAT_S16,
+      FISCHE_AUDIOFORMAT_U32,
+      FISCHE_AUDIOFORMAT_S32,
+      FISCHE_AUDIOFORMAT_FLOAT,
+      FISCHE_AUDIOFORMAT_DOUBLE,
+      _FISCHE__AUDIOFORMAT_LAST_
+     };
+
+/* pixel formats */
+enum {FISCHE_PIXELFORMAT_0xRRGGBBAA,
+      FISCHE_PIXELFORMAT_0xAABBGGRR,
+      FISCHE_PIXELFORMAT_0xAARRGGBB,
+      FISCHE_PIXELFORMAT_0xBBGGRRAA,
+      _FISCHE__PIXELFORMAT_LAST_
+     };
+
+/* blur style */
+enum {FISCHE_BLUR_SLICK,
+      FISCHE_BLUR_FUZZY,
+      _FISCHE__BLUR_LAST_
+     };
+
+/* line style */
+enum {FISCHE_LINESTYLE_THIN,
+      FISCHE_LINESTYLE_THICK,
+      FISCHE_LINESTYLE_ALPHA_SIMULATION,
+      _FISCHE__LINESTYLE_LAST_
+     };
+
+#endif
diff --git a/xbmc/visualizations/fishBMC/fische_internal.h b/xbmc/visualizations/fishBMC/fische_internal.h
new file mode 100644 (file)
index 0000000..76fc534
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef FISCHE_INTERNAL_H
+#define FISCHE_INTERNAL_H
+
+#include "fische.h"
+#include "wavepainter.h"
+#include "screenbuffer.h"
+#include "analyst.h"
+#include "vector.h"
+#include "vectorfield.h"
+#include "blurengine.h"
+#include "audiobuffer.h"
+
+#ifdef WIN32
+#define rand_r(_seed) (_seed == _seed ? rand() : rand())
+#endif
+
+#define FISCHE_PRIVATE(P) ((struct _fische__internal_*) P->fische->priv)
+
+uint_fast8_t _fische__cpu_detect_();
+
+
+struct _fische__internal_ {
+    struct fische__screenbuffer*    screenbuffer;
+    struct fische__wavepainter*     wavepainter;
+    struct fische__analyst*         analyst;
+    struct fische__blurengine*      blurengine;
+    struct fische__vectorfield*     vectorfield;
+    struct fische__audiobuffer*     audiobuffer;
+    double                          init_progress;
+    uint_fast8_t                    init_cancel;
+    uint_fast8_t                    audio_valid;
+};
+
+#endif
diff --git a/xbmc/visualizations/fishBMC/fishbmc_addon.cpp b/xbmc/visualizations/fishBMC/fishbmc_addon.cpp
new file mode 100644 (file)
index 0000000..cc080ef
--- /dev/null
@@ -0,0 +1,374 @@
+/*   fishBMC visualization plugin
+ *   Copyright (C) 2012 Marcel Ebmer
+
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+
+ *   You should have received a copy of the GNU General Public License along
+ *   with this program; if not, write to the Free Software Foundation, Inc.,
+ *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
+
+#ifdef __GNUC__
+#define __cdecl
+#endif
+
+#include "addons/include/xbmc_vis_types.h"
+#include "addons/include/xbmc_vis_dll.h"
+
+#include "fische.h"
+
+#include <cmath>
+#include <cstring>
+#include <unistd.h>
+#include <iostream>
+#include <string>
+#include <fstream>
+#include <sstream>
+#include <sys/stat.h>
+
+
+// global variables
+FISCHE*     g_fische;
+double      g_aspect;
+bool        g_isrotating;
+double      g_angle;
+double      g_lastangle;
+bool        g_errorstate;
+int         g_framedivisor;
+double      g_angleincrement;
+double      g_texright;
+double      g_texleft;
+bool        g_filemode;
+int         g_size;
+uint8_t*    g_axis = 0;
+
+
+
+
+
+// render functions
+// must be included AFTER global variables
+#if defined(_WIN32)
+#include "fishbmc_directx.hpp"
+#else // _WIN32
+#include "fishbmc_opengl.hpp"
+#endif // _WIN32
+
+
+
+
+
+void on_beat (double frames_per_beat)
+{
+    if (!g_isrotating) {
+        g_isrotating = true;
+        if (frames_per_beat < 1) frames_per_beat = 12;
+        g_angleincrement = 180 / 4 / frames_per_beat;
+    }
+}
+
+void write_vectors (const void* data, size_t bytes)
+{
+    char const * homedir = getenv ("HOME");
+    if (!homedir)
+        return;
+
+    std::string dirname = std::string (homedir) + "/.fishBMC-data";
+    mkdir (dirname.c_str(), 0755);
+
+    std::ostringstream filename;
+    filename << dirname << "/" << g_fische->height;
+
+    // open the file
+    std::fstream vectorsfile (filename.str().c_str(), std::fstream::out | std::fstream::binary);
+    if (!vectorsfile.good())
+        return;
+
+    // write it
+    vectorsfile.write (reinterpret_cast<const char*> (data), bytes);
+    vectorsfile.close();
+}
+
+size_t read_vectors (void** data)
+{
+    char const * homedir = getenv ("HOME");
+    if (!homedir)
+        return 0;
+
+    std::string dirname = std::string (homedir) + "/.fishBMC-data";
+    mkdir (dirname.c_str(), 0755);
+
+    std::ostringstream filename;
+    filename << dirname << "/" << g_fische->height;
+
+    // open the file
+    std::fstream vectorsfile (filename.str().c_str(), std::fstream::in);
+    if (!vectorsfile.good())
+        return 0;
+
+    vectorsfile.seekg (0, std::ios::end);
+    size_t n = vectorsfile.tellg();
+    vectorsfile.seekg (0, std::ios::beg);
+
+    *data = malloc (n);
+    vectorsfile.read (reinterpret_cast<char*> (*data), n);
+    vectorsfile.close();
+
+    return n;
+}
+
+void delete_vectors()
+{
+    char const * homedir = getenv ("HOME");
+    if (!homedir)
+        return;
+
+    std::string dirname = std::string (homedir) + "/.fishBMC-data";
+    mkdir (dirname.c_str(), 0755);
+
+    for (int i = 64; i <= 2048; i *= 2) {
+        std::ostringstream filename;
+        filename << dirname << "/" << i;
+        unlink (filename.str().c_str());
+    }
+}
+
+extern "C" ADDON_STATUS ADDON_Create (void* hdl, void* props)
+{
+    if (!props)
+        return ADDON_STATUS_UNKNOWN;
+
+    VIS_PROPS* visProps = (VIS_PROPS*) props;
+
+    init (visProps);
+
+    g_fische = fische_new();
+    g_fische->on_beat = &on_beat;
+    g_fische->pixel_format = FISCHE_PIXELFORMAT_0xAABBGGRR;
+    g_fische->line_style = FISCHE_LINESTYLE_THICK;
+    g_aspect = double (visProps->width) / double (visProps->height);
+    g_texleft = (2 - g_aspect) / 4;
+    g_texright = 1 - g_texleft;
+    g_framedivisor = 1;
+    g_filemode = false;
+    g_size = 128;
+
+    return ADDON_STATUS_NEED_SETTINGS;
+}
+
+extern "C" void Start (int, int, int, const char*)
+{
+    g_errorstate = false;
+
+    g_fische->audio_format = FISCHE_AUDIOFORMAT_FLOAT;
+
+    g_fische->height = g_size;
+    g_fische->width = 2 * g_size;
+
+    if (g_filemode) {
+        g_fische->read_vectors = &read_vectors;
+        g_fische->write_vectors = &write_vectors;
+    }
+
+    else {
+        delete_vectors();
+    }
+
+    if (fische_start (g_fische) != 0) {
+        std::cerr << "fische failed to start" << std::endl;
+        g_errorstate = true;
+        return;
+    }
+
+    uint32_t* pixels = fische_render (g_fische);
+
+    init_texture (g_fische->width, g_fische->height, pixels);
+
+    g_isrotating = false;
+    g_angle = 0;
+    g_lastangle = 0;
+    g_angleincrement = 0;
+}
+
+extern "C" void AudioData (const float* pAudioData, int iAudioDataLength, float*, int)
+{
+    fische_audiodata (g_fische, pAudioData, iAudioDataLength * 4);
+}
+
+extern "C" void Render()
+{
+    static int frame = 0;
+
+    // check if this frame is to be skipped
+    if (++ frame % g_framedivisor == 0) {
+        uint32_t* pixels = fische_render (g_fische);
+        replace_texture (g_fische->width, g_fische->height, pixels);
+        if (g_isrotating)
+            g_angle += g_angleincrement;
+    }
+
+    // stop rotation if required
+    if (g_isrotating) {
+        if (g_angle - g_lastangle > 180) {
+            g_lastangle = g_lastangle ? 0 : 180;
+            g_angle = g_lastangle;
+            g_isrotating = false;
+        }
+    }
+
+    // how many quads will there be?
+    int n_Y = 8;
+    int n_X = (g_aspect * 8 + 0.5);
+
+    // one-time initialization of rotation axis array
+    if (!g_axis) {
+        g_axis = new uint8_t[n_X * n_Y];
+        for (int i = 0; i < n_X * n_Y; ++ i) {
+            g_axis[i] = rand() % 2;
+        }
+    }
+
+    start_render();
+
+    // loop over and draw all quads
+    int quad_count = 0;
+    double quad_width = 4.0 / n_X;
+    double quad_height = 4.0 / n_Y;
+    double tex_width = (g_texright - g_texleft);
+
+    for (double X = 0; X < n_X; X += 1) {
+        for (double Y = 0; Y < n_Y; Y += 1) {
+            double center_x = -2 + (X + 0.5) * 4 / n_X;
+            double center_y = -2 + (Y + 0.5) * 4 / n_Y;
+            double tex_left = g_texleft + tex_width * X / n_X;
+            double tex_right = g_texleft + tex_width * (X + 1) / n_X;
+            double tex_top = Y / n_Y;
+            double tex_bottom = (Y + 1) / n_Y;
+            double angle = (g_angle - g_lastangle) * 4 - (X + Y * n_X) / (n_X * n_Y) * 360;
+            if (angle < 0) angle = 0;
+            if (angle > 360) angle = 360;
+
+            textured_quad (center_x,
+                              center_y,
+                              angle,
+                              g_axis[quad_count ++],
+                              quad_width,
+                              quad_height,
+                              tex_left,
+                              tex_right,
+                              tex_top,
+                              tex_bottom);
+        }
+    }
+
+    finish_render();
+}
+
+extern "C" void GetInfo (VIS_INFO* pInfo)
+{
+    // std::cerr << "fishBMC::GetInfo" << std::endl;
+    pInfo->bWantsFreq = false;
+    pInfo->iSyncDelay = 0;
+}
+
+extern "C" bool OnAction (long flags, const void *param)
+{
+    return false;
+}
+
+extern "C" unsigned int GetPresets (char ***presets)
+{
+    return 0;
+}
+
+extern "C" unsigned GetPreset()
+{
+    return 0;
+}
+
+extern "C" bool IsLocked()
+{
+    return false;
+}
+
+extern "C" unsigned int GetSubModules (char ***names)
+{
+    return 0;
+}
+
+extern "C" void ADDON_Stop()
+{
+    fische_free (g_fische);
+    g_fische = 0;
+    delete_texture();
+    delete [] g_axis;
+    g_axis = 0;
+}
+
+extern "C" void ADDON_Destroy()
+{
+    return;
+}
+
+extern "C" bool ADDON_HasSettings()
+{
+    return false;
+}
+
+extern "C" ADDON_STATUS ADDON_GetStatus()
+{
+    if (g_errorstate)
+        return ADDON_STATUS_UNKNOWN;
+
+    return ADDON_STATUS_OK;
+}
+
+extern "C" unsigned int ADDON_GetSettings (ADDON_StructSetting ***sSet)
+{
+    return 0;
+}
+
+extern "C" void ADDON_FreeSettings()
+{
+}
+
+extern "C" ADDON_STATUS ADDON_SetSetting (const char *strSetting, const void* value)
+{
+    if (!strSetting || !value)
+        return ADDON_STATUS_UNKNOWN;
+
+    if (!strncmp (strSetting, "nervous", 7)) {
+        bool nervous = * ( (bool*) value);
+        g_fische->nervous_mode = nervous ? 1 : 0;
+    }
+
+    else if (!strncmp (strSetting, "filemode", 7)) {
+        bool filemode = * ( (bool*) value);
+        g_filemode = filemode;
+    }
+
+    else if (!strncmp (strSetting, "detail", 6)) {
+        int detail = * ( (int*) value);
+        g_size = 128;
+        while (detail--) {
+            g_size *= 2;
+        }
+    }
+
+    else if (!strncmp (strSetting, "divisor", 7)) {
+        int divisor = * ( (int*) value);
+        g_framedivisor = 8;
+        while (divisor--) {
+            g_framedivisor /= 2;
+        }
+    }
+
+    return ADDON_STATUS_OK;
+}
diff --git a/xbmc/visualizations/fishBMC/fishbmc_directx.hpp b/xbmc/visualizations/fishBMC/fishbmc_directx.hpp
new file mode 100644 (file)
index 0000000..97b7550
--- /dev/null
@@ -0,0 +1,69 @@
+// TEMPLATE for DirectX implementation
+// check out fishbmc_opengl.hpp
+// contact marcel@26elf.at for questions
+// thanks for porting!
+
+#include <any headers you may need>
+
+// declare a global texture
+// declare other globals you may need
+
+void init (VIS_PROPS* vis_props)
+{
+    // take anything from the VIS_PROPS struct
+}
+
+inline void init_texture (int width, int height, uint32_t* pixels)
+{
+    // initialize the global texture of size (width x height) with data from pixels
+}
+
+inline void replace_texture (int width, int height, uint32_t* pixels)
+{
+    // replace the texture data with pixels
+}
+
+inline void delete_texture()
+{
+    // free memory held by global texture
+}
+
+void textured_quad (double center_x,
+                    double center_y,
+                    double angle,
+                    double axis,
+                    double width,
+                    double height,
+                    double tex_left,
+                    double tex_right,
+                    double tex_top,
+                    double tex_bottom)
+{
+    // draw a textured quad, sized (width x height), centered at (center_x, center_y),
+    // rotated by angle (this is in degrees) around an axis defined as (axis, 1 - axis, 0),
+    // scaled by (1 - sin (angle / 360 * M_PI) / 3)
+    // texture coordinates are given for all corners
+}
+
+inline void start_render()
+{
+    // save state
+    // enable blending
+    // disable depth testing
+    // paint both sides of polygons
+
+    // setup coordinate system:
+    //     screen top left: (-1, -1)
+    //     screen bottom right: (1, 1)
+    //     screen distance from eye: 3
+    //     screen depth clipping: 3 to 15
+
+    // bind global texture
+    // move 6 units into the screen
+    // rotate by global variable g_angle, around axis (0, 1, 0)
+}
+
+inline void finish_render()
+{
+    // restore original state
+}
diff --git a/xbmc/visualizations/fishBMC/fishbmc_opengl.hpp b/xbmc/visualizations/fishBMC/fishbmc_opengl.hpp
new file mode 100644 (file)
index 0000000..58426a2
--- /dev/null
@@ -0,0 +1,135 @@
+#if defined(__APPLE__)
+#include <OpenGL/gl.h>
+#include <OpenGL/glu.h>
+#else // __APPLE__
+#include <GL/gl.h>
+#include <GL/glu.h>
+#endif // __APPLE__
+
+
+// additional global variable
+GLuint      g_texture;
+
+
+// OpenGL: ignores VIS_PROPS
+void init (VIS_PROPS*) {}
+
+// OpenGL: texture initialization
+inline void init_texture (int width, int height, uint32_t* pixels)
+{
+    // generate a texture for drawing into
+    glEnable (GL_TEXTURE_2D);
+    glGenTextures (1, &g_texture);
+    glBindTexture (GL_TEXTURE_2D, g_texture);
+    glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
+}
+
+// OpenGL: replace texture
+inline void replace_texture (int width, int height, uint32_t* pixels)
+{
+    glBindTexture (GL_TEXTURE_2D, g_texture);
+    glTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
+}
+
+// OpenGL: delete texture
+inline void delete_texture()
+{
+    glDeleteTextures (1, &g_texture);
+}
+
+// OpenGL: paint a textured quad
+void textured_quad (double center_x,
+                    double center_y,
+                    double angle,
+                    double axis,
+                    double width,
+                    double height,
+                    double tex_left,
+                    double tex_right,
+                    double tex_top,
+                    double tex_bottom)
+{
+    glPushMatrix();
+
+    glTranslatef (center_x, center_y, 0);
+    glRotatef (angle, axis, 1 - axis, 0);
+
+    double scale = 1 - sin (angle / 360 * M_PI) / 3;
+    glScalef (scale, scale, scale);
+
+    glBegin (GL_QUADS);
+
+    glTexCoord2d (tex_left, tex_top);
+    glVertex3d (- width / 2, - height / 2, 0);
+
+    glTexCoord2d (tex_right, tex_top);
+    glVertex3d (width / 2, - height / 2, 0);
+
+    glTexCoord2d (tex_right, tex_bottom);
+    glVertex3d (width / 2, height / 2, 0);
+
+    glTexCoord2d (tex_left, tex_bottom);
+    glVertex3d (- width / 2, height / 2, 0);
+
+    glEnd();
+
+    glPopMatrix();
+}
+
+// OpenGL: setup to start rendering
+inline void start_render()
+{
+    // save state
+    glPushAttrib (GL_ENABLE_BIT | GL_TEXTURE_BIT);
+
+    // enable blending
+    glEnable (GL_BLEND);
+    glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+    // enable texturing
+    glEnable (GL_TEXTURE_2D);
+
+    // disable depth testing
+    glDisable (GL_DEPTH_TEST);
+
+    // paint both sides of polygons
+    glPolygonMode (GL_FRONT, GL_FILL);
+
+    // OpenGL projection matrix setup
+    glMatrixMode (GL_PROJECTION);
+    glPushMatrix();
+    glLoadIdentity();
+
+    // coordinate system:
+    //     screen top left: (-1, -1)
+    //     screen bottom right: (1, 1)
+    //     screen depth clipping: 3 to 15
+    glFrustum (-1, 1, 1, -1, 3, 15);
+
+    glMatrixMode (GL_MODELVIEW);
+    glPushMatrix();
+    glLoadIdentity();
+
+    // bind global texture
+    glBindTexture (GL_TEXTURE_2D, g_texture);
+
+    // move 6 units into the screen
+    glTranslatef (0, 0, -6.0f);
+
+    // rotate
+    glRotatef (g_angle, 0, 1, 0);
+}
+
+// OpenGL: done rendering
+inline void finish_render()
+{
+    // return OpenGL matrices to original state
+    glPopMatrix();
+    glMatrixMode (GL_PROJECTION);
+    glPopMatrix();
+
+    // restore OpenGl original state
+    glPopAttrib();
+}
diff --git a/xbmc/visualizations/fishBMC/screenbuffer.c b/xbmc/visualizations/fishBMC/screenbuffer.c
new file mode 100644 (file)
index 0000000..a4aa31e
--- /dev/null
@@ -0,0 +1,169 @@
+#include "fische_internal.h"
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+
+struct fische__screenbuffer*
+fische__screenbuffer_new (struct fische* parent) {
+    struct fische__screenbuffer* retval = malloc (sizeof (struct fische__screenbuffer));
+    retval->priv = malloc (sizeof (struct _fische__screenbuffer_));
+    struct _fische__screenbuffer_* P = retval->priv;
+
+    P->fische = parent;
+    P->width = parent->width;
+    P->height = parent->height;
+    P->is_locked = 0;
+
+    retval->pixels = malloc (P->width * P->height * sizeof (uint32_t));
+    memset (retval->pixels, '\0', P->width * P->height * sizeof (uint32_t));
+
+    switch (parent->pixel_format) {
+
+        case FISCHE_PIXELFORMAT_0xAABBGGRR:
+            P->alpha_shift = 24;
+            P->blue_shift = 16;
+            P->green_shift = 8;
+            P->red_shift = 0;
+            break;
+
+        case FISCHE_PIXELFORMAT_0xAARRGGBB:
+            P->alpha_shift = 24;
+            P->blue_shift = 0;
+            P->green_shift = 8;
+            P->red_shift = 16;
+            break;
+
+        case FISCHE_PIXELFORMAT_0xBBGGRRAA:
+            P->alpha_shift = 0;
+            P->blue_shift = 24;
+            P->green_shift = 16;
+            P->red_shift = 8;
+            break;
+
+        case FISCHE_PIXELFORMAT_0xRRGGBBAA:
+            P->alpha_shift = 0;
+            P->blue_shift = 8;
+            P->green_shift = 16;
+            P->red_shift = 24;
+            break;
+    }
+
+    return retval;
+}
+
+void
+fische__screenbuffer_free (struct fische__screenbuffer* self)
+{
+    if (!self)
+        return;
+
+    fische__screenbuffer_lock( self );
+
+    free (self->priv);
+    free (self->pixels);
+    free (self);
+}
+
+void
+fische__screenbuffer_lock (struct fische__screenbuffer* self)
+{
+    #ifdef __GNUC__
+    while ( !__sync_bool_compare_and_swap( &self->priv->is_locked, 0, 1 ) )
+        usleep( 1 );
+    #else
+    while( self->priv->is_locked )
+        usleep( 1 );
+    self->priv->is_locked = 1;
+    #endif
+}
+
+void
+fische__screenbuffer_unlock (struct fische__screenbuffer* self)
+{
+    self->priv->is_locked = 0;
+}
+
+void
+fische__screenbuffer_line (struct fische__screenbuffer* self,
+                           int_fast16_t x1,
+                           int_fast16_t y1,
+                           int_fast16_t x2,
+                           int_fast16_t y2,
+                           uint32_t color)
+{
+    struct _fische__screenbuffer_* P = self->priv;
+
+    double diff_x     = (x1 > x2) ? (x1 - x2) : (x2 - x1);
+    double diff_y     = (y1 > y2) ? (y1 - y2) : (y2 - y1);
+    double dir_x      = (x2 < x1) ? -1 : 1;
+    double dir_y      = (y2 < y1) ? -1 : 1;
+
+    if (!diff_x && !diff_y)
+        return;
+
+    uint32_t half_alpha_mask;
+
+    if (P->fische->line_style == FISCHE_LINESTYLE_ALPHA_SIMULATION)
+        half_alpha_mask = (0x7f << P->red_shift)
+                          + (0x7f << P->green_shift)
+                          + (0x7f << P->blue_shift)
+                          + (0x7f << P->alpha_shift);
+    else
+        half_alpha_mask = (0xff << P->red_shift)
+                          + (0xff << P->green_shift)
+                          + (0xff << P->blue_shift)
+                          + (0x7f << P->alpha_shift);
+
+
+    if (diff_x > diff_y) {
+
+        int_fast16_t x;
+        for (x = x1; x * dir_x <= x2 * dir_x; x += dir_x) {
+
+            int_fast16_t y = (y1 + diff_y / diff_x * dir_y * abs (x - x1) + 0.5);
+
+            if ( (x < 0) || (x >= P->width) || (y < 0) || (y >= P->height))
+                continue;
+
+            if (P->fische->line_style != FISCHE_LINESTYLE_THIN) {
+                y ++;
+                if (! (y < 0) && ! (y >= P->height))
+                    * (self->pixels + y * P->width + x) = color & half_alpha_mask;
+
+                y -= 2;
+                if ( (y < 0) || (y >= P->height)) continue;
+                * (self->pixels + y * P->width + x) = color & half_alpha_mask;
+
+                y ++;
+            }
+
+            * (self->pixels + y * P->width + x) = color;
+        }
+    } else {
+
+        int_fast16_t y;
+        for (y = y1; y * dir_y <= y2 * dir_y; y += dir_y) {
+
+            int_fast16_t x = (x1 + diff_x / diff_y * dir_x * abs (y - y1) + 0.5);
+
+            if ( (x < 0) || (x >= P->width) || (y < 0) || (y >= P->height))
+                continue;
+
+            if (P->fische->line_style != FISCHE_LINESTYLE_THIN) {
+                x ++;
+                if (! (x < 0) && ! (x >= P->width))
+                    * (self->pixels + y * P->width + x) = color & half_alpha_mask;
+
+                x -= 2;
+                if ( (x < 0) || (x >= P->width)) continue;
+                * (self->pixels + y * P->width + x) = color & half_alpha_mask;
+
+                x ++;
+            }
+
+            * (self->pixels + y * P->width + x) = color;
+        }
+    }
+}
diff --git a/xbmc/visualizations/fishBMC/screenbuffer.h b/xbmc/visualizations/fishBMC/screenbuffer.h
new file mode 100644 (file)
index 0000000..84f90fd
--- /dev/null
@@ -0,0 +1,45 @@
+#ifndef SCREENBUFFER_H
+#define SCREENBUFFER_H
+
+#include <stdint.h>
+
+struct fische;
+struct _fische__screenbuffer;
+struct fische__screenbuffer;
+
+
+
+struct fische__screenbuffer*    fische__screenbuffer_new (struct fische* parent);
+void                            fische__screenbuffer_free (struct fische__screenbuffer* self);
+
+void                            fische__screenbuffer_lock (struct fische__screenbuffer* self);
+void                            fische__screenbuffer_unlock (struct fische__screenbuffer* self);
+
+void fische__screenbuffer_line (struct fische__screenbuffer* self,
+                                int_fast16_t x1,
+                                int_fast16_t y1,
+                                int_fast16_t x2,
+                                int_fast16_t y2,
+                                uint32_t color);
+
+
+
+struct _fische__screenbuffer_ {
+    uint_fast8_t        is_locked;
+    int_fast16_t        width;
+    int_fast16_t        height;
+    uint_fast8_t        red_shift;
+    uint_fast8_t        blue_shift;
+    uint_fast8_t        green_shift;
+    uint_fast8_t        alpha_shift;
+
+    struct fische*    fische;
+};
+
+struct fische__screenbuffer {
+    uint32_t*       pixels;
+
+    struct _fische__screenbuffer_* priv;
+};
+
+#endif
diff --git a/xbmc/visualizations/fishBMC/vector.c b/xbmc/visualizations/fishBMC/vector.c
new file mode 100644 (file)
index 0000000..5a1a53e
--- /dev/null
@@ -0,0 +1,137 @@
+#include "vector.h"
+
+inline double fische__vector_length (fische__vector* self)
+{
+    return sqrt (pow (self->x, 2) + pow (self->y, 2));
+}
+
+inline fische__vector fische__vector_normal (fische__vector* self)
+{
+    fische__vector r;
+    r.x = self->y;
+    r.y = - self->x;
+    return r;
+}
+
+inline fische__vector fische__vector_single (fische__vector* self)
+{
+    double l = fische__vector_length (self);
+    fische__vector r;
+    r.x = self->x / l;
+    r.y = self->y / l;
+    return r;
+}
+
+inline double fische__vector_angle (fische__vector* self)
+{
+    fische__vector su = fische__vector_single (self);
+    double a = acos (su.x);
+    if (self->y > 0) return a;
+    else return -a;
+}
+
+// conversion to 2x int8
+inline uint16_t fische__vector_to_uint16 (fische__vector* self)
+{
+    if (self->x < -127) self->x = -127;
+    if (self->x > 127) self->x = 127;
+    if (self->y < -127) self->y = -127;
+    if (self->y > 127) self->y = 127;
+
+    int8_t ix = (self->x < 0) ? self->x - 0.5 : self->x + 0.5;
+    int8_t iy = (self->y < 0) ? self->y - 0.5 : self->y + 0.5;
+
+    uint16_t retval = (uint8_t) ix;
+    retval |= ( (uint8_t) iy) << 8;
+    return retval;
+}
+
+inline fische__vector fische__vector_from_uint16 (uint16_t val)
+{
+    int8_t ix = val & 0xff;
+    int8_t iy = val >> 8;
+    fische__vector r;
+    r.x = ix;
+    r.y = iy;
+    return r;
+}
+
+inline void fische__vector_add (fische__vector* self, fische__vector* other)
+{
+    self->x += other->x;
+    self->y += other->y;
+}
+
+inline void fische__vector_sub (fische__vector* self, fische__vector* other)
+{
+    self->x -= other->x;
+    self->y -= other->y;
+}
+
+inline void fische__vector_mul (fische__vector* self, double val)
+{
+    self->x *= val;
+    self->y *= val;
+}
+
+inline void fische__vector_div (fische__vector* self, double val)
+{
+    self->x /= val;
+    self->y /= val;
+}
+
+fische__vector fische__vector_intersect_border (fische__vector* self,
+        fische__vector* normal_vec,
+        uint_fast16_t width,
+        uint_fast16_t height,
+        int_fast8_t direction)
+{
+    width--;
+    height--;
+
+    fische__vector nvec = *normal_vec;
+    if (direction == _FISCHE__VECTOR_RIGHT_) {
+        fische__vector_mul (&nvec, -1);
+    }
+
+    double t1, t2, t3, t4;
+
+    if (nvec.x == 0) {
+        t1 = 1e6;
+        t2 = 1e6;
+    } else {
+        t1 = - self->x / nvec.x;
+        t2 = (width - self->x) / nvec.x;
+    }
+
+    if (nvec.y == 0) {
+        t3 = 1e6;
+        t4 = 1e6;
+    } else {
+        t3 = -self->y / nvec.y;
+        t4 = (height - self->y) / nvec.y;
+    }
+
+    t1 = (t1 < 0) ? 1e6 : t1;
+    t2 = (t2 < 0) ? 1e6 : t2;
+    t3 = (t3 < 0) ? 1e6 : t3;
+    t4 = (t4 < 0) ? 1e6 : t4;
+
+    double a = (t1 < t2) ? t1 : t2;
+    double b = (t3 < t4) ? t3 : t4;
+
+    double min_t = (a < b) ? a : b;
+
+    int_fast16_t ret_x = self->x + nvec.x * min_t;
+    while (ret_x < 0) ret_x ++;
+    while ( (unsigned) ret_x > width) ret_x --;
+
+    int_fast16_t ret_y = self->y + nvec.y * min_t;
+    while (ret_y < 0) ret_y ++;
+    while ( (unsigned) ret_y > height) ret_y --;
+
+    fische__vector r;
+    r.x = ret_x;
+    r.y = ret_y;
+    return r;
+}
diff --git a/xbmc/visualizations/fishBMC/vector.h b/xbmc/visualizations/fishBMC/vector.h
new file mode 100644 (file)
index 0000000..7f81afd
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef F_VECTOR_H
+#define F_VECTOR_H
+
+#include <math.h>
+#include <stdint.h>
+
+struct _fische__vector_ {
+    double x;
+    double y;
+};
+
+typedef struct _fische__vector_ fische__vector;
+typedef struct _fische__vector_ fische__point;
+
+enum {_FISCHE__VECTOR_LEFT_, _FISCHE__VECTOR_RIGHT_};
+
+double          fische__vector_length (fische__vector* self);
+fische__vector  fische__vector_normal (fische__vector* self);
+fische__vector  fische__vector_single (fische__vector* self);
+double          fische__vector_angle (fische__vector* self);
+uint16_t        fische__vector_to_uint16 (fische__vector* self);
+fische__vector  fische__vector_from_uint16 (uint16_t val);
+void            fische__vector_add (fische__vector* self, fische__vector* other);
+void            fische__vector_sub (fische__vector* self, fische__vector* other);
+void            fische__vector_mul (fische__vector* self, double val);
+void            fische__vector_div (fische__vector* self, double val);
+
+fische__vector  fische__vector_intersect_border (fische__vector* self,
+        fische__vector* normal_vec,
+        uint_fast16_t width,
+        uint_fast16_t height,
+        int_fast8_t direction);
+
+#endif
diff --git a/xbmc/visualizations/fishBMC/vectorfield.c b/xbmc/visualizations/fishBMC/vectorfield.c
new file mode 100644 (file)
index 0000000..e34e02b
--- /dev/null
@@ -0,0 +1,414 @@
+#include "fische_internal.h"
+
+#include <stdlib.h>
+#include <pthread.h>
+#include <string.h>
+
+#ifdef DEBUG
+#include <stdio.h>
+#endif
+
+#define N_FIELDS 20
+
+struct field_param {
+    uint16_t*           data;
+    uint_fast8_t        number;
+    uint_fast16_t       start_y;
+    uint_fast16_t       end_y;
+    struct _fische__vectorfield_* vecfield;
+};
+
+unsigned int rand_seed;
+
+inline void
+_fische__vectorfield_randomize_ (fische__vector* vec)
+{
+    vec->x += rand_r (&rand_seed) % 3;
+    vec->x -= 1;
+    vec->y += rand_r (&rand_seed) % 3;
+    vec->y -= 1;
+}
+
+
+inline void
+_fische__vectorfield_validate_ (struct _fische__vectorfield_* P,
+                                fische__vector* vec,
+                                double x,
+                                double y)
+{
+    while (x + vec->x < 2)
+        vec->x += 1;
+    while (x + vec->x > P->width - 3)
+        vec->x -= 1;
+    while (y + vec->y < 2)
+        vec->y += 1;
+    while (y + vec->y > P->height - 2)
+        vec->y -= 1;
+}
+
+void*
+_fische__fill_thread_ (void* arg)
+{
+    struct field_param* params = arg;
+    uint16_t* field = params->data;
+    int fieldno = params->number;
+    struct _fische__vectorfield_* P = params->vecfield;
+
+    uint_fast16_t y;
+    for (y = params->start_y; y < params->end_y; y ++) {
+
+        uint_fast16_t x;
+        for (x = 0; x < P->width; x++) {
+
+            uint16_t* vector = field + x + y * P->width;
+
+            // distance and direction relative to center
+            fische__vector rvec;
+            rvec.x = x;
+            rvec.x -= P->center_x;
+            rvec.y = y;
+            rvec.y -= P->center_y;
+
+            fische__vector e = fische__vector_single (&rvec);
+            fische__vector n = fische__vector_normal (&e);
+
+            double r = fische__vector_length (&rvec) / P->dimension;
+
+            // distance and direction relative to left co-center
+            fische__vector rvec_left;
+            rvec_left.x = (double)x - P->center_x + P->width / 3 * P->fische->scale;
+            rvec_left.y = (double)y - P->center_y;
+
+            fische__vector e_left = fische__vector_single (&rvec_left);
+            fische__vector n_left = fische__vector_normal (&e_left);
+
+            double r_left = fische__vector_length (&rvec_left) / P->dimension;
+
+            // distance and direction relative to right co-center
+            fische__vector rvec_right;
+            rvec_right.x = (double)x - P->center_x - P->width / 3 * P->fische->scale;
+            rvec_right.y = (double)y - P->center_y;
+
+            fische__vector e_right = fische__vector_single (&rvec_right);
+            fische__vector n_right = fische__vector_normal (&e_right);
+
+            double r_right = fische__vector_length (&rvec_right) / P->dimension;
+
+            double speed = P->dimension / 45;
+
+            // correction factors ensure consistent average speeds with all field types
+            // double const corr[] = {0.77, 0.92, 1.72, 2.06, 1.45, 1.45, 1.73, 1.18, 3.24, 2.76, 0.82, 1.21, 1.73, 3.55, 0.47, 0.66, 0.96, 0.97, 1.00, 1.00};
+            double const corr[] =    {0.83, 0.83, 1.56, 1.56, 1.08, 3.54, 1.56, 1.00, 4.47, 2.77, 0.74, 1.01, 1.56, 3.12, 0.67, 0.67, 0.83, 2.43, 1.21, 0.77};
+
+            fische__vector v;
+            switch (fieldno) {
+
+                case 0:
+                    // linear vectors showing away from a horizontal mirror axis
+                    v.x = 0;
+                    v.y = (y < P->center_y) ? speed * corr[fieldno] : -speed * corr[fieldno];
+                    break;
+
+                case 1:
+                    // linear vectors showing away from a vertical mirror axis
+                    v.x = (x < P->center_x) ? speed * corr[fieldno] : -speed * corr[fieldno];
+                    v.y = 0;
+                    break;
+
+                case 2:
+                    // radial vectors showing away from the center
+                    v = e;
+                    fische__vector_mul (&v, -r * speed * corr[fieldno]);
+                    break;
+
+                case 3:
+                    // tangential vectors (right)
+                    v = n;
+                    fische__vector_mul (&v, r * speed * corr[fieldno]);
+                    break;
+
+                case 4: {
+                    // tangential-radial vectors (left)
+                    fische__vector _v1 = n;
+                    fische__vector_mul (&_v1, -r * speed * corr[fieldno]);
+                    v = e;
+                    fische__vector_mul (&v, -r * speed * corr[fieldno]);
+                    fische__vector_add (&v, &_v1);
+                    break;
+                }
+
+                case 5: {
+                    // tree rings
+                    double dv = cos (M_PI * 24 * r);
+                    v = e;
+                    fische__vector_mul (&v, speed * 0.33 * corr[fieldno] * dv);
+                    break;
+                }
+
+                case 6: {
+                    // hyperbolic vectors
+                    v.x = e.y;
+                    v.y = e.x;
+                    fische__vector_mul (&v, -r * speed * corr[fieldno]);
+                    break;
+                }
+
+                case 7:
+                    // purely random
+                    v.x = rand_r (&rand_seed) % (int_fast32_t) (2 * speed * corr[fieldno] + 1) - (speed * corr[fieldno]);
+                    v.y = rand_r (&rand_seed) % (int_fast32_t) (2 * speed * corr[fieldno] + 1) - (speed * corr[fieldno]);
+                    break;
+
+                case 8: {
+                    // sphere
+                    double dv = cos (M_PI * r);
+                    v = e;
+                    fische__vector_mul (&v, -r * dv * speed * corr[fieldno]);
+                    break;
+                }
+
+                case 9: {
+                    // sine distortion
+                    double dv = sin (M_PI * 8 * r);
+                    v = e;
+                    fische__vector_mul (&v, -r * dv * speed * corr[fieldno]);
+                    break;
+                }
+
+                case 10: {
+                    // black hole
+                    fische__vector _v1 = n;
+                    fische__vector_mul (&_v1, speed * corr[fieldno]);
+                    v = e;
+                    fische__vector_mul (&v, r * speed * corr[fieldno]);
+                    fische__vector_add (&v, &_v1);
+                    if (r * P->dimension < 10) {
+                        v.x = 0;
+                        v.y = 0;
+                    }
+                    break;
+                }
+
+                case 11: {
+                    // circular waves
+                    double dim = pow (11 * M_PI, 2);
+                    double _r = r * dim;
+                    v = e;
+                    fische__vector_mul (&v, -speed * corr[fieldno] * sqrt (1.04 - pow (cos (sqrt (_r)), 2) + 0.25 * pow (sin (sqrt (_r)), 2)));
+                    break;
+                }
+
+                case 12:
+                    // spinning CD
+                    v = n;
+                    if (fabs (r - 0.25) < 0.15)
+                        fische__vector_mul (&v, r * speed * corr[fieldno]);
+                    else
+                        fische__vector_mul (&v, -r * speed * corr[fieldno]);
+                    break;
+
+                case 13: {
+                    // three spinning disks
+                    double rt = 0.3;
+                    if (r < rt * 1.2) {
+                        v = n;
+                        fische__vector_mul (&v, -r * speed * corr[fieldno]);
+                    } else if (r_left < rt) {
+                        v = n_left;
+                        fische__vector_mul (&v, r_left * speed * corr[fieldno]);
+                    } else if (r_right < rt) {
+                        v = n_right;
+                        fische__vector_mul (&v, r_right * speed * corr[fieldno]);
+                    } else {
+                        v.x = 0;
+                        v.y = 0;
+                    }
+                    break;
+                }
+
+                case 14: {
+                    // 3-centered fields - radial
+                    fische__vector _v1 = e_left;
+                    fische__vector_mul (&_v1, (2 - r_left) * speed * corr[fieldno]);
+                    fische__vector _v2 = e_right;
+                    fische__vector_mul (&_v2, (2 - r_right)  * speed * corr[fieldno]);
+                    v = e;
+                    fische__vector_mul (&v, (2 - r) * -speed * corr[fieldno]);
+                    fische__vector_add (&v, &_v1);
+                    fische__vector_add (&v, &_v2);
+                    break;
+                }
+
+                case 15: {
+                    // 3-centered fields - tangential
+                    fische__vector _v1 = n_left;
+                    fische__vector_mul (&_v1, (2 - r_left) * -speed * corr[fieldno]);
+                    fische__vector _v2 = n_right;
+                    fische__vector_mul (&_v2, (2 - r_right)  * -speed * corr[fieldno]);
+                    v = n;
+                    fische__vector_mul (&v, (2 - r) * speed * corr[fieldno]);
+                    fische__vector_add (&v, &_v1);
+                    fische__vector_add (&v, &_v2);
+                    break;
+                }
+
+                case 16: {
+                    // lenses effect
+                    double _r = r *    8 * M_PI;
+                    fische__vector _v1 = e;
+                    fische__vector_mul (&_v1, sin (_r) * -speed * corr[fieldno]);
+                    v = n;
+                    fische__vector_mul (&v,  sin (8 * fische__vector_angle (&e)) * -speed * corr[fieldno]);
+                    fische__vector_add (&v, &_v1);
+                    break;
+                }
+
+                case 17: {
+                    // lenses effect
+                    double _r = r *    24 * M_PI;
+                    fische__vector _v1 = e;
+                    fische__vector_mul (&_v1, sin (_r) * -speed * 0.33 * corr[fieldno]);
+                    v = n;
+                    fische__vector_mul (&v,  sin (24 * fische__vector_angle (&e)) * -speed * 0.33 * corr[fieldno]);
+                    fische__vector_add (&v, &_v1);
+                    break;
+                }
+
+                case 18: {
+                    // fan 1
+                    v = e;
+                    double angle = fische__vector_angle (&e);
+                    fische__vector_mul (&v, -speed * corr[fieldno] * sin (8 * angle));
+                    break;
+                }
+
+                case 19: {
+                    // fan 1
+                    v = e;
+                    double angle = fische__vector_angle (&e);
+                    fische__vector_mul (&v, -speed * corr[fieldno] * (1.1 + sin (8 * angle)));
+                    break;
+                }
+
+                default:
+                    // index too high. return nothing.
+                    return 0;
+            }
+
+            if (P->fische->blur_mode == FISCHE_BLUR_FUZZY)
+                _fische__vectorfield_randomize_ (&v);
+
+            _fische__vectorfield_validate_ (P, &v, x, y);
+            *vector = fische__vector_to_uint16 (&v);
+        }
+    }
+    return 0;
+}
+
+void
+_fische__fill_field_ (struct _fische__vectorfield_* P, uint_fast8_t fieldno)
+{
+    uint16_t* field = P->fields + fieldno * P->fieldsize / 2;
+
+    // threads maximum is 8
+    pthread_t vec_threads[8];
+    struct field_param params[8];
+
+    uint_fast8_t i;
+    for (i = 0; i < P->threads; ++ i) {
+        params[i].data = field;
+        params[i].number = fieldno;
+        params[i].start_y = (i * P->height) / P->threads;
+        params[i].end_y = ( (i + 1) * P->height) / P->threads;
+        params[i].vecfield = P;
+
+        pthread_create (&vec_threads[i], NULL, _fische__fill_thread_, &params[i]);
+    }
+
+    for (i = 0; i < P->threads; ++ i) {
+        pthread_join (vec_threads[i], NULL);
+    }
+}
+
+struct fische__vectorfield*
+fische__vectorfield_new (struct fische* parent,
+                         double* progress,
+                         uint_fast8_t* cancel) {
+
+    struct fische__vectorfield* retval = malloc (sizeof (struct fische__vectorfield));
+    retval->priv = malloc (sizeof (struct _fische__vectorfield_));
+    struct _fische__vectorfield_* P = retval->priv;
+
+    rand_seed = time (NULL);
+    *progress = 0;
+
+    P->fische = parent;
+    P->width = parent->width;
+    P->height = parent->height;
+    P->center_x = P->width / 2;
+    P->center_y = P->height / 2;
+    P->dimension = P->width < P->height ? P->width * P->fische->scale : P->height * P->fische->scale;
+    P->fieldsize = P->width * P->height * sizeof (int16_t);
+    P->threads = parent->used_cpus;
+    P->cancelled = 0;
+
+    // if we have stored fields, load them
+    if (parent->read_vectors) {
+        size_t bytes = parent->read_vectors ( (void**) (&P->fields));
+        if (bytes) {
+            *progress = 1;
+            P->n_fields = bytes / P->fieldsize;
+            retval->field = P->fields;
+            return retval;
+        }
+    }
+
+    // if not, recalculate everything
+    P->fields = malloc (N_FIELDS * P->fieldsize);
+    P->n_fields = N_FIELDS;
+
+    uint_fast8_t i;
+    for (i = 0; i < N_FIELDS; ++i) {
+        if (*cancel) {
+            P->cancelled = 1;
+            break;
+        }
+        _fische__fill_field_ (P, i);
+        *progress = (i + 1);
+        *progress /= N_FIELDS;
+    }
+
+    *progress = 1;
+
+    retval->field = P->fields;
+
+    return retval;
+}
+
+void
+fische__vectorfield_free (struct fische__vectorfield* self)
+{
+    if (!self)
+        return;
+
+    struct _fische__vectorfield_* P = self->priv;
+
+    if (!P->cancelled && P->fische->write_vectors) {
+        P->fische->write_vectors (P->fields, P->n_fields * P->fieldsize);
+    }
+
+    free (self->priv->fields);
+    free (self->priv);
+    free (self);
+}
+
+void
+fische__vectorfield_change (struct fische__vectorfield* self)
+{
+    struct _fische__vectorfield_* P = self->priv;
+
+    uint16_t* n = self->field;
+    while (n == self->field) {
+        self->field = P->fields + rand() % P->n_fields * P->width * P->height;
+    }
+}
diff --git a/xbmc/visualizations/fishBMC/vectorfield.h b/xbmc/visualizations/fishBMC/vectorfield.h
new file mode 100644 (file)
index 0000000..7e6f706
--- /dev/null
@@ -0,0 +1,42 @@
+#ifndef VECTORFIELD_H
+#define VECTORFIELD_H
+
+#include <stdint.h>
+
+struct fische;
+struct _fische__vectorfield_;
+struct fische__vectorfield;
+
+
+
+struct fische__vectorfield* fische__vectorfield_new (struct fische* parent, double* progress, uint_fast8_t* cancel);
+void                        fische__vectorfield_free (struct fische__vectorfield* self);
+
+void                        fische__vectorfield_change (struct fische__vectorfield* self);
+
+
+
+struct _fische__vectorfield_ {
+    uint16_t*          fields;
+    uint_fast32_t       fieldsize;
+    uint_fast16_t       width;
+    uint_fast16_t       height;
+    uint_fast16_t       dimension;
+    uint_fast16_t       center_x;
+    uint_fast16_t       center_y;
+    uint_fast8_t        threads;
+    uint_fast8_t        n_fields;
+    uint_fast8_t        cancelled;
+
+    struct fische*    fische;
+};
+
+
+
+struct fische__vectorfield {
+    uint16_t* field;
+
+    struct _fische__vectorfield_* priv;
+};
+
+#endif
diff --git a/xbmc/visualizations/fishBMC/wavepainter.c b/xbmc/visualizations/fishBMC/wavepainter.c
new file mode 100644 (file)
index 0000000..a2593b8
--- /dev/null
@@ -0,0 +1,314 @@
+#include "fische_internal.h"
+
+#include <math.h>
+#include <stdlib.h>
+
+#ifdef DEBUG
+#include <stdio.h>
+#endif
+
+struct fische__wavepainter*
+fische__wavepainter_new (struct fische* parent) {
+
+    struct fische__wavepainter* retval = malloc (sizeof (struct fische__wavepainter));
+    retval->priv = malloc (sizeof (struct _fische__wavepainter_));
+    struct _fische__wavepainter_* P = retval->priv;
+
+    P->fische = parent;
+
+    uint32_t full_alpha = 0xff << FISCHE_PRIVATE (P)->screenbuffer->priv->alpha_shift;
+
+    P->width = parent->width;
+    P->height = parent->height;
+    P->angle = 0;
+    P->center_x = P->width / 2;
+    P->center_y = P->height / 2;
+    P->color_1 = (rand() % 0xffffffff) | full_alpha;
+    P->color_2 = (~P->color_1) | full_alpha;
+    P->direction = 1;
+    P->is_rotating = 0;
+    P->n_shapes = 2;
+    P->rotation_increment = 0;
+    P->shape = 0;
+
+    return retval;
+}
+
+void
+fische__wavepainter_free (struct fische__wavepainter* self)
+{
+    if (!self)
+        return;
+
+    free (self->priv);
+    free (self);
+}
+
+void
+fische__wavepainter_paint (struct fische__wavepainter* self,
+                           double* data,
+                           uint_fast16_t size)
+{
+    if (!size)
+        return;
+
+    struct _fische__wavepainter_* P = self->priv;
+
+    // rotation
+    if (P->is_rotating) {
+        P->angle += P->rotation_increment;
+        if ( (P->angle > 2 * M_PI) || (P->angle < -2 * M_PI)) {
+            P->angle = 0;
+            P->is_rotating = 0;
+        }
+    }
+
+    // only init fische scale once
+    static double f_scale = 0;
+    if (f_scale == 0)
+        f_scale = P->fische->scale;
+
+    // necessary parameters
+    double dim = (P->height < P->width) ? P->height : P->width;
+    dim *= f_scale;
+    double factor = pow (10, P->fische->amplification / 10);
+    double scale = 6 / dim / factor;
+
+    // alpha saturation fix
+    struct fische__screenbuffer* sbuf = FISCHE_PRIVATE (P)->screenbuffer;
+    fische__screenbuffer_line (sbuf, 0, 0, P->width - 1, 0, 0);
+    fische__screenbuffer_line (sbuf, P->width - 1, 0, P->width - 1, P->height - 1, 0);
+    fische__screenbuffer_line (sbuf, P->width - 1, P->height - 1, 0, P->height - 1, 0);
+    fische__screenbuffer_line (sbuf, 0, P->height - 1, 0, 0, 0);
+
+    switch (P->shape) {
+
+        case 0: {
+            fische__point center;
+            center.x = P->center_x;
+            center.y = P->center_y;
+
+            // base will be the middle of a line,
+            // normally horizontal (angle = 0), but could be rotating
+            fische__point base1;
+            base1.x = center.x + (dim / 6) * sin (P->angle);
+            base1.y = center.y + (dim / 6) * cos (P->angle);
+
+            fische__point base2;
+            base2.x = P->width / 2 - (dim / 6) * sin (P->angle);
+            base2.y = P->height / 2 - (dim / 6) * cos (P->angle);
+
+            // create vectors perpendicular to the line center->base
+            fische__vector _nvec1 = base1;
+            fische__vector_sub (&_nvec1, &center);
+            fische__vector nvec1 = fische__vector_normal (&_nvec1);
+
+            fische__vector _nvec2 = base2;
+            fische__vector_sub (&_nvec2, &center);
+            fische__vector nvec2 = fische__vector_normal (&_nvec2);
+
+            // find the points where the line would exit the screen
+            fische__point start1 = fische__vector_intersect_border (&base1, &nvec1, P->width, P->height, _FISCHE__VECTOR_LEFT_);
+            fische__point end1 = fische__vector_intersect_border (&base1, &nvec1, P->width, P->height, _FISCHE__VECTOR_RIGHT_);
+
+            fische__point start2 = fische__vector_intersect_border (&base2, &nvec2, P->width, P->height, _FISCHE__VECTOR_LEFT_);
+            fische__point end2 = fische__vector_intersect_border (&base2, &nvec2, P->width, P->height, _FISCHE__VECTOR_RIGHT_);
+
+            // determine the direction and length (i.e. vector)
+            // of the increment between two sound samples
+            fische__vector v1 = end1;
+            fische__vector_sub (&v1, &start1);
+            fische__vector_div (&v1, size);
+
+            fische__vector v2 = end2;
+            fische__vector_sub (&v2, &start2);
+            fische__vector_div (&v2, size);
+
+            // determine the normal vectors
+            // for calculating the sound sample offset (amplitude)
+            fische__vector _n1 = fische__vector_normal (&v1);
+            fische__vector n1 = fische__vector_single (&_n1);
+            fische__vector _n2 = fische__vector_normal (&v2);
+            fische__vector n2 = fische__vector_single (&_n2);
+
+            // draw both lines
+            fische__point base_p1 = start1;
+            fische__point base_p2 = start2;
+
+            uint_fast16_t i;
+            for (i = 0; i < size - 1; i ++) {
+                fische__point pt11 = base_p1;
+                fische__vector offset11 = n1;
+                fische__vector_mul (&offset11, (* (data + 2 * i)));
+                fische__vector_div (&offset11, scale);
+                fische__vector_add (&pt11, &offset11);
+
+                fische__point pt21 = base_p2;
+                fische__vector offset21 = n2;
+                fische__vector_mul (&offset21, (* (data + 1 + 2 * i)));
+                fische__vector_div (&offset21, scale);
+                fische__vector_add (&pt21, &offset21);
+
+                fische__vector_add (&base_p1, &v1);
+                fische__vector_add (&base_p2, &v2);
+
+                fische__point pt12 = base_p1;
+                fische__vector offset12 = n1;
+                fische__vector_mul (&offset12, (* (data + 2 * (i + 1))));
+                fische__vector_div (&offset12, scale);
+                fische__vector_add (&pt12, &offset12);
+
+                fische__point pt22 = base_p2;
+                fische__vector offset22 = n2;
+                fische__vector_mul (&offset22, (* (data + 1 + 2 * (i + 1))));
+                fische__vector_div (&offset22, scale);
+                fische__vector_add (&pt22, &offset22);
+
+                fische__screenbuffer_line (sbuf, pt11.x, pt11.y, pt12.x, pt12.y, P->color_1);
+                fische__screenbuffer_line (sbuf, pt21.x, pt21.y, pt22.x, pt22.y, P->color_2);
+            }
+            return;
+        }
+
+        // circular shape
+        case 1: {
+            double f = cos (M_PI / 3 + 2 * P->angle) + 0.5;
+            double e = 1;
+
+            uint_fast16_t i;
+            for (i = 0; i < size - 1; i ++) {
+
+                double incr = i;
+
+                // calculate angles for this and the next sound sample
+                double phi1 = M_PI * (0.25 + incr / size) + P->angle;
+                double phi2 = phi1 + M_PI / size;
+
+                // calculate the corresponding radius
+                double r1 = dim / 4 + * (data + 2 * i) / scale;
+                double r2 = dim / 4 + * (data + 2 * (i + 1)) / scale;
+
+                uint_fast16_t x1 = floor ( (P->center_x + f * r1 * sin (phi1)) + 0.5);
+                uint_fast16_t x2 = floor ( (P->center_x + f * r2 * sin (phi2)) + 0.5);
+                uint_fast16_t y1 = floor ( (P->center_y + e * r1 * cos (phi1)) + 0.5);
+                uint_fast16_t y2 = floor ( (P->center_y + e * r2 * cos (phi2)) + 0.5);
+
+                fische__screenbuffer_line (sbuf, x1, y1, x2, y2, P->color_1);
+
+                // the second line will be exactly on the
+                // opposite side of the circle
+                phi1 += M_PI;
+                phi2 += M_PI;
+
+                r1 = dim / 4 + * (data + 1 + 2 * i) / scale;
+                r2 = dim / 4 + * (data + 1 + 2 * (i + 1)) / scale;
+
+                x1 = floor ( (P->center_x + f * r1 * sin (phi1)) + 0.5);
+                x2 = floor ( (P->center_x + f * r2 * sin (phi2)) + 0.5);
+                y1 = floor ( (P->center_y + e * r1 * cos (phi1)) + 0.5);
+                y2 = floor ( (P->center_y + e * r2 * cos (phi2)) + 0.5);
+
+                fische__screenbuffer_line (sbuf, x1, y1, x2, y2, P->color_2);
+            }
+            return;
+        }
+    }
+
+}
+
+void
+fische__wavepainter_beat (struct fische__wavepainter* self, double frames_per_beat)
+{
+    struct _fische__wavepainter_* P = self->priv;
+    if (!P->is_rotating) {
+        if (frames_per_beat != 0) {
+            P->direction = 1 - 2 * (rand() % 2);
+            P->rotation_increment = M_PI / frames_per_beat / 2 * P->direction;
+            P->angle = 0;
+            P->is_rotating = 1;
+        }
+    }
+
+}
+
+void
+fische__wavepainter_change_color (struct fische__wavepainter* self,
+                                  double frames_per_beat,
+                                  double energy)
+{
+    struct _fische__wavepainter_* P = self->priv;
+
+    uint32_t full_alpha = 0xff << FISCHE_PRIVATE (P)->screenbuffer->priv->alpha_shift;
+
+    if (!frames_per_beat && !energy) {
+        P->color_1 = (rand() % 0xffffffff) | full_alpha;
+        P->color_2 = (~P->color_1) | full_alpha;
+    }
+
+    if (!frames_per_beat)
+        return;
+
+    double hue = frames_per_beat / 2;
+    while (hue >= 6)
+        hue -= 6;
+
+    double sv = (energy > 1) ? 1 : pow (energy, 4);
+    double x = sv * (1 - fabs ( (int_fast32_t) hue % 2 - 1));
+
+    double r, g, b;
+
+    switch ( (int_fast32_t) hue) {
+        case 0:
+            r = sv;
+            g = x;
+            b = 0;
+            break;
+        case 1:
+            r = x;
+            g = sv;
+            b = 0;
+            break;
+        case 2:
+            r = 0;
+            g = sv;
+            b = x;
+            break;
+        case 3:
+            r = 0;
+            g = x;
+            b = sv;
+            break;
+        case 4:
+            r = x;
+            g = 0;
+            b = sv;
+            break;
+        default:
+        case 5:
+            r = sv;
+            g = 0;
+            b = x;
+    }
+
+    uint32_t red = floor (r * 255 + 0.5);
+    uint32_t green = floor (b * 255 + 0.5);
+    uint32_t blue = floor (g * 255 + 0.5);
+
+    P->color_1 = (blue << FISCHE_PRIVATE (P)->screenbuffer->priv->blue_shift)
+                 + (green << FISCHE_PRIVATE (P)->screenbuffer->priv->green_shift)
+                 + (red << FISCHE_PRIVATE (P)->screenbuffer->priv->red_shift)
+                 + (0xff << FISCHE_PRIVATE (P)->screenbuffer->priv->alpha_shift);
+
+    P->color_2 = (~P->color_1) | full_alpha;
+}
+
+void
+fische__wavepainter_change_shape (struct fische__wavepainter* self)
+{
+    struct _fische__wavepainter_* P = self->priv;
+
+    if (P->is_rotating) return;
+    int_fast8_t n = P->shape;
+    while (n == P->shape) n = rand() % P->n_shapes;
+    P->shape = n;
+}
diff --git a/xbmc/visualizations/fishBMC/wavepainter.h b/xbmc/visualizations/fishBMC/wavepainter.h
new file mode 100644 (file)
index 0000000..9167fc6
--- /dev/null
@@ -0,0 +1,43 @@
+#ifndef WAVEPAINTER_H
+#define WAVEPAINTER_H
+
+#include <stdint.h>
+
+struct fische;
+struct _fische__wavepainter_;
+struct fische__wavepainter;
+
+
+
+struct fische__wavepainter* fische__wavepainter_new (struct fische* parent);
+void                        fische__wavepainter_free (struct fische__wavepainter* self);
+
+void                        fische__wavepainter_paint (struct fische__wavepainter* self, double* data, uint_fast16_t size);
+void                        fische__wavepainter_beat (struct fische__wavepainter* self, double bpm);
+void                        fische__wavepainter_change_color (struct fische__wavepainter* self, double bpm, double energy);
+void                        fische__wavepainter_change_shape (struct fische__wavepainter* self);
+
+
+
+struct _fische__wavepainter_ {
+    uint_fast16_t   width;
+    uint_fast16_t   height;
+    uint_fast16_t   center_x;
+    uint_fast16_t   center_y;
+    int_fast8_t     direction;
+    uint_fast8_t    shape;
+    uint_fast8_t    n_shapes;
+    uint32_t        color_1;
+    uint32_t        color_2;
+    double          angle;
+    uint_fast8_t    is_rotating;
+    double          rotation_increment;
+
+    struct fische* fische;
+};
+
+struct fische__wavepainter {
+    struct _fische__wavepainter_* priv;
+};
+
+#endif
index b093d07..2800a34 100644 (file)
@@ -71,12 +71,12 @@ BEGIN
         BEGIN
             VALUE "CompanyName", "Team XBMC"
             VALUE "FileDescription", "XBMC"
-            VALUE "FileVersion", "12.0-RC3"
+            VALUE "FileVersion", "13.0-ALPHA1"
             VALUE "InternalName", "XBMC.exe"
             VALUE "LegalCopyright", "Copyright (c) Team XBMC.  All rights reserved."
             VALUE "OriginalFilename", "XBMC.exe"
             VALUE "ProductName", "XBMC for Windows"
-            VALUE "ProductVersion", "12.0-RC3"
+            VALUE "ProductVersion", "13.0-ALPHA1"
         END
     END
     BLOCK "VarFileInfo"
index c6383e3..f9873f8 100644 (file)
@@ -57,7 +57,6 @@ HWND g_hWnd = NULL;
 #define EXTKEYPAD(keypad) ((scancode & 0x100)?(mvke):(keypad))
 
 static XBMCKey VK_keymap[XBMCK_LAST];
-static HKL hLayoutUS = NULL;
 
 static GUID USB_HID_GUID = { 0x4D1E55B2, 0xF16F, 0x11CF, { 0x88, 0xCB, 0x00, 0x11, 0x11, 0x00, 0x00, 0x30 } };
 
@@ -80,10 +79,6 @@ void DIB_InitOSKeymap()
 
   GetKeyboardLayoutName(current_layout);
 
-  hLayoutUS = LoadKeyboardLayout("00000409", KLF_NOTELLSHELL);
-  if (!hLayoutUS)
-    hLayoutUS = GetKeyboardLayout(0);
-
   LoadKeyboardLayout(current_layout, KLF_ACTIVATE);
 
   /* Map the VK keysyms */
@@ -237,10 +232,6 @@ void DIB_InitOSKeymap()
 
 static int XBMC_MapVirtualKey(int scancode, int vkey)
 {
-// It isn't clear why the US keyboard layout was being used. This causes
-// problems with e.g. the \ key. I have provisionally switched the code
-// to use the Windows layout.
-// int mvke = MapVirtualKeyEx(scancode & 0xFF, 1, hLayoutUS);
   int mvke = MapVirtualKeyEx(scancode & 0xFF, 1, NULL);
 
   switch(vkey)