aboutsummaryrefslogtreecommitdiff
path: root/Src/Plugins/Input/in_mp3/graphics
diff options
context:
space:
mode:
Diffstat (limited to 'Src/Plugins/Input/in_mp3/graphics')
-rw-r--r--Src/Plugins/Input/in_mp3/graphics/filterWater.cpp452
-rw-r--r--Src/Plugins/Input/in_mp3/graphics/filterWater.h47
-rw-r--r--Src/Plugins/Input/in_mp3/graphics/image.cpp209
-rw-r--r--Src/Plugins/Input/in_mp3/graphics/image.h61
-rw-r--r--Src/Plugins/Input/in_mp3/graphics/imageFilters.cpp91
-rw-r--r--Src/Plugins/Input/in_mp3/graphics/imageFilters.h17
6 files changed, 877 insertions, 0 deletions
diff --git a/Src/Plugins/Input/in_mp3/graphics/filterWater.cpp b/Src/Plugins/Input/in_mp3/graphics/filterWater.cpp
new file mode 100644
index 00000000..d6128738
--- /dev/null
+++ b/Src/Plugins/Input/in_mp3/graphics/filterWater.cpp
@@ -0,0 +1,452 @@
+#include ".\filterwater.h"
+#include <math.h>
+
+#define random( min, max ) (( rand() % (int)((( max ) + 1 ) - ( min ))) + ( min ))
+
+MLImageFilterWater::MLImageFilterWater(void)
+{
+ hField1 = NULL;
+ hField2 = NULL;
+ hHandle = NULL;
+
+ width = 0;
+ height = 0;
+
+ drawWithLight = TRUE;
+ lightModifier = 1;
+ hPage = 0;
+ density = 5;
+
+}
+
+MLImageFilterWater::~MLImageFilterWater(void)
+{
+ ClearData();
+}
+
+void MLImageFilterWater::ClearData(void)
+{
+ if (hHandle)
+ {
+ if (hField1) HeapFree(hHandle, NULL, hField1);
+ if (hField2) HeapFree(hHandle, NULL, hField2);
+ HeapDestroy(hHandle);
+ hField1 = NULL;
+ hField2 = NULL;
+ hHandle = NULL;
+ }
+
+}
+
+BOOL MLImageFilterWater::CreateFor(const MLImage *image)
+{
+ ClearData();
+ width = image->GetWidth();
+ height = image->GetHeight();
+ hPage = 0;
+ int len = height * width * sizeof(int);
+ hHandle = HeapCreate(NULL, 3*len, 3*len);
+ if (!hHandle)
+ {
+ width = 0;
+ height = 0;
+ return FALSE;
+ }
+
+ hField1 = (int*)HeapAlloc(hHandle, HEAP_ZERO_MEMORY, len);
+ hField2 = (int*)HeapAlloc(hHandle, HEAP_ZERO_MEMORY, len);
+ return hField1 && hField2;
+}
+
+void MLImageFilterWater::Render(MLImage* destination, const MLImage* source)
+{
+ if(!drawWithLight) DrawWaterNoLight(hPage, destination, source);
+ else DrawWaterWithLight(destination, source);
+ CalculateWater(hPage, density);
+// CalcWaterBigFilter(hPage, density);
+ hPage ^= 1;
+}
+
+void MLImageFilterWater::CalculateWater(int page, int density)
+{
+ int newh;
+ int count = width + 1;
+ int *newptr;
+ int *oldptr;
+
+ if(page == 0)
+ {
+ newptr = hField1;
+ oldptr = hField2;
+ }
+ else
+ {
+ newptr = hField2;
+ oldptr = hField1;
+ }
+
+ int x, y;
+ for (y = (height - 1) * width; count < y; count += 2)
+ {
+ for (x = count + width - 2; count < x; count++)
+ {
+ // This does the eight-pixel method.
+
+ newh = ((oldptr[count + width]
+ + oldptr[count - width]
+ + oldptr[count + 1]
+ + oldptr[count - 1]
+ + oldptr[count - width - 1]
+ + oldptr[count - width + 1]
+ + oldptr[count + width - 1]
+ + oldptr[count + width + 1]
+ ) >> 2 )
+ - newptr[count];
+ newptr[count] = newh - (newh >> density);
+ /*
+ // This is the "sludge" method...
+ newh = (oldptr[count]<<2)
+ + oldptr[count-1-m_iWidth]
+ + oldptr[count+1-m_iWidth]
+ + oldptr[count-1+m_iWidth]
+ + oldptr[count+1+m_iWidth]
+ + ((oldptr[count-1]
+ + oldptr[count+1]
+ + oldptr[count-m_iWidth]
+ + oldptr[count+m_iWidth])<<1);
+
+ newptr[count] = (newh-(newh>>6)) >> density;
+ */
+ }
+ }
+}
+
+void MLImageFilterWater::SmoothWater(int page)
+{
+ int newh;
+ int count = width + 1;
+
+ int *newptr;
+ int *oldptr;
+
+ if(page == 0)
+ {
+ newptr = hField1;
+ oldptr = hField2;
+ }
+ else
+ {
+ newptr = hField2;
+ oldptr = hField1;
+ }
+
+ int x, y;
+
+ for(y = 1; y < height; y++, count += 2)
+ {
+ for( x = 1; x < width; x++, count++)
+ {
+ // This does the eight-pixel method.
+
+ newh = ((oldptr[count + width]
+ + oldptr[count - width]
+ + oldptr[count + 1]
+ + oldptr[count - 1]
+ + oldptr[count - width - 1]
+ + oldptr[count - width + 1]
+ + oldptr[count + width - 1]
+ + oldptr[count + width + 1]
+ ) >> 3 )
+ + newptr[count];
+ newptr[count] = newh>>1;
+ }
+ }
+}
+void MLImageFilterWater::FlattenWater(void)
+{
+ int len = width * height * sizeof(int);
+ SecureZeroMemory(hField1, len);
+ SecureZeroMemory(hField2, len);
+}
+void MLImageFilterWater::SineBlob(int x, int y, int radius, int height, int page)
+{
+ int cx, cy;
+ int left,top,right,bottom;
+ double square, dist;
+ double radsquare = radius * radius;
+ double length = double((1024.0/(double)radius)*(1024.0/(double)radius));
+ int *newptr;
+
+ if(page == 0)
+ {
+ newptr = hField1;
+ }
+ else
+ {
+ newptr = hField2;
+ }
+
+ int t = (this->width - 2*radius - 1);
+ if (t == 0) t = 1;
+ if(x<0) x = 1 + radius + rand() % t;
+ t = (this->height - 2*radius - 1);
+ if (t == 0) t = 1;
+ if(y<0) y = 1 + radius + rand() % t;
+
+ radsquare = (radius*radius);
+
+ left = -radius; right = radius;
+ top = -radius; bottom = radius;
+
+ // Perform edge clipping...
+ if(x - radius < 1) left -= (x-radius-1);
+ if(y - radius < 1) top -= (y-radius-1);
+ if(x + radius > this->width - 1) right -= (x + radius - this->width + 1);
+ if(y + radius > this->height - 1) bottom -= (y + radius - this->height + 1);
+
+ for(cy = top; cy < bottom; cy++)
+ {
+ for(cx = left; cx < right; cx++)
+ {
+ square = cy*cy + cx*cx;
+ if(square < radsquare)
+ {
+ dist = sqrt(square*length);
+ newptr[this->width*(cy+y) + cx+x] += (int)((cos(dist)+0xffff)*(height)) >> 19;
+ }
+ }
+ }
+}
+
+void MLImageFilterWater::WarpBlob(int x, int y, int radius, int height, int page)
+{
+ int cx, cy;
+ int left,top,right,bottom;
+ int square;
+ int radsquare = radius * radius;
+ int *newptr;
+
+ if(page == 0)
+ {
+ newptr = hField1;
+ }
+ else
+ {
+ newptr = hField2;
+ }
+
+ radsquare = (radius*radius);
+
+ height /= 64;
+
+ left=-radius; right = radius;
+ top=-radius; bottom = radius;
+
+ // Perform edge clipping...
+ if(x - radius < 1) left -= (x-radius-1);
+ if(y - radius < 1) top -= (y-radius-1);
+ if(x + radius > this->width-1) right -= (x+ radius - this->width + 1);
+ if(y + radius > this->height-1) bottom-= (y + radius - this->height + 1);
+
+ for(cy = top; cy < bottom; cy++)
+ {
+ for(cx = left; cx < right; cx++)
+ {
+ square = cy*cy + cx*cx;
+ if(square < radsquare)
+ {
+ newptr[this->width*(cy+y) + cx+x] += int((radius-sqrt((float)square))*(float)(height));
+ }
+ }
+ }
+}
+void MLImageFilterWater::HeightBox (int x, int y, int radius, int height, int page)
+{
+ int cx, cy;
+ int left,top,right,bottom;
+ int *newptr;
+
+ if(page == 0)
+ {
+ newptr = hField1;
+ }
+ else
+ {
+ newptr = hField2;
+ }
+
+ int t = (this->width - 2*radius - 1);
+ if (t == 0) t = 1;
+ if(x<0) x = 1 + radius + rand() % t;
+ t = (this->height - 2*radius - 1);
+ if (t == 0) t = 1;
+ if(y<0) y = 1 + radius + rand() % t;
+
+ left=-radius; right = radius;
+ top=-radius; bottom = radius;
+
+ // Perform edge clipping...
+ if(x - radius < 1) left -= (x-radius-1);
+ if(y - radius < 1) top -= (y-radius-1);
+ if(x + radius > this->width-1) right -= (x+ radius - this->width + 1);
+ if(y + radius > this->height-1) bottom-= (y + radius - this->height + 1);
+
+ for(cy = top; cy < bottom; cy++)
+ {
+ for(cx = left; cx < right; cx++)
+ {
+ newptr[this->width*(cy+y) + cx+x] = height;
+ }
+ }
+}
+void MLImageFilterWater::HeightBlob(int x, int y, int radius, int height, int page)
+{
+ int rquad;
+ int cx, cy;
+ int left, top, right, bottom;
+
+ rquad = radius * radius;
+
+ // Make a randomly-placed blob...
+ int t = (this->width - 2*radius - 1);
+ if (t == 0) t = 1;
+ if(x<0) x = 1 + radius + rand() % t;
+ t = (this->height - 2*radius - 1);
+ if (t == 0) t = 1;
+ if(y<0) y = 1 + radius + rand() % t;
+
+ left = -radius; right = radius;
+ top = -radius; bottom = radius;
+
+ // Perform edge clipping...
+ if(x - radius < 1) left -= (x-radius-1);
+ if(y - radius < 1) top -= (y-radius-1);
+ if(x + radius > this->width-1) right -= (x+ radius - this->width + 1);
+ if(y + radius > this->height-1) bottom-= (y + radius - this->height + 1);
+
+ for(cy = top; cy < bottom; cy++)
+ {
+ int cyq = cy*cy;
+ for(cx = left; cx < right; cx++)
+ {
+ if(cx*cx + cyq < rquad) newptr[this->width * (cy+y) + (cx+x)] += height;
+ }
+ }
+}
+
+void MLImageFilterWater::CalcWaterBigFilter(int page, int density)
+{
+ int newh;
+ int count = (2 * width) + 2;
+
+ int *newptr;
+ int *oldptr;
+
+ // Set up the pointers
+ if(page == 0)
+ {
+ newptr = hField1;
+ oldptr = hField2;
+ }
+ else
+ {
+ newptr = hField2;
+ oldptr = hField1;
+ }
+
+ int x, y;
+
+ for(y=2; y < height-2; y++, count += 4)
+ {
+ for(x=2; x < width-2; x++, count++)
+ {
+ // This does the 25-pixel method. It looks much okay.
+
+ newh = (
+ (
+ (
+ (oldptr[count + width]
+ + oldptr[count - width]
+ + oldptr[count + 1]
+ + oldptr[count - 1]
+ )<<1)
+ + ((oldptr[count - width - 1]
+ + oldptr[count - width + 1]
+ + oldptr[count + width - 1]
+ + oldptr[count + width + 1]))
+ + ( (
+ oldptr[count - (width*2)]
+ + oldptr[count + (width*2)]
+ + oldptr[count - 2]
+ + oldptr[count + 2]
+ ) >> 1 )
+ + ( (
+ oldptr[count - (width*2) - 1]
+ + oldptr[count - (width*2) + 1]
+ + oldptr[count + (width*2) - 1]
+ + oldptr[count + (width*2) + 1]
+ + oldptr[count - 2 - width]
+ + oldptr[count - 2 + width]
+ + oldptr[count + 2 - width]
+ + oldptr[count + 2 + width]
+ ) >> 2 )
+ )
+ >> 3)
+ - (newptr[count]);
+
+
+ newptr[count] = newh - (newh >> density);
+ }
+ }
+}
+
+void MLImageFilterWater::DrawWaterNoLight(int page, MLImage* destination, const MLImage* source)
+{
+ unsigned int brk = width * height;
+
+ int *ptr = hField1;
+
+ DWORD *dataS = (DWORD*)source->GetData();
+ DWORD *dataD = (DWORD*)destination->GetData();
+
+ for (unsigned int offset = 0; offset < brk; offset++)
+ {
+ int dx = ptr[offset] - ptr[offset + 1];
+ int dy = ptr[offset] - ptr[offset + width];
+ unsigned int index = offset + width * (dy>>3) + (dx>>3);
+ dataD[offset] = (index < brk ) ? dataS[offset + width*(dy>>3) + (dx>>3)] : dataS[offset];
+ }
+}
+
+void MLImageFilterWater::DrawWaterWithLight(MLImage* destination, const MLImage* source)
+{
+ unsigned int brk = width * height;
+
+ int *ptr = hField1;
+
+ DWORD *dataS = (DWORD*)source->GetData();
+ DWORD *dataD = (DWORD*)destination->GetData();
+
+ for (unsigned int offset = 0; offset < brk; offset++)
+ {
+ int dx = ptr[offset] - ptr[offset + 1];
+ int dy = ptr[offset] - ptr[offset + width];
+ unsigned int index = offset + width * (dy>>3) + (dx>>3);
+ dataD[offset] = (index < brk ) ? GetShiftedColor(dataS[index], dx) : dataS[offset];
+ }
+}
+COLORREF MLImageFilterWater::GetShiftedColor(COLORREF color,int shift)
+{
+ int R,G, B;
+ int r, g, b;
+
+ R = GetRValue(color)-shift;
+ G = GetGValue(color)-shift;
+ B = GetBValue(color)-shift;
+
+ r = (R < 0) ? 0 : (R > 255) ? 255 : R;
+ g = (G < 0) ? 0 : (G > 255) ? 255 : G;
+ b = (B < 0) ? 0 : (B > 255) ? 255 : B;
+
+ return RGB(r,g,b);
+}
diff --git a/Src/Plugins/Input/in_mp3/graphics/filterWater.h b/Src/Plugins/Input/in_mp3/graphics/filterWater.h
new file mode 100644
index 00000000..21ed92c0
--- /dev/null
+++ b/Src/Plugins/Input/in_mp3/graphics/filterWater.h
@@ -0,0 +1,47 @@
+#ifndef NULLSOFT_ML_IMAGE_FILTERWATER_HEADER
+#define NULLSOFT_ML_IMAGE_FILTERWATER_HEADER
+
+#include <windows.h>
+#include ".\image.h"
+
+class MLImageFilterWater
+{
+public:
+ MLImageFilterWater(void);
+ ~MLImageFilterWater(void);
+
+public:
+ BOOL CreateFor(const MLImage *image);
+ void Render(MLImage* destination, const MLImage* source);
+
+ void CalculateWater(int page, int density);
+ void SmoothWater(int page);
+ void FlattenWater(void);
+
+ void SineBlob(int x, int y, int radius, int height, int page);
+ void WarpBlob(int x, int y, int radius, int height, int page);
+ void HeightBox (int x, int y, int radius, int height, int page);
+ void HeightBlob(int x, int y, int radius, int height, int page);
+
+protected:
+ void ClearData(void);
+ void CalcWaterBigFilter(int page, int density);
+ void DrawWaterNoLight(int page,MLImage* destination, const MLImage* source);
+ void DrawWaterWithLight(MLImage* destination, const MLImage* source);
+ COLORREF GetShiftedColor(COLORREF color,int shift);
+
+private:
+ HANDLE hHandle;
+ int height;
+ int width;
+
+ BOOL drawWithLight;
+ int lightModifier;
+ int hPage;
+ int density;
+
+ int* hField1;
+ int* hField2;
+};
+
+#endif //#define NULLSOFT_ML_IMAGE_FILTERWATER_HEADER \ No newline at end of file
diff --git a/Src/Plugins/Input/in_mp3/graphics/image.cpp b/Src/Plugins/Input/in_mp3/graphics/image.cpp
new file mode 100644
index 00000000..2e3cda46
--- /dev/null
+++ b/Src/Plugins/Input/in_mp3/graphics/image.cpp
@@ -0,0 +1,209 @@
+#include ".\image.h"
+
+MLImage::MLImage(void)
+{
+ loader = NULL;
+ loaderDelete = TRUE;
+ ResetData();
+}
+
+MLImage::MLImage(IMGLOADFUNC loader, BOOL deleteDone)
+{
+ ResetData();
+ SetLoader(loader, deleteDone, FALSE);
+}
+
+MLImage::MLImage(int width, int height)
+{
+ loader = NULL;
+ ResetData();
+ Init(width,height);
+}
+
+MLImage::~MLImage(void)
+{
+ ResetData();
+}
+
+INT_PTR MLImage::SetLoader(IMGLOADFUNC loader, BOOL deleteDone, BOOL forceLoad)
+{
+ this->loader = loader;
+ this->loaderDelete = deleteDone;
+ if (loader && forceLoad) Load();
+ return (loader != NULL) ? (INT_PTR) this : FALSE;
+}
+
+BOOL MLImage::Load(void)
+{
+ ResetData();
+
+ if (!loader) return FALSE;
+ HBITMAP hbmpLoaded = loader((INT_PTR)this);
+ if(hbmpLoaded == NULL) return FALSE;
+
+ BITMAP bi;
+ if (GetObject(hbmpLoaded, sizeof(bi), &bi))
+ {
+ hbmp = ConvertTo32BppDIB(hbmpLoaded, bi.bmWidth, bi.bmHeight, &info, &data);
+ }
+
+ if (loaderDelete) DeleteObject(hbmpLoaded);
+ return (hbmp != NULL);
+}
+
+void MLImage::ResetData(void)
+{
+ if (hbmp) DeleteObject(hbmp);
+ hbmp = NULL;
+ SecureZeroMemory(&info, sizeof(BITMAPINFO));
+ data = NULL;
+}
+
+BOOL MLImage::Draw(HDC hdcDest, int destX, int destY, int destWidth, int destHeight, int sourceX, int sourceY)
+{
+ if (!hbmp) return FALSE;
+
+ int realheight = abs(info.bmiHeader.biHeight);
+ int rsX = min(sourceX, info.bmiHeader.biWidth);
+ int rsY = min(sourceY, info.bmiHeader.biWidth);
+ int height = min(destHeight, realheight - rsY);
+
+ BOOL bResult = SetDIBitsToDevice( hdcDest, destX, destY,
+ min(destWidth, info.bmiHeader.biWidth - rsX), height,
+ rsX, realheight - height - rsY,
+ 0, height,
+ data, &info, DIB_RGB_COLORS);
+ return bResult;
+}
+
+BOOL MLImage::Draw(HDC hdcDest, int destX, int destY)
+{
+ return (!hbmp) ? FALSE : SetDIBitsToDevice( hdcDest, destX, destY,
+ info.bmiHeader.biWidth, abs(info.bmiHeader.biHeight),
+ 0, 0,
+ 0, abs(info.bmiHeader.biHeight),
+ data, &info, DIB_RGB_COLORS);
+}
+
+int MLImage::GetWidth(void) const
+{
+ return (hbmp) ? info.bmiHeader.biWidth : 0;
+}
+
+int MLImage::GetHeight(void) const
+{
+ return (hbmp) ? abs(info.bmiHeader.biHeight) : 0;
+}
+
+void* MLImage::GetData(void) const
+{
+ return data;
+}
+
+HBITMAP MLImage::ConvertTo32BppDIB(HBITMAP bmpHandle, int bmpWidth, int bmpHeight, LPBITMAPINFO bmpInfo, LPVOID *bmpData)
+{
+ HBITMAP hbmpNew = NULL;
+
+ HDC hdc = GetWindowDC(NULL);
+ HDC hdcTmp = CreateCompatibleDC(hdc);
+ HBITMAP hbmpTmp = CreateCompatibleBitmap(hdc, bmpWidth, bmpHeight);
+ HBITMAP hbmpOld = (HBITMAP) SelectObject(hdcTmp, hbmpTmp);
+
+ // render original bitmap to the temp dc
+ HDC hdcBmp = CreateCompatibleDC(hdc);
+ SelectObject(hdcBmp, bmpHandle);
+ BitBlt(hdcTmp, 0, 0, bmpWidth, bmpHeight, hdcBmp, 0,0, SRCCOPY);
+ SelectObject(hdcBmp, NULL);
+ DeleteDC(hdcBmp);
+
+ // Create a 32 bit bitmap
+ BITMAPINFO bih;
+ // create DIB Section
+ bih.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ bih.bmiHeader.biWidth = bmpWidth;
+ bih.bmiHeader.biHeight = 0 - bmpHeight;
+ bih.bmiHeader.biPlanes = 1;
+ bih.bmiHeader.biBitCount = 32;
+ bih.bmiHeader.biCompression = BI_RGB;
+ bih.bmiHeader.biSizeImage = 0;
+ bih.bmiHeader.biXPelsPerMeter = 0;
+ bih.bmiHeader.biYPelsPerMeter = 0;
+ bih.bmiHeader.biClrUsed = 0;
+ bih.bmiHeader.biClrImportant = 0;
+
+ // Create a DC which will be used to get DIB, then create DIBsection
+ hbmpNew = CreateDIBSection(hdc, (const BITMAPINFO*) &bih, DIB_RGB_COLORS, bmpData, NULL, 0);
+
+
+ DWORD* line = (DWORD*)(*bmpData);
+ // Copy the bits into our 32 bit dib..
+ for(int i=0; i<bmpHeight; i++)
+ {
+ for(int j=0; j<bmpWidth; j++)
+ {
+ line[(i*bmpWidth) + j] = FIXCOLORREF(GetPixel(hdcTmp, j, i));
+ }
+ }
+
+ SelectObject(hdcTmp, hbmpOld);
+ ReleaseDC(NULL, hdc);
+ DeleteDC(hdcTmp);
+
+ memcpy(bmpInfo, &bih, sizeof(BITMAPINFO));
+
+ return hbmpNew;
+}
+
+MLImage* MLImage::Copy(MLImage* destination, const MLImage* original)
+{
+ if (!destination) return NULL;
+
+ destination->ResetData();
+
+ destination->loader = original->loader;
+ destination->loaderDelete = original->loaderDelete;
+ destination->info = original->info;
+ HDC hdc = GetWindowDC(NULL);
+ destination->hbmp = CreateDIBSection(hdc, (const BITMAPINFO*) &destination->info, DIB_RGB_COLORS, &destination->data, NULL, 0);
+
+ CopyMemory(destination->data, original->data, 4*destination->GetHeight() * destination->GetWidth());
+ ReleaseDC(NULL, hdc);
+ return destination;
+}
+
+MLImage* MLImage::Init(int width, int height)
+{
+ ResetData();
+
+ loader = NULL;
+ loaderDelete = TRUE;
+
+ // create DIB Section
+ info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ info.bmiHeader.biWidth = width;
+ info.bmiHeader.biHeight = 0 - height;
+ info.bmiHeader.biPlanes = 1;
+ info.bmiHeader.biBitCount = 32;
+ info.bmiHeader.biCompression = BI_RGB;
+ info.bmiHeader.biSizeImage = 0;
+ info.bmiHeader.biXPelsPerMeter = 0;
+ info.bmiHeader.biYPelsPerMeter = 0;
+ info.bmiHeader.biClrUsed = 0;
+ info.bmiHeader.biClrImportant = 0;
+
+ HDC hdc = GetWindowDC(NULL);
+ hbmp = CreateDIBSection(hdc, (const BITMAPINFO*) &info, DIB_RGB_COLORS, &data, NULL, 0);
+ ReleaseDC(NULL, hdc);
+ return this;
+}
+
+MLImage* MLImage::Init(int width, int height, COLORREF color)
+{
+ Init(width, height);
+
+ int rColor = FIXCOLORREF(color);
+ DWORD *line = (DWORD*)(data);
+ DWORD *end = line + GetHeight() * GetWidth();
+ for(;line != end; line++) *line = rColor;
+ return this;
+} \ No newline at end of file
diff --git a/Src/Plugins/Input/in_mp3/graphics/image.h b/Src/Plugins/Input/in_mp3/graphics/image.h
new file mode 100644
index 00000000..72a4aa5d
--- /dev/null
+++ b/Src/Plugins/Input/in_mp3/graphics/image.h
@@ -0,0 +1,61 @@
+#ifndef NULLSOFT_ML_IMAGE_HEADER
+#define NULLSOFT_ML_IMAGE_HEADER
+
+#include <windows.h>
+
+#define RGBA(r,g,b,a) ((COLORREF)(((BYTE)(r)|((WORD)(g)<<8))|(((DWORD)(BYTE)(b))<<16)|(((DWORD)(BYTE)(a))<<24)))
+#define FIXCOLORREF(clr) RGBA(GetBValue(clr),GetGValue(clr), GetRValue(clr),((DWORD)(clr)) >> 24)
+
+// loader function will be called every time MLImage need to
+// reload picture. Input parameter - handle to the calling object
+// Output - loaded bitmap
+typedef HBITMAP (*IMGLOADFUNC)(INT_PTR handle);
+
+class MLImage
+{
+public:
+ MLImage(void);
+ MLImage(IMGLOADFUNC loader, BOOL deleteDone);
+ MLImage(int width, int height);
+ ~MLImage(void);
+
+public:
+ // sets the loader function and returns handle to the class or NULL if error
+ // loader - pointer to the loader function
+ // deleteDone - if TRUE MLImage will delete HBITMAP object from loader every time it is done loading
+ // forceLoad - forcing to load bitamp immedialty by calling Load()
+ INT_PTR SetLoader(IMGLOADFUNC loader, BOOL deleteDone, BOOL forceLoad);
+ BOOL Load(void); // load image
+
+ MLImage* Init(int width, int height); // init image (allocates memory)
+ MLImage* Init(int width, int height, COLORREF color); // init image (allocates memory) and set
+
+ BOOL Draw(HDC hdcDest, int destX, int destY, int destWidth, int destHeight, int sourceX, int sourceY); // draw image
+ BOOL Draw(HDC hdcDest, int destX, int destY); // draw image
+
+public:
+ int GetWidth(void) const;
+ int GetHeight(void) const;
+ void* GetData(void) const;
+
+
+private:
+ void ResetData(void);
+
+public:
+ static MLImage* Copy(MLImage* destination, const MLImage* original);// copy all data from the original object (including image data) to the destination
+
+private:
+ static HBITMAP ConvertTo32BppDIB(HBITMAP bmpHandle, int bmpWidth, int bmpHeight, LPBITMAPINFO bmpInfo, LPVOID *bmpData);
+
+private:
+ IMGLOADFUNC loader; // pointer to the loader function
+ BOOL loaderDelete; // TRUE - delete HBITMAP from loader after load
+
+ HBITMAP hbmp; // my bitmap
+ BITMAPINFO info;
+ void *data;
+};
+
+#endif // NULLSOFT_ML_IMAGE_HEADER
+
diff --git a/Src/Plugins/Input/in_mp3/graphics/imageFilters.cpp b/Src/Plugins/Input/in_mp3/graphics/imageFilters.cpp
new file mode 100644
index 00000000..59d994ed
--- /dev/null
+++ b/Src/Plugins/Input/in_mp3/graphics/imageFilters.cpp
@@ -0,0 +1,91 @@
+#include ".\imagefilters.h"
+
+void MLImageFilter_GrayScale(MLImage *image)
+{
+ DWORD *line = (DWORD*)(image->GetData());
+ DWORD *end = line + image->GetHeight() * image->GetWidth();
+ for(;line != end; line++)
+ {
+ BYTE y = (BYTE)(0.3f * GetBValue(*line) + 0.59f *GetGValue(*line) + 0.11f *GetRValue(*line));
+ *line = RGB(y,y,y);
+ }
+}
+
+void MLImageFilter_Invert(MLImage *image)
+{
+ DWORD *line = (DWORD*)(image->GetData());
+ DWORD *end = line + image->GetHeight() * image->GetWidth();
+ for(;line != end; line++) *line = ((~*line) & 0x00FFFFFF) | (*line & 0xFF000000);
+}
+
+void MLImageFilter_SetToColor(MLImage *image, COLORREF color)
+{
+ COLORREF rColor = FIXCOLORREF(color);
+ DWORD *line = (DWORD*)(image->GetData());
+ DWORD *end = line + image->GetHeight() * image->GetWidth();
+ for(;line != end; line++) *line = rColor;
+}
+
+void MLImageFilter_Fader1(MLImage *dest, const MLImage* source, COLORREF color)
+{
+ int len = dest->GetHeight() * dest->GetWidth();
+ BYTE r = GetRValue(color), g = GetGValue(color), b = GetBValue(color);
+
+ DWORD *dataS = (DWORD*)(source->GetData());
+ DWORD *dataD = (DWORD*)(dest->GetData());
+ DWORD *end = dataD + len;
+ for(;dataD != end; dataD++, dataS++)
+ {
+ *dataD = RGB( max(b, GetRValue(*dataS)), max(g, GetGValue(*dataS)), max(r, GetBValue(*dataS))) ;
+ }
+}
+
+void MLImageFilter_Fader2(MLImage *dest, const MLImage* source, COLORREF color)
+{
+ int len = dest->GetHeight() * dest->GetWidth();
+ BYTE r = GetRValue(color), g = GetGValue(color), b = GetBValue(color);
+
+ DWORD *dataS = (DWORD*)(source->GetData());
+ DWORD *dataD = (DWORD*)(dest->GetData());
+ DWORD *end = dataD + len;
+ for(;dataD != end; dataD++, dataS++)
+ {
+ *dataD = RGB( min(b, GetRValue(*dataS)), min(g, GetGValue(*dataS)), min(r, GetBValue(*dataS))) ;
+ }
+}
+
+void MLImageFilter_Fader3(MLImage *dest, const MLImage* source, int koeff)
+{
+ int len = dest->GetHeight() * dest->GetWidth();
+
+ DWORD *dataS = (DWORD*)(source->GetData());
+ DWORD *dataD = (DWORD*)(dest->GetData());
+ DWORD *end = dataD + len;
+ for(;dataD != end; dataD++, dataS++)
+ {
+ *dataD = RGB(min(255,GetRValue(*dataS) + koeff), min(255,GetGValue(*dataS) + koeff), min(255, GetBValue(*dataS) + koeff));
+ }
+}
+
+void MLImageFilter_Blend1(MLImage *dest, MLImage *src1, int destX, int destY, int width, int height, const MLImage* src2, int srcX, int srcY, COLORREF color)
+{
+ int widthS1 = src1->GetWidth();
+ int widthS2 = src2->GetWidth();
+
+ DWORD *dataD = (DWORD*)(dest->GetData()) + destY * widthS1 + destX;
+ DWORD *dataS1 = (DWORD*)(src1->GetData()) + destY * widthS1 + destX;
+ DWORD *dataS2 = (DWORD*)(src2->GetData()) + srcY * widthS2 + srcX;
+
+ DWORD *curS1;
+
+ for (int y = 0; y < height; y++)
+ {
+ DWORD *curD = dataD + y * widthS1;
+ curS1 = dataS1 + y * widthS1;
+ DWORD *curS2 = dataS2 + y * widthS2;
+ for (DWORD *end = curS1 + width; end != curS1; curD++, curS1++, curS2++)
+ {
+ *curD = (*curS1 == color) ? *curS2 : *curS1;
+ }
+ }
+} \ No newline at end of file
diff --git a/Src/Plugins/Input/in_mp3/graphics/imageFilters.h b/Src/Plugins/Input/in_mp3/graphics/imageFilters.h
new file mode 100644
index 00000000..ebb1c752
--- /dev/null
+++ b/Src/Plugins/Input/in_mp3/graphics/imageFilters.h
@@ -0,0 +1,17 @@
+#ifndef NULLSOFT_ML_IMAGE_FILTER_HEADER
+#define NULLSOFT_ML_IMAGE_FILTER_HEADER
+
+#include <windows.h>
+#include ".\image.h"
+#include ".\filterwater.h"
+
+void MLImageFilter_GrayScale(MLImage *image);
+void MLImageFilter_Invert(MLImage *image);
+void MLImageFilter_SetToColor(MLImage *image, COLORREF color);
+void MLImageFilter_Fader1(MLImage *dest, const MLImage* source, COLORREF color);
+void MLImageFilter_Fader2(MLImage *dest, const MLImage* source, COLORREF color);
+void MLImageFilter_Fader3(MLImage *dest, const MLImage* source, int koeff);
+void MLImageFilter_Blend1(MLImage *dest, MLImage *src1, int destX, int destY, int width, int height, const MLImage* src2, int srcX, int srcY, COLORREF color);
+
+
+#endif //NULLSOFT_ML_IMAGE_FILTER_HEADER