aboutsummaryrefslogtreecommitdiff
path: root/Src/tataki
diff options
context:
space:
mode:
Diffstat (limited to 'Src/tataki')
-rw-r--r--Src/tataki/api__tataki.h41
-rw-r--r--Src/tataki/bitmap/autobitmap.cpp201
-rw-r--r--Src/tataki/bitmap/autobitmap.h106
-rw-r--r--Src/tataki/bitmap/bitmap.h7
-rw-r--r--Src/tataki/bitmap/ifc_bitmap.h51
-rw-r--r--Src/tataki/bitmap/mac/osx_bitmap_cgimage.cpp219
-rw-r--r--Src/tataki/bitmap/mac/osx_bitmap_cgimage.h48
-rw-r--r--Src/tataki/bitmap/win/bitmap.cpp1874
-rw-r--r--Src/tataki/bitmap/win/bitmap.h113
-rw-r--r--Src/tataki/blending/blending.cpp54
-rw-r--r--Src/tataki/blending/blending.h542
-rw-r--r--Src/tataki/canvas/PaintCanvas.h3
-rw-r--r--Src/tataki/canvas/bltcanvas.h5
-rw-r--r--Src/tataki/canvas/canvas.h5
-rw-r--r--Src/tataki/canvas/ifc_canvas.cpp1
-rw-r--r--Src/tataki/canvas/ifc_canvas.h165
-rw-r--r--Src/tataki/canvas/mac/PaintCanvas.cpp51
-rw-r--r--Src/tataki/canvas/mac/PaintCanvas.h46
-rw-r--r--Src/tataki/canvas/mac/bltcanvas.h27
-rw-r--r--Src/tataki/canvas/mac/canvas.h70
-rw-r--r--Src/tataki/canvas/mac/osx_canvas_layer.cpp95
-rw-r--r--Src/tataki/canvas/mac/osx_canvas_quartz.cpp275
-rw-r--r--Src/tataki/canvas/win/BltCanvas.cpp295
-rw-r--r--Src/tataki/canvas/win/bltcanvas.h41
-rw-r--r--Src/tataki/canvas/win/canvas.h368
-rw-r--r--Src/tataki/canvas/win/win32_canvas.cpp1489
-rw-r--r--Src/tataki/color/filteredcolor.cpp78
-rw-r--r--Src/tataki/color/filteredcolor.h29
-rw-r--r--Src/tataki/color/skinclr.cpp134
-rw-r--r--Src/tataki/color/skinclr.h39
-rw-r--r--Src/tataki/export.h33
-rw-r--r--Src/tataki/main.cpp122
-rw-r--r--Src/tataki/region/api_region.cpp1
-rw-r--r--Src/tataki/region/api_region.h201
-rw-r--r--Src/tataki/region/mac/osx_region_hishape.cpp217
-rw-r--r--Src/tataki/region/mac/region.h116
-rw-r--r--Src/tataki/region/region.h5
-rw-r--r--Src/tataki/region/win/region.h137
-rw-r--r--Src/tataki/region/win/win32_region.cpp813
-rw-r--r--Src/tataki/resource.h14
-rw-r--r--Src/tataki/tataki.rc76
-rw-r--r--Src/tataki/tataki.sln54
-rw-r--r--Src/tataki/tataki.vcxproj311
-rw-r--r--Src/tataki/tataki.vcxproj.filters119
-rw-r--r--Src/tataki/tataki.xcodeproj/project.pbxproj418
-rw-r--r--Src/tataki/version.rc239
46 files changed, 9148 insertions, 0 deletions
diff --git a/Src/tataki/api__tataki.h b/Src/tataki/api__tataki.h
new file mode 100644
index 00000000..89098039
--- /dev/null
+++ b/Src/tataki/api__tataki.h
@@ -0,0 +1,41 @@
+#ifndef NULLSOFT_TATAKI_API_H
+#define NULLSOFT_TATAKI_API_H
+
+#include <api/service/api_service.h>
+//extern api_service *serviceManager;
+//#define WASABI_API_SVC serviceManager
+
+#include <api/application/api_application.h>
+#define WASABI_API_APP applicationApi
+
+#include <api/syscb/api_syscb.h>
+#define WASABI_API_SYSCB sysCallbackApi
+
+#include <api/font/api_font.h>
+#define WASABI_API_FONT fontApi
+
+#include <api/wnd/api_wnd.h>
+#define WASABI_API_WND wndApi
+
+#include <api/config/api_config.h>
+#define WASABI_API_CONFIG configApi
+
+#include <api/imgldr/api_imgldr.h>
+#define WASABI_API_IMGLDR imgLoaderApi
+
+#include <Agave/Random/api_random.h>
+extern api_random *randomApi;
+#define AGAVE_API_RANDOM randomApi
+
+#include <api/memmgr/api_memmgr.h>
+extern api_memmgr *memoryManager;
+#define WASABI_API_MEMMGR memoryManager
+
+#include <api/skin/api_skin.h>
+#define WASABI_API_SKIN skinApi
+
+#include <api/skin/api_palette.h>
+extern api_palette *paletteManagerApi;
+#define WASABI_API_PALETTE paletteManagerApi
+
+#endif \ No newline at end of file
diff --git a/Src/tataki/bitmap/autobitmap.cpp b/Src/tataki/bitmap/autobitmap.cpp
new file mode 100644
index 00000000..9c85c586
--- /dev/null
+++ b/Src/tataki/bitmap/autobitmap.cpp
@@ -0,0 +1,201 @@
+#include <tataki/api__tataki.h>
+#include "autobitmap.h"
+#include <bfc/assert.h>
+#define TIMER_ID_RESET 0x1664
+
+#ifdef DROP_BITMAP_ON_IDLE
+// these are in seconds
+#define DROP_MINDELAY 3
+#define DROP_MAXDELAY 15
+#define DROP_INITIALBUMP -5
+#define DROP_MINDELAYSINCELASTUSE 7
+#endif
+
+/*
+#ifdef _WIN32
+extern HINSTANCE hInstance;
+#endif
+*/
+
+AutoSkinBitmap::AutoSkinBitmap(const wchar_t *_name)
+{
+ bitmap = NULL;
+ use = 0;
+ id = 0;
+ colorgroup = 0;
+ name = 0;
+ resamplingMode = RESAMPLING_MODE_NONE;
+#ifdef WIN32
+ myInstance = 0;
+#endif
+#ifdef DROP_BITMAP_ON_IDLE
+ lastuse = 0;
+#endif
+ setBitmap(_name);
+}
+
+AutoSkinBitmap::~AutoSkinBitmap()
+{
+#ifdef DROP_BITMAP_ON_IDLE
+ timerclient_killTimer(TIMER_ID_RESET);
+#endif
+ if (bitmap) bitmap->Release();
+ ASSERT(WASABI_API_SYSCB != NULL);
+ WASABI_API_SYSCB->syscb_deregisterCallback(this);
+ free(colorgroup);
+ free(name);
+}
+
+const wchar_t *AutoSkinBitmap::setBitmap(const wchar_t *_name)
+{
+ if (_name == NULL) return NULL;
+ if (name == NULL || wcscmp(name, _name))
+ {
+ reset();
+ free(name);
+ name = _wcsdup(_name);
+ }
+ return name;
+}
+
+int AutoSkinBitmap::setBitmap(int _id)
+{
+ if (_id == 0) return 0;
+ if (_id != id)
+ {
+ reset();
+ id = _id;
+ }
+ return id;
+}
+
+#ifdef _WIN32
+void AutoSkinBitmap::setHInstance(HINSTANCE hinstance)
+{
+ myInstance = hinstance;
+}
+#endif
+
+void AutoSkinBitmap::reset()
+{
+ if (bitmap) bitmap->Release(); bitmap = NULL;
+#ifdef DROP_BITMAP_ON_IDLE
+ timerclient_killTimer(TIMER_ID_RESET);
+#endif
+}
+static int modrandom(int max)
+{
+ int ret = AGAVE_API_RANDOM->GetPositiveNumber();
+ ret %= max;
+ return ret;
+}
+SkinBitmap *AutoSkinBitmap::getBitmap()
+{
+ //FG ASSERT(name != NULL);
+ if ((name == NULL || (name != NULL && *name == NULL)) && id == NULL) return NULL;
+ if (bitmap == NULL)
+ {
+ if (name)
+ {
+ switch (resamplingMode)
+ {
+ case RESAMPLING_MODE_SUPERSAMPLING:
+ bitmap = new HQSkinBitmap(name);
+ break;
+ case RESAMPLING_MODE_NONE:
+ default:
+ bitmap = new SkinBitmap(name);
+ break;
+ }
+ }
+ else
+ {
+#ifdef WIN32
+ switch (resamplingMode)
+ {
+ case RESAMPLING_MODE_SUPERSAMPLING:
+ bitmap = new HQSkinBitmap(myInstance, id, colorgroup);
+ break;
+ case RESAMPLING_MODE_NONE:
+ default:
+ bitmap = new SkinBitmap(myInstance, id, colorgroup);
+ break;
+ }
+#endif
+ }
+ ASSERT(WASABI_API_SYSCB != NULL);
+ if (bitmap)
+ WASABI_API_SYSCB->syscb_registerCallback(this);
+#ifdef DROP_BITMAP_ON_IDLE
+ if (bitmap)
+ {
+ lastuse = GetTickCount() + DROP_INITIALBUMP;
+ timerclient_setTimer(TIMER_ID_RESET, DROP_MINDELAY*1000 + modrandom((DROP_MAXDELAY - DROP_MINDELAY)*1000));
+ return bitmap;
+ }
+#endif
+
+ }
+#ifdef DROP_BITMAP_ON_IDLE
+ if (bitmap) lastuse = GetTickCount();
+#endif
+ return bitmap;
+}
+
+const wchar_t *AutoSkinBitmap::getBitmapName()
+{
+ return name;
+}
+
+int AutoSkinBitmap::skincb_onReset()
+{
+ reset();
+ return 1;
+}
+
+void AutoSkinBitmap::setHInstanceBitmapColorGroup(const wchar_t *_colorgroup)
+{
+ free(colorgroup);
+ if (_colorgroup)
+ colorgroup = _wcsdup(_colorgroup);
+ else
+ colorgroup=0;
+}
+
+#ifdef DROP_BITMAP_ON_IDLE
+void AutoSkinBitmap::timerclient_timerCallback(int id)
+{
+ if (id == TIMER_ID_RESET)
+ {
+ tryUnload();
+ }
+ else TimerClientDI::timerclient_timerCallback(id);
+}
+
+void AutoSkinBitmap::tryUnload()
+{
+ DWORD now = GetTickCount();
+ if (now < lastuse + DROP_MINDELAYSINCELASTUSE*1000) return ;
+ reset();
+}
+#endif
+
+void AutoSkinBitmap::setResamplingMode(int mode)
+{
+ this->resamplingMode = mode;
+ this->reset();
+}
+
+int AutoSkinBitmap::getResamplingMode()
+{
+ return this->resamplingMode;
+}
+
+
+#define CBCLASS AutoSkinBitmap
+START_DISPATCH;
+ CB(SYSCALLBACK_GETEVENTTYPE, getEventType);
+ CB(SYSCALLBACK_NOTIFY, notify);
+END_DISPATCH;
+#undef CBCLASS
+
diff --git a/Src/tataki/bitmap/autobitmap.h b/Src/tataki/bitmap/autobitmap.h
new file mode 100644
index 00000000..c1303b3c
--- /dev/null
+++ b/Src/tataki/bitmap/autobitmap.h
@@ -0,0 +1,106 @@
+#ifndef _AUTOBITMAP_H
+#define _AUTOBITMAP_H
+
+#include "bitmap.h"
+#include <api/syscb/callbacks/syscb.h>
+#include <api/syscb/callbacks/skincb.h>
+#include <tataki/export.h>
+
+#ifdef DROP_BITMAP_ON_IDLE
+#include <api/timer/timerclient.h>
+#define DROP_BITMAP_ANCESTOR , public TimerClientDI
+#else
+#define DROP_BITMAP_ANCESTOR
+#endif
+
+
+class TATAKIAPI AutoSkinBitmap : public SysCallback DROP_BITMAP_ANCESTOR {
+public:
+ AutoSkinBitmap(const wchar_t *_name=NULL);
+ virtual ~AutoSkinBitmap();
+
+ const wchar_t *setBitmap(const wchar_t *_name=NULL);
+ int setBitmap(int _id=0);
+
+ // call this when you get freeResources called on you
+ // doesn't hurt to call as much as you want
+ void reset();
+ void reload() { getBitmap(); } // force a reload
+
+ // this loads the bitmap if necessary
+ SkinBitmap *getBitmap();
+ operator SkinBitmap *() { return getBitmap(); }
+
+ const wchar_t *operator =(const wchar_t *_name) { return setBitmap(_name); }
+ int operator =(int _id) { return setBitmap(_id); }
+
+ const wchar_t *getBitmapName();
+
+ void setHInstanceBitmapColorGroup(const wchar_t *_colorgroup);
+
+ enum
+ {
+ RESAMPLING_MODE_NONE = 0,
+ RESAMPLING_MODE_SUPERSAMPLING = 1,
+ };
+
+ void setResamplingMode(int mode);
+ int getResamplingMode();
+
+ // feel free to add more methods here to help make using this class
+ // transparent...
+ int getWidth() { return getBitmap()->getWidth(); };
+ int getHeight() { return getBitmap()->getHeight(); };
+ void stretchToRectAlpha(ifc_canvas *canvas, RECT *r, int alpha=255) {
+ getBitmap()->stretchToRectAlpha(canvas, r, alpha);
+ }
+ void stretchToRectAlpha(ifc_canvas *canvas, RECT *r, RECT *dest, int alpha=255) {
+ getBitmap()->stretchToRectAlpha(canvas, r, dest, alpha);
+ }
+ void stretchToRect(ifc_canvas *canvas, RECT *r) {
+ getBitmap()->stretchToRect(canvas, r);
+ }
+ void blitAlpha(ifc_canvas *canvas, int x, int y, int alpha=255) {
+ getBitmap()->blitAlpha(canvas, x, y, alpha);
+ }
+
+#ifdef _WIN32
+ void setHInstance(HINSTANCE hinstance); // use this if you use autoskinbitmap and resource in a wac
+#endif
+#ifdef DROP_BITMAP_ON_IDLE
+ virtual void timerclient_timerCallback(int id);
+#endif
+
+protected:
+ FOURCC getEventType() { return SysCallback::SKINCB; }
+ int notify(int msg, intptr_t param1 = 0, intptr_t param2 = 0)
+ {
+ if (msg == SkinCallback::RESET)
+ return skincb_onReset();
+ else
+ return 0;
+ }
+
+ int skincb_onReset();
+#ifdef DROP_BITMAP_ON_IDLE
+ virtual void tryUnload();
+#endif
+
+private:
+ int use;
+ int id;
+ wchar_t *name;
+ wchar_t *colorgroup;
+ SkinBitmap *bitmap;
+ int resamplingMode;
+#ifdef _WIN32
+ HINSTANCE myInstance;
+#endif
+#ifdef DROP_BITMAP_ON_IDLE
+ uint32_t lastuse;
+#endif
+protected:
+ RECVS_DISPATCH;
+};
+
+#endif
diff --git a/Src/tataki/bitmap/bitmap.h b/Src/tataki/bitmap/bitmap.h
new file mode 100644
index 00000000..3eced689
--- /dev/null
+++ b/Src/tataki/bitmap/bitmap.h
@@ -0,0 +1,7 @@
+#ifdef _WIN32
+#include "win/bitmap.h"
+#elif defined(__APPLE__)
+#include "mac/osx_bitmap_cgimage.h"
+#else
+#error port me
+#endif \ No newline at end of file
diff --git a/Src/tataki/bitmap/ifc_bitmap.h b/Src/tataki/bitmap/ifc_bitmap.h
new file mode 100644
index 00000000..560d13a4
--- /dev/null
+++ b/Src/tataki/bitmap/ifc_bitmap.h
@@ -0,0 +1,51 @@
+#ifndef NULLSOFT_WASABI_IFC_BITMAP_H
+#define NULLSOFT_WASABI_IFC_BITMAP_H
+
+#include <bfc/dispatch.h>
+#include <bfc/platform/types.h>
+#include <bfc/platform/platform.h>
+
+#warning move this typedef to bfc/platform/platform.h
+#ifdef _WIN32
+typedef HBITMAP OSBITMAPHANDLE;
+#elif defined(__APPLE__)
+typedef CGImageRef OSBITMAPHANDLE;
+#else
+#error port me
+#endif
+
+class ifc_bitmap : public Dispatchable
+{
+protected:
+ ifc_bitmap() {}
+ ~ifc_bitmap() {}
+public:
+ OSBITMAPHANDLE GetBitmap();
+ uint8_t *GetBits();
+ void UpdateBits(uint8_t *bits); // call to signify that you've modified the underlying bits.
+
+ DISPATCH_CODES
+ {
+ IFC_BITMAP_GETBITMAP = 10,
+ IFC_BITMAP_GETBITS = 20,
+ IFC_BITMAP_UPDATEBITS = 30,
+ };
+};
+
+
+inline OSBITMAPHANDLE ifc_bitmap::GetBitmap()
+{
+ return _call(IFC_BITMAP_GETBITMAP, (OSBITMAPHANDLE)0);
+}
+
+inline uint8_t *ifc_bitmap::GetBits()
+{
+ return _call(IFC_BITMAP_GETBITS, (uint8_t *)0);
+}
+
+inline void ifc_bitmap::UpdateBits(uint8_t *bits)
+{
+ _voidcall(IFC_BITMAP_UPDATEBITS, bits);
+}
+
+#endif \ No newline at end of file
diff --git a/Src/tataki/bitmap/mac/osx_bitmap_cgimage.cpp b/Src/tataki/bitmap/mac/osx_bitmap_cgimage.cpp
new file mode 100644
index 00000000..9e1c33c2
--- /dev/null
+++ b/Src/tataki/bitmap/mac/osx_bitmap_cgimage.cpp
@@ -0,0 +1,219 @@
+#include "osx_bitmap_cgimage.h"
+
+SkinBitmap::SkinBitmap(ARGB32 *_bits, int w, int h) : image(0)
+{
+ // TODO: allow a mechanism for SkinBitmap to take ownership of the data
+ bits = malloc(w*h*4);
+ if (bits)
+ {
+ memcpy(bits, _bits, w*h*4);
+ CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
+ imageContext = CGBitmapContextCreate(bits, w, h, 8, w*4, colorSpace, kCGBitmapByteOrder32Little|kCGImageAlphaPremultipliedFirst);
+ image = CGBitmapContextCreateImage(imageContext);
+ CGColorSpaceRelease(colorSpace);
+ }
+}
+
+SkinBitmap::~SkinBitmap()
+{
+ CGImageRelease(image);
+#ifndef SKINBITMAP_USE_CGIMAGE
+ free(bits);
+ CGContextRelease(imageContext);
+#endif
+}
+
+#ifdef WASABI_COMPILE_IMGLDR
+SkinBitmap::SkinBitmap(const wchar_t *elementname, int _cached)
+{
+ ASSERT(elementname!= NULL);
+
+ bitmapname = elementname;
+ x_offset = -1;
+ y_offset = -1;
+ subimage_w = -1;
+ subimage_h = -1;
+ fullimage_w=fullimage_h=0;
+ ownbits=1;
+ bits = NULL;
+ fromskin = 0;
+ last_failed = 0;
+#ifdef WASABI_COMPILE_SKIN
+ bits = WASABI_API_IMGLDR->imgldr_requestSkinBitmap(elementname, &has_alpha, &x_offset, &y_offset, &subimage_w, &subimage_h, &fullimage_w, &fullimage_h,_cached);
+ fromskin = (bits != NULL);
+#endif
+ if (bits == NULL)
+ bits = WASABI_API_IMGLDR->imgldr_makeBmp(elementname, &has_alpha, &fullimage_w, &fullimage_h);
+#ifdef WASABI_COMPILE_SKIN
+ if (bits == NULL)
+ {
+ bits = WASABI_API_IMGLDR->imgldr_requestSkinBitmap(ERRORBMP, &has_alpha, &x_offset, &y_offset, &subimage_w, &subimage_h, &fullimage_w, &fullimage_h,_cached);
+ last_failed = 1;
+ }
+#endif
+ if (bits == NULL)
+ {
+ bits = WASABI_API_IMGLDR->imgldr_makeBmp(HARDERRORBMP, &has_alpha, &fullimage_w, &fullimage_h);
+ last_failed = 1;
+ }
+
+ // check that coordinates are correct
+ if(x_offset!=-1 && x_offset>fullimage_w) x_offset=fullimage_w-1;
+ if(y_offset!=-1 && y_offset>fullimage_h) y_offset=fullimage_h-1;
+ if(subimage_w!=-1 && (x_offset+subimage_w)>fullimage_w) subimage_w=fullimage_w-x_offset;
+ if(subimage_h!=-1 && (y_offset+subimage_h)>fullimage_h) subimage_h=fullimage_h-y_offset;
+
+ // ASSERTPR(bits != NULL, elementname);
+ if (bits == NULL) {
+ DebugString("element not found ! %s\n", elementname);
+ int n = 10*10;
+ bits = (ARGB32 *)WASABI_API_MEMMGR->sysMalloc(n * 4);
+
+
+ ARGB32 *p = bits;
+ while (n--)
+ *p++ = 0xFFFF00FF;
+ }
+}
+#endif
+
+
+int SkinBitmap::getWidth()
+{
+ if (!image)
+ return 0;
+
+ return CGImageGetWidth(image);
+}
+
+int SkinBitmap::getFullWidth()
+{
+ if (!image)
+ return 0;
+
+ return CGImageGetBytesPerRow(image)/4; // assumes 32bit pixel data
+}
+
+int SkinBitmap::getHeight()
+{
+ if (!image)
+ return 0;
+ return CGImageGetHeight(image);
+}
+
+void SkinBitmap::blit(api_canvas *canvas, int x, int y)
+{
+ if (!image)
+ return;
+
+ CGContextRef context = canvas->getHDC();
+ CGRect rect = CGRectMake(x, y, getWidth(), getHeight());
+ CGContextDrawImage(context, rect, image);
+}
+
+void SkinBitmap::blitAlpha(api_canvas *canvas, int x, int y, int alpha)
+{
+ if (!image)
+ return;
+
+ float floatAlpha = alpha / 255.f;
+
+ CGContextRef context = canvas->getHDC();
+ CGContextSaveGState(context);
+
+// CGContextTranslateCTM(context, 0, r->bottom);
+// CGContextScaleCTM(context, 1.0, -1.0);
+
+ CGContextSetAlpha(context, floatAlpha);
+ CGRect rect = CGRectMake(x, y, getWidth(), getHeight());
+ CGContextDrawImage(context, rect, image);
+ CGContextRestoreGState(context);
+}
+
+void SkinBitmap::stretchToRect(api_canvas *canvas, RECT *r)
+{
+ if (!image)
+ return;
+
+ CGContextRef context = canvas->getHDC();
+ CGContextSaveGState(context);
+
+ CGContextTranslateCTM (context, 0, r->bottom);
+ CGContextScaleCTM(context, 1.0, -1.0);
+
+ CGRect rect = CGRectMake(r->left, r->top, r->right-r->left, r->bottom-r->top);
+ CGContextDrawImage(context, rect, image);
+
+ CGContextRestoreGState(context);
+}
+
+void SkinBitmap::stretchToRectAlpha(api_canvas *canvas, RECT *r, int alpha)
+{
+ if (!image)
+ return;
+
+ float floatAlpha = alpha / 255.f;
+
+ CGContextRef context = canvas->getHDC();
+ CGContextSaveGState(context);
+
+ CGContextTranslateCTM (context, 0, r->bottom);
+ CGContextScaleCTM(context, 1.0, -1.0);
+
+ CGContextSetAlpha(context, floatAlpha);
+ CGRect rect = CGRectMake(r->left, r->top, r->right-r->left, r->bottom-r->top);
+ CGContextDrawImage(context, rect, image);
+ CGContextRestoreGState(context);
+}
+
+void SkinBitmap::stretchToRectAlpha(api_canvas *canvas, RECT *src, RECT *dst, int alpha)
+{
+ if (!image)
+ return;
+
+ float floatAlpha = alpha / 255.f;
+
+ // make a new image ref clipped to the source rect
+ CGRect srcRect = CGRectMake(src->left, src->top, src->right-src->left, src->bottom-src->top);
+ CGImageRef clippedImage = CGImageCreateWithImageInRect(image, srcRect);
+
+ // blit onto canvas
+ CGContextRef context = canvas->getHDC();
+ CGContextSaveGState(context);
+
+ CGContextTranslateCTM(context, 0, dst->bottom);
+ CGContextScaleCTM(context, 1.0, -1.0);
+
+ CGContextSetAlpha(context, floatAlpha);
+ CGRect rect = CGRectMake(dst->left, dst->top, dst->right-dst->left, dst->bottom-dst->top);
+ CGContextDrawImage(context, rect, clippedImage);
+ CGContextRestoreGState(context);
+
+ // release the reference to our clipped image
+ CGImageRelease(clippedImage);
+}
+
+uint8_t *SkinBitmap::getBits()
+{
+ return static_cast<uint8_t *>(CGBitmapContextGetData(imageContext));
+}
+
+void SkinBitmap::UpdateBits(uint8_t *bits)
+{
+ CGImageRelease(image);
+ image = CGBitmapContextCreateImage(imageContext);
+}
+
+ARGB32 SkinBitmap::getPixel(int x, int y)
+{
+ ARGB32 *array = (ARGB32 *)getBits();
+ return array[x + y*getFullWidth()];
+}
+
+#define CBCLASS SkinBitmap
+START_DISPATCH;
+CB(IFC_BITMAP_GETBITMAP, GetBitmap);
+CB(IFC_BITMAP_GETBITS, getBits);
+VCB(IFC_BITMAP_UPDATEBITS, UpdateBits);
+END_DISPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/tataki/bitmap/mac/osx_bitmap_cgimage.h b/Src/tataki/bitmap/mac/osx_bitmap_cgimage.h
new file mode 100644
index 00000000..0e842c08
--- /dev/null
+++ b/Src/tataki/bitmap/mac/osx_bitmap_cgimage.h
@@ -0,0 +1,48 @@
+#ifndef NULLSOFT_WASABI_OSX_BITMAP_CGIMAGE_H
+#define NULLSOFT_WASABI_OSX_BITMAP_CGIMAGE_H
+
+#include <tataki/export.h>
+#include <bfc/platform/platform.h>
+#include <tataki/canvas/api_canvas.h>
+#include <api/wnd/ifc_bitmap.h>
+
+/*
+ TODO:
+ need some kind of updateBits() so that the underlying image can be updated to reflect changes
+ */
+class TATAKIAPI SkinBitmap : public ifc_bitmap
+{
+public:
+ SkinBitmap(ARGB32 *bits, int w, int h); // added by benski, use if you have raw image bits
+ SkinBitmap(const wchar_t *elementname, int cached = 1);
+ ~SkinBitmap();
+ int getWidth();
+ int getHeight();
+ int getFullWidth(); // aka pitch
+
+ // blits
+ void blit(api_canvas *canvas, int x, int y);
+ void blitAlpha(api_canvas *canvas, int x, int y, int alpha = 255);
+ // stretch blits
+ void stretchToRect(api_canvas *canvas, RECT *r);
+ void stretchToRectAlpha(api_canvas *canvas, RECT *r, int alpha = 255);
+ void stretchToRectAlpha(api_canvas *canvas, RECT *src, RECT *dst, int alpha = 255);
+// tiled blits
+ void blitTile(api_canvas *canvas, RECT *dest, int xoffs = 0, int yoffs = 0, int alpha = 255);
+
+ ARGB32 getPixel(int x, int y);
+public: // ifc_bitmap implementations
+ OSBITMAPHANDLE GetBitmap() { return image; }
+ uint8_t *getBits();
+ void UpdateBits(uint8_t *bits);
+
+private:
+ CGImageRef image;
+ CGContextRef imageContext;
+ void *bits;
+
+protected:
+ RECVS_DISPATCH;
+};
+
+#endif \ No newline at end of file
diff --git a/Src/tataki/bitmap/win/bitmap.cpp b/Src/tataki/bitmap/win/bitmap.cpp
new file mode 100644
index 00000000..24ea0228
--- /dev/null
+++ b/Src/tataki/bitmap/win/bitmap.cpp
@@ -0,0 +1,1874 @@
+#include <tataki/api__tataki.h>
+
+//#define NO_SIMPLEFASTMODE
+#include <api/imgldr/api_imgldr.h>
+#include <tataki/blending/blending.h>
+
+#include "bitmap.h"
+
+#include <bfc/wasabi_std.h>
+#include <tataki/canvas/bltcanvas.h>
+
+#include <api/memmgr/api_memmgr.h>
+
+
+#if !defined(WIN32) && !defined(LINUX)
+#error port me!
+#endif
+
+#define ERRORBMP L"wasabi.bitmapnotfound"
+#define HARDERRORBMP L"xml/wasabi/window/error.png"
+// do not define NO_MMX in this file. :)
+
+#ifndef NO_MMX
+
+#ifdef WIN32
+#define MMX_CONST const
+#else
+#define MMX_CONST
+#endif
+
+static unsigned int MMX_CONST SkinBitmap_mmx_revn2[2]={0x01000100,0x01000100};
+static unsigned int MMX_CONST SkinBitmap_mmx_zero[2];
+static unsigned int MMX_CONST SkinBitmap_mmx_one[2]={1,0};
+#define HAS_MMX Blenders::MMX_AVAILABLE()
+
+#else
+
+//NO_MMX defined
+#define HAS_MMX 0
+
+#endif
+#if 0
+ int bitmap_x = bitmap->getX();
+ int bitmap_y = bitmap->getY();
+ int bmpheight = bitmap->getHeight();
+ int fullimage_w = bitmap->getFullWidth();
+ void *bits = bitmap->getBits();
+ int xp=xe-xs;
+ for (int yp = ys; yp < ye; yp ++)
+ {
+ int t=yv>>16;
+ if (t < 0) t=0;
+ if (t >= bmpheight) t=bmpheight-1;
+ int *psrc=((int*)bits) + (t+bitmap_y)*fullimage_w + bitmap_x;
+ int *dest=((int*)dib) + pitch*yp + xs;
+
+ C::stretch(xp, psrc, dest, xstart, dxv, alpha);
+
+ yv+=dyv;
+ }
+ }
+#endif
+ static __inline int shc(int offset, int offset16, int pos, int delta)
+ {
+ __int64 num = (Int32x32To64(pos, delta) + (__int64)offset16)/65536LL;
+ return (int)(num+offset);
+ }
+
+ static __inline void *ROUNDUP16(void *ptr)
+ {
+ return (void *)(((size_t)ptr+15) & ~15);
+ }
+
+static void Shrink(SkinBitmap *src_, int ys, int ye, int xe, int xs, int xstart, int yv, void *dst_, int dstpitch, int dxv, int dyv, int alpha)
+{
+// to scale an image
+ // where the destination image is both smaller on X *and* Y.
+
+ // inputs:
+ int srcpitch = src_->getFullWidth();
+ int bitmap_x = src_->getX();
+ int bitmap_height = src_->getHeight();
+ int bitmap_fullheight = src_->getFullHeight();
+ int bitmap_y = src_->getY();
+
+ uint8_t *src=(uint8_t *)src_->getBits();;
+ ARGB32 *dst= (ARGB32 *)dst_;
+
+//#define NEW_X(x__) ((srcxs+bitmap_x)+MulDiv(x__, dxv, 65536))
+#define NEW_X(x__) shc(bitmap_x, xstart,(x__), dxv)
+#define NEW_Y(y__) shc(bitmap_y, yv, (y__)-ys, dyv)
+
+ int dstw = xe-xs;
+ // make sure we have enough room. I don't think anyone is going to have destination bitmaps this big, but might as well play it safe
+ ASSERT(dstw <= 4096);
+ if (dstw > 4096) return;
+
+ // all this weird stuff is to align on 16 byte boundary
+ char *_new_x[4096*sizeof(int)+15] = {0};
+ char *new_x_aligned = (char *)_new_x;
+ ROUNDUP16(new_x_aligned);
+ int *new_x = (int *)new_x_aligned;
+ for (int x=0; x<=dstw; x++)
+ new_x[x] = NEW_X(x);
+
+ // FOR EACH DEST PIXEL
+ for (int y=ys; y<ye; y++)
+ {
+ int sy1 = NEW_Y(y);
+ int sy2 = NEW_Y(y+1);
+ for (int x=0; x<dstw; x++)
+ {
+ uint32_t sum[4] = { 0, 0, 0, 0 };
+ int sx1 = new_x[x];
+ int sx2 = new_x[x+1];
+ // FOR EACH CONTRIBUTING SOURCE PIXEL: in a block [sx1..sx2) x [sy1..sy2)
+ for (int b=sy1; b<sy2; b++)
+ for (int a=sx1; a<sx2; a++)
+ {
+ uint8_t *ps = &src[(b*srcpitch + a)*4];
+ sum[0] += (uint32_t)ps[0];
+ sum[1] += (uint32_t)ps[1];
+ sum[2] += (uint32_t)ps[2];
+ sum[3] += (uint32_t)ps[3];
+ }
+ // write downsampled pixel:
+ ARGB32 &dstpix = dst[(y*dstpitch + x+xs)];
+ uint32_t out;
+ uint8_t *pd = (uint8_t *)&out;
+ int pixels_covered = (sy2-sy1)*(sx2-sx1);
+ pd[0] = (uint32_t)(sum[0] / pixels_covered);
+ pd[1] = (uint32_t)(sum[1] / pixels_covered);
+ pd[2] = (uint32_t)(sum[2] / pixels_covered);
+ pd[3] = (uint32_t)(sum[3] / pixels_covered);
+#ifdef NO_MMX
+ dstpix = Blenders::BLEND_ADJ3(dstpix, out, alpha);
+#else
+ dstpix = Blenders::BLEND_ADJ3_MMX(dstpix, out, alpha);
+#endif
+ }
+ }
+}
+
+static wchar_t skinBitmapBlankName[] = L"";
+SkinBitmap::SkinBitmap(HINSTANCE hInstance, int id, const wchar_t *forcegroup)
+{
+ high_quality_resampling = false;
+ references = 1;
+ bitmapname = skinBitmapBlankName;
+ subimage_w = -1;
+ subimage_h = -1;
+ x_offset = -1;
+ y_offset = -1;
+ fullimage_w = fullimage_h = 0;
+ has_alpha = 0;
+ ASSERT(hInstance != NULL);
+ ownbits = 1;
+ fromskin = 0;
+ bits = WASABI_API_IMGLDR->imgldr_makeBmp(hInstance, id,&has_alpha,&fullimage_w,&fullimage_h, forcegroup);
+ last_failed = 0;
+ if (bits == NULL)
+ {
+ //last_failed = 1;
+ //TODO: bits = WASABI_API_IMGLDR->imgldr_requestSkinBitmap(ERRORBMP, &has_alpha, &x_offset, &y_offset, &subimage_w, &subimage_h, &fullimage_w, &fullimage_h,_cached);
+ }
+ if (bits == NULL)
+ {
+ last_failed = 1;
+ bits = WASABI_API_IMGLDR->imgldr_makeBmp(HARDERRORBMP, &has_alpha, &fullimage_w, &fullimage_h);
+ }
+}
+
+SkinBitmap::SkinBitmap(ARGB32 *_bits, int w, int h, bool own)
+{
+ high_quality_resampling = false;
+ references = 1;
+ subimage_w = -1;
+ subimage_h = -1;
+ x_offset = -1;
+ y_offset = -1;
+ bitmapname = skinBitmapBlankName;
+ fullimage_w = w;
+ fullimage_h = h;
+ has_alpha = 1;
+ if (own)
+ ownbits = OWNBITS_USECFREE;
+ else
+ ownbits = OWNBITS_NOTOURS;
+ bits = _bits;
+ fromskin = 0;
+ last_failed = 0;
+}
+
+// TODO: benski> could we be using GetDIBits here?
+void SkinBitmap::bmpToBits(HBITMAP hbmp, HDC defaultDC)
+{
+#ifdef WIN32
+ if (hbmp && !bits)
+ {
+ BITMAPINFO srcbmi={0};
+ HDC hMemDC, hMemDC2;
+ HBITMAP hprev,hprev2=0;
+ HBITMAP hsrcdib;
+ void *srcdib;
+ BITMAP bm;
+ int r = GetObject(hbmp, sizeof(BITMAP), &bm);
+ ASSERT(r != 0);
+
+ fullimage_w=bm.bmWidth;
+ fullimage_h=ABS(bm.bmHeight);
+
+ int bmw=getWidth();
+ int bmh=getHeight();
+ int xo=getX();
+ int yo=getY();
+
+ srcbmi.bmiHeader.biSize=sizeof(srcbmi.bmiHeader);
+ srcbmi.bmiHeader.biWidth=bmw;
+ srcbmi.bmiHeader.biHeight=-bmh;
+ srcbmi.bmiHeader.biPlanes=1;
+ srcbmi.bmiHeader.biBitCount=32;
+ srcbmi.bmiHeader.biCompression=BI_RGB;
+ hMemDC = CreateCompatibleDC(NULL);
+ hsrcdib=CreateDIBSection(hMemDC,&srcbmi,DIB_RGB_COLORS,&srcdib,NULL,0);
+ ASSERTPR(hsrcdib != 0, "CreateDIBSection() failed #6");
+ if (defaultDC)
+ hMemDC2 = defaultDC;
+ else
+ {
+ hMemDC2 = CreateCompatibleDC(NULL);
+ hprev2 = (HBITMAP) SelectObject(hMemDC2, hbmp);
+ }
+ hprev = (HBITMAP) SelectObject(hMemDC, hsrcdib);
+ BitBlt(hMemDC,0,0,bmw,bmh,hMemDC2,xo,yo,SRCCOPY);
+ SelectObject(hMemDC, hprev);
+ if (!defaultDC)
+ {
+ SelectObject(hMemDC2, hprev2);
+ DeleteDC(hMemDC2);
+ }
+ DeleteDC(hMemDC);
+ bits=(ARGB32*)MALLOC(bmw*bmh*4);
+ if (getHeight()+getY() > bm.bmHeight || getWidth()+getX() > bm.bmWidth)
+ {
+ ASSERTALWAYS(StringPrintf("Subbitmap coordinates outside master bitmap [%d,%d,%d,%d in 0,0,%d,%d]", getX(), getY(), getWidth(), getHeight(), bm.bmWidth, bm.bmHeight));
+ }
+ MEMCPY32(bits,srcdib,bmw*bmh/**sizeof(ARGB32)*/);
+ DeleteObject(hsrcdib);
+ x_offset=-1;
+ y_offset=-1;
+ subimage_w=-1;
+ subimage_h=-1;
+ fullimage_w=bmw;
+ fullimage_h=bmh;
+ }
+#endif
+#ifdef LINUX
+ if (! bits)
+ {
+ fullimage_w=hbmp.bmWidth;
+ fullimage_h=ABS(hbmp.bmHeight);
+
+ bits=(ARGB32*)MALLOC_(fullimage_w * fullimage_h * 4);
+ MEMCPY32(bits, hbmp.shmseginfo->shmaddr, fullimage_w * fullimage_h);
+ x_offset=-1;
+ y_offset=-1;
+ subimage_w=-1;
+ subimage_h=-1;
+ }
+#endif
+}
+
+SkinBitmap::SkinBitmap(const wchar_t *elementname, int _cached)
+{
+ ASSERT(elementname!= NULL);
+
+ high_quality_resampling=false;
+ references=1;
+ bitmapname = _wcsdup(elementname);
+ x_offset = -1;
+ y_offset = -1;
+ subimage_w = -1;
+ subimage_h = -1;
+ fullimage_w = fullimage_h = 0;
+ ownbits = OWNBITS_USEIMGLDR;
+ bits = NULL;
+ fromskin = 0;
+ last_failed = 0;
+
+ if (WASABI_API_IMGLDR) // someone might be using us in Classic Skin so explicitly check this
+ {
+ bits = WASABI_API_IMGLDR->imgldr_requestSkinBitmap(elementname, &has_alpha, &x_offset, &y_offset, &subimage_w, &subimage_h, &fullimage_w, &fullimage_h,_cached);
+ fromskin = (bits != NULL);
+
+ if (bits == NULL)
+ bits = WASABI_API_IMGLDR->imgldr_makeBmp(elementname, &has_alpha, &fullimage_w, &fullimage_h);
+
+ if (bits == NULL)
+ {
+ bits = WASABI_API_IMGLDR->imgldr_requestSkinBitmap(ERRORBMP, &has_alpha, &x_offset, &y_offset, &subimage_w, &subimage_h, &fullimage_w, &fullimage_h,_cached);
+ last_failed = 1;
+ }
+
+ if (bits == NULL)
+ {
+ bits = WASABI_API_IMGLDR->imgldr_makeBmp(HARDERRORBMP, &has_alpha, &fullimage_w, &fullimage_h);
+ last_failed = 1;
+ }
+
+ // check that coordinates are correct
+ if (x_offset!=-1 && x_offset>fullimage_w) x_offset=fullimage_w-1;
+ if (y_offset!=-1 && y_offset>fullimage_h) y_offset=fullimage_h-1;
+ if (subimage_w!=-1 && (x_offset+subimage_w)>fullimage_w) subimage_w=fullimage_w-x_offset;
+ if (subimage_h!=-1 && (y_offset+subimage_h)>fullimage_h) subimage_h=fullimage_h-y_offset;
+
+ // ASSERTPR(bits != NULL, elementname);
+ if (bits == NULL)
+ {
+ DebugStringW(L"element not found ! %s\n", elementname);
+ int n = 10*10;
+ bits = (ARGB32 *)WASABI_API_MEMMGR->sysMalloc(n * sizeof(ARGB32));
+ fromskin = OWNBITS_USESYSFREE;
+ ARGB32 *p = bits;
+ while (n--)
+ *p++ = 0xFFFF00FF;
+ }
+ }
+ else
+ last_failed = 1;
+}
+
+SkinBitmap::SkinBitmap(HBITMAP bitmap)
+{
+#ifdef WIN32
+ ASSERT(bitmap != NULL);
+#endif
+ high_quality_resampling = false;
+ references = 1;
+ subimage_w = -1;
+ subimage_h = -1;
+ x_offset = -1;
+ y_offset = -1;
+ bitmapname = skinBitmapBlankName;
+ fullimage_w = fullimage_h = 0;
+ has_alpha = 0;
+ ownbits = OWNBITS_USESTDFREE;
+ bits = NULL;
+ fromskin = 0;
+ last_failed = 0;
+ bmpToBits(bitmap,NULL);
+}
+
+SkinBitmap::SkinBitmap(HBITMAP bitmap, HDC dc, int _has_alpha, void *_bits)
+{
+ high_quality_resampling=false;
+ references=1;
+ subimage_w=-1;
+ subimage_h=-1;
+ x_offset=-1;
+ y_offset=-1;
+ fromskin = 0;
+ last_failed = 0;
+ bitmapname = skinBitmapBlankName;
+ fullimage_w=fullimage_h=0;
+#ifdef WIN32
+ ASSERT(bitmap != NULL);
+#endif
+ has_alpha = _has_alpha;
+ bits = (ARGB32*)_bits;
+ if (!_bits)
+ {
+ ownbits = OWNBITS_USESTDFREE;
+ bmpToBits(bitmap,dc);
+ }
+ else
+ {
+#ifdef WIN32
+ BITMAP bm;
+ ownbits = OWNBITS_NOTOURS;
+ int r = GetObject(bitmap, sizeof(BITMAP), &bm);
+ ASSERT(r != 0);
+ fullimage_w = bm.bmWidth;
+ fullimage_h = ABS(bm.bmHeight);
+#endif
+#ifdef LINUX
+ ownbits = OWNBITS_NOTOURS;
+ fullimage_w = bitmap.bmWidth;
+ fullimage_h = ABS(bitmap.bmHeight);
+#endif
+//port me
+ }
+}
+
+SkinBitmap::SkinBitmap(ifc_canvas *canvas)
+{
+ high_quality_resampling=false;
+ references=1;
+ subimage_w=-1;
+ subimage_h=-1;
+ x_offset=-1;
+ y_offset=-1;
+ bits = NULL;
+
+ void *canvas_bits = canvas->getBits();
+ if (canvas_bits)
+ {
+ canvas->getDim(&subimage_w, &fullimage_h, &fullimage_w);
+ fullimage_w/=4;
+ canvas->getOffsets(&x_offset, &y_offset);
+ size_t copylen = fullimage_h*fullimage_w*sizeof(ARGB32);
+ bits =(ARGB32 *)MALLOC(copylen);
+ memcpy(bits, canvas_bits, copylen);
+ last_failed = 0;
+ ownbits = OWNBITS_USESTDFREE;
+ }
+ else
+ {
+ last_failed = 1;
+ ownbits = OWNBITS_NOTOURS;
+ }
+ subimage_h=-1;
+ bitmapname = skinBitmapBlankName;
+ has_alpha = 1;
+ fromskin = 0;
+}
+
+SkinBitmap::SkinBitmap(int w, int h, ARGB32 bgcolor)
+{
+ high_quality_resampling=false;
+ references=1;
+ subimage_w=-1;
+ subimage_h=-1;
+ x_offset=-1;
+ y_offset=-1;
+ fullimage_w=w;
+ bitmapname = skinBitmapBlankName;
+ fullimage_h=h;
+ fromskin = 0;
+ last_failed = 0;
+
+ int memsize = w*h*sizeof(ARGB32);
+ if (memsize == 0) memsize++; // +1 so no failure when 0x0
+ bits = (ARGB32*)MALLOC(memsize);
+
+ DWORD *dw = (DWORD *)bits;
+ MEMFILL<DWORD>(dw, bgcolor, w*h);
+
+ has_alpha = TRUE;
+ ownbits = OWNBITS_USESTDFREE; // 2 specifies should be FREE()'d
+}
+
+SkinBitmap::~SkinBitmap()
+{
+ if (bits)
+ {
+ switch(ownbits)
+ {
+ case OWNBITS_USESTDFREE:
+ FREE(bits);
+ break;
+ case OWNBITS_USECFREE:
+ free(bits);
+ break;
+ case OWNBITS_USESYSFREE:
+ WASABI_API_MEMMGR->sysFree(bits);
+ break;
+ case OWNBITS_USEIMGLDR:
+ {
+ if (WASABI_API_IMGLDR)
+ {
+ if (fromskin)
+ WASABI_API_IMGLDR->imgldr_releaseSkinBitmap(bits);
+ else
+#ifndef _WASABIRUNTIME
+ WASABI_API_IMGLDR->imgldr_releaseBmp(bits);
+#else
+ WASABI_API_IMGLDR->imgldr_releaseSkinBitmap(bits);
+#endif
+ }
+ }
+ break;
+ }
+ }
+ bits = NULL;
+
+ if (bitmapname && bitmapname != skinBitmapBlankName)
+ free(bitmapname);
+}
+
+void SkinBitmap::blit(ifc_canvas *canvas, int x, int y)
+{
+ RECT src, dst;
+ src.left=0;
+ src.top=0;
+ src.bottom=getHeight();
+ src.right=getWidth();
+ dst.left=x;
+ dst.right=x+getWidth();
+ dst.top=y;
+ dst.bottom=y+getHeight();
+ blitToRect(canvas,&src,&dst,255);
+}
+
+void SkinBitmap::blitRectToTile(ifc_canvas *canvas, RECT *dest, RECT *src, int xoffs, int yoffs, int alpha)
+{
+ int startx,starty;
+
+ int w,h;
+
+ w = src->right-src->left;
+ h = src->bottom-src->top;
+ if (w <= 0 || h <= 0) return; //wtfmf
+
+ RECT c;
+ if (canvas->getClipBox(&c) == NULLREGION)
+ {
+ c = *dest;
+ }
+ else
+ {
+ if (dest->left > c.left) c.left = dest->left;
+ if (dest->top > c.top) c.top = dest->top;
+ if (dest->right < c.right) c.right = dest->right;
+ if (dest->bottom < c.bottom) c.bottom = dest->bottom;
+ }
+
+
+ starty = c.top-((c.top - dest->top) % h)- yoffs;
+ startx = c.left-((c.left - dest->left) % w) - xoffs;
+
+ for (int j=starty;j<c.bottom;j+=h)
+ for (int i=startx;i<c.right;i+=w)
+ {
+ int xp=i;
+ int yp=j;
+ int xo=0;
+ int yo=0;
+ int _w=getWidth();
+ int _h=getHeight();
+ if (xp < c.left)
+ {
+ xo=c.left-xp;
+ _w+=xo;
+ xp=c.left;
+ }
+ if (yp < c.top)
+ {
+ yo=c.top-yp;
+ _h+=yo;
+ yp=c.top;
+ }
+ if (xp + _w >= c.right) _w=c.right-xp;
+ if (yp + _h >= c.bottom) _h=c.bottom-yp;
+ RECT _s={xo, yo, xo+_w, yo+_h};
+ RECT _d={xp, yp, xp+_w, yp+_h};
+ blitToRect(canvas, &_s, &_d, alpha);
+ }
+}
+
+
+void SkinBitmap::blitTile(ifc_canvas *canvas, RECT *dest, int xoffs, int yoffs, int alpha)
+{
+ RECT r={0,0,getWidth(),getHeight()};
+ blitRectToTile(canvas, dest, &r, xoffs, yoffs, alpha);
+}
+
+#ifdef WIN32
+#pragma warning(push)
+#pragma warning(disable : 4799)
+#endif
+
+
+#define DEFAULT_CACHE_WIDTH 64
+#define DEFAULT_CACHE_HEIGHT 64
+
+extern DWORD bitmap_cache_tls;
+
+void SkinBitmap::blitToRect(ifc_canvas *canvas, RECT *src, RECT *dst, int alpha) // only dst(top,left) are used
+{
+ if (alpha <= 0) return;
+ if (alpha > 255) alpha = 255;
+
+ BltCanvas *blitToRectCanvas=0;
+ HDC hdc = canvas->getHDC();
+ if (hdc == NULL) return;
+ void *dib=canvas->getBits();
+ int cwidth,cheight, pitch;
+ BaseCloneCanvas clone(canvas);
+ bool usingBlitCanvas = false;
+ RECT destrect=*dst;
+ destrect.bottom=destrect.top+(src->bottom-src->top);
+ destrect.right=destrect.left+(src->right-src->left);
+
+ RECT c;
+ int ctype=canvas->getClipBox(&c);
+
+ if (c.top > destrect.top) destrect.top=c.top;
+ if (c.left > destrect.left) destrect.left=c.left;
+ if (c.bottom < destrect.bottom) destrect.bottom=c.bottom;
+ if (c.right < destrect.right) destrect.right=c.right;
+
+#ifdef NO_SIMPLEFASTMODE
+ dib=NULL;
+#endif
+
+ if (destrect.right <= destrect.left || destrect.bottom <= destrect.top) return;
+ int xs,yp,xe,ye;
+
+ if (!dib || canvas->getDim(NULL,&cheight,&cwidth) || !cwidth || cheight < 1 || ctype == COMPLEXREGION)
+ {
+ cwidth=destrect.right-destrect.left;
+ cheight=destrect.bottom-destrect.top;
+
+/* create cached canvas for this thread if it doesn't exist */
+ blitToRectCanvas = (BltCanvas *)TlsGetValue(bitmap_cache_tls);
+ if (!blitToRectCanvas)
+ {
+ blitToRectCanvas = new BltCanvas(cwidth, cheight);
+ TlsSetValue(bitmap_cache_tls, (LPVOID)blitToRectCanvas);
+ }
+ int cacheWidth, cacheHeight;
+ blitToRectCanvas->getDim(&cacheWidth, &cacheHeight, NULL);
+
+ /* resize cache if necessary */
+ if (cwidth > cacheWidth || cheight > cacheHeight)
+ {
+ cacheWidth=MAX(cacheWidth, cwidth);
+ cacheHeight=MAX(cacheHeight, cheight);
+ blitToRectCanvas->DestructiveResize(cacheWidth, cacheHeight);
+ }
+
+ dib = blitToRectCanvas->getBits();
+ if (has_alpha || alpha < 255)
+ clone.blit(destrect.left, destrect.top, blitToRectCanvas, 0, 0, cwidth, cheight);
+
+ xs=0;
+ yp=0;
+ xe=cwidth;
+ ye=cheight;
+ pitch=cacheWidth;
+ usingBlitCanvas = true;
+ }
+ else
+ {
+ xs=destrect.left;
+ xe=destrect.right;
+ yp=destrect.top;
+ ye=destrect.bottom;
+
+ cwidth/=4;
+ pitch=cwidth;
+ }
+ int xpo=(dst->left-destrect.left+xs)-(getX()+src->left);
+ int ypo=(dst->top-destrect.top+yp)-(getY()+src->top);
+
+ if (yp < 0) yp=0;
+ if (xs < 0) xs=0;
+
+ if (yp<getY()+ypo) yp=ypo+getY();
+ if (xs<getX()+xpo) xs=xpo+getX();
+
+ if (xe > getWidth()+getX()+xpo) xe=getWidth()+getX()+xpo;
+ if (ye > getHeight()+getY()+ypo) ye=getHeight()+getY()+ypo;
+
+ // blend bitmap to dib
+
+ if (xs<xe) for (; yp < ye; yp ++)
+ {
+ int xp=xe-xs;
+ unsigned int *dest=((unsigned int*)dib) + pitch*yp + xs;
+ unsigned int *src=((unsigned int*)bits) + (yp-ypo)*fullimage_w + (xs-xpo);
+
+ if (!has_alpha && alpha==255) // simple copy
+ {
+ MEMCPY32(dest,src,xp);
+ }
+ else if (!has_alpha) // no alpha channel info, but just a simple blend
+ {
+ if (!HAS_MMX)
+ while (xp--) *dest++ = Blenders::BLEND_ADJ1(*src++, *dest, alpha);
+
+#ifndef NO_MMX
+ else
+ {
+#ifdef WIN32
+ if (xp>1) __asm
+ {
+ movd mm3, [alpha]
+ mov ecx, xp
+
+ movq mm4, [SkinBitmap_mmx_revn2]
+ packuswb mm3, mm3 // 0000HHVV
+
+ paddusw mm3, [SkinBitmap_mmx_one]
+ mov edi, dest
+
+ punpcklwd mm3, mm3 // HHVVHHVV
+ mov esi, src
+
+ punpckldq mm3, mm3 // HHVVHHVV HHVVHHVV
+ shr ecx, 1
+
+ psubw mm4, mm3
+
+ align 16
+_blitAlpha_Loop1:
+
+ movd mm0, [edi]
+
+ movd mm1, [esi]
+ punpcklbw mm0, [SkinBitmap_mmx_zero]
+
+ movd mm7, [edi+4]
+ punpcklbw mm1, [SkinBitmap_mmx_zero]
+
+ pmullw mm0, mm4
+ pmullw mm1, mm3
+
+ movd mm6, [esi+4]
+ punpcklbw mm7, [SkinBitmap_mmx_zero]
+
+ punpcklbw mm6, [SkinBitmap_mmx_zero]
+
+ pmullw mm7, mm4
+ pmullw mm6, mm3
+
+ paddw mm0, mm1
+
+ psrlw mm0, 8
+
+ packuswb mm0, mm0
+ add esi, 8
+
+ movd [edi], mm0
+ paddw mm7, mm6
+
+ psrlw mm7, 8
+
+ packuswb mm7, mm7
+
+ movd [edi+4], mm7
+
+ add edi, 8
+
+ dec ecx
+ jnz _blitAlpha_Loop1
+ mov src, esi
+ mov dest, edi
+#else
+ if (xp > 1)
+ {
+ __asm__ volatile(
+ "movd %6, %%mm3\n"
+ "mov %2, %%ecx\n"
+ "movq (SkinBitmap_mmx_revn2), %%mm4\n"
+ "packuswb %%mm3, %%mm3\n"
+ "paddusw (SkinBitmap_mmx_one), %%mm3\n"
+ "mov %0, %%edi\n"
+ "punpcklwd %%mm3, %%mm3\n"
+ "mov %1, %%esi\n"
+ "punpckldq %%mm3, %%mm3\n"
+ "shr $1, %%ecx\n"
+ "psubw %%mm3, %%mm4\n"
+ ".align 16\n"
+ "_blitAlpha_Loop1:\n"
+ "movd (%%edi), %%mm0\n"
+ "movd (%%esi), %%mm1\n"
+ "punpcklbw (SkinBitmap_mmx_zero), %%mm0\n"
+ "movd 4(%%edi), %%mm7\n"
+ "punpcklbw (SkinBitmap_mmx_zero), %%mm1\n"
+ "pmullw %%mm3, %%mm0\n"
+ "pmullw %%mm4, %%mm1\n"
+ "movd 4(%%esi), %%mm6\n"
+ "punpcklbw (SkinBitmap_mmx_zero), %%mm7\n"
+ "punpcklbw (SkinBitmap_mmx_zero), %%mm6\n"
+ "pmullw %%mm4, %%mm6\n"
+ "pmullw %%mm3, %%mm7\n"
+ "paddw %%mm1, %%mm0\n"
+ "psrlw $8, %%mm0\n"
+ "packuswb %%mm0, %%mm0\n"
+ "add $8, %%esi\n"
+ "movd %%mm0, (%%edi)\n"
+ "paddw %%mm6, %%mm7\n"
+ "psrlw $8, %%mm7\n"
+ "packuswb %%mm7, %%mm7\n"
+ "movd %%mm7, 4(%%edi)\n"
+ "add $8, %%edi\n"
+ "dec %%ecx\n"
+ "jnz _blitAlpha_Loop1\n"
+ "mov %%esi, %1\n"
+ "mov %%edi, %0\n"
+
+ : "=m"(dest), "=m"(src), "=m"(xp)
+ : "0"(dest), "1"(src), "2"(xp), "m"(alpha)
+ : "%eax", "%ecx", "%esi", "%edi");
+
+#endif
+ }
+ if (xp & 1) *dest++ = Blenders::BLEND_ADJ1_MMX(*src++, *dest, alpha);
+ } // mmx available
+#endif // !NO_MMX
+ }
+ else if (alpha == 255) // no global alpha, just alpha channel
+ {
+ if (!HAS_MMX)
+ while (xp--) *dest++ = Blenders::BLEND_ADJ2(*dest, *src++);
+
+#ifndef NO_MMX
+ else
+ {
+#ifdef WIN32
+ if (xp > 1) __asm
+ {
+ mov ecx, xp
+ shr ecx, 1
+ mov edi, dest
+ mov esi, src
+ align 16
+_blitAlpha_Loop2:
+
+ movd mm3, [esi]
+ movd mm5, [esi+4]
+
+ movq mm2, [SkinBitmap_mmx_revn2]
+ psrld mm3, 24
+
+ movq mm4, [SkinBitmap_mmx_revn2]
+ psrld mm5, 24
+
+ movd mm0, [edi]
+ packuswb mm3, mm3 // 0000HHVV
+
+ movd mm1, [esi]
+ packuswb mm5, mm5 // 0000HHVV
+
+ movd mm6, [esi+4]
+ paddusw mm3, [SkinBitmap_mmx_one]
+
+ punpcklwd mm3, mm3 // HHVVHHVV
+ paddusw mm5, [SkinBitmap_mmx_one]
+
+ movd mm7, [edi+4]
+ punpcklwd mm5, mm5 // HHVVHHVV
+
+ punpckldq mm3, mm3 // HHVVHHVV HHVVHHVV
+ punpckldq mm5, mm5 // HHVVHHVV HHVVHHVV
+
+ punpcklbw mm6, [SkinBitmap_mmx_zero]
+ psubw mm4, mm5
+
+ punpcklbw mm0, [SkinBitmap_mmx_zero]
+ psubw mm2, mm3
+
+ punpcklbw mm7, [SkinBitmap_mmx_zero]
+ pmullw mm0, mm2
+
+ pmullw mm7, mm4
+ punpcklbw mm1, [SkinBitmap_mmx_zero]
+
+ psubw mm2, mm3
+
+ psrlw mm0, 8
+ psrlw mm7, 8
+ paddw mm0, mm1
+
+ paddw mm7, mm6
+ packuswb mm0, mm0
+
+ movd [edi], mm0
+ packuswb mm7, mm7
+
+ movd [edi+4], mm7
+
+ add esi, 8
+ add edi, 8
+
+ dec ecx
+ jnz _blitAlpha_Loop2
+ mov src, esi
+ mov dest, edi
+#else
+ if (xp > 1)
+ {
+ __asm__ volatile(
+ "mov %4, %%ecx\n"
+ "shr $1, %%ecx\n"
+ "mov %0, %%edi\n"
+ "mov %1, %%esi\n"
+ ".align 16\n"
+ "_blitAlpha_Loop2:\n"
+ "movd (%%esi), %%mm3\n"
+ "movd 4(%%esi), %%mm5\n"
+ "movq (SkinBitmap_mmx_revn2), %%mm2\n"
+ "psrld $24, %%mm3\n"
+ "movq (SkinBitmap_mmx_revn2), %%mm4\n"
+ "psrld $24, %%mm5\n"
+ "movd (%%edi), %%mm0\n"
+ "packuswb %%mm3, %%mm3\n"
+ "movd (%%esi), %%mm1\n"
+ "packuswb %%mm5, %%mm5\n"
+ "movd 4(%%esi), %%mm6\n"
+ "paddusw (SkinBitmap_mmx_one), %%mm3\n"
+ "punpcklwd %%mm3, %%mm3\n"
+ "paddusw (SkinBitmap_mmx_one), %%mm5\n"
+ "movd 4(%%edi), %%mm7\n"
+ "punpcklwd %%mm5, %%mm5\n"
+ "punpckldq %%mm3, %%mm3\n"
+ "punpckldq %%mm5, %%mm5\n"
+ "punpcklbw (SkinBitmap_mmx_zero), %%mm6\n"
+ "psubw %%mm5, %%mm4\n"
+ "punpcklbw (SkinBitmap_mmx_zero), %%mm0\n"
+ "psubw %%mm3, %%mm2\n"
+ "punpcklbw (SkinBitmap_mmx_zero), %%mm7\n"
+ "pmullw %%mm2, %%mm0\n"
+ "pmullw %%mm4, %%mm7\n"
+ "punpcklbw (SkinBitmap_mmx_zero), %%mm1\n"
+ "psubw %%mm3, %%mm2\n"
+ "psrlw $8, %%mm0\n"
+ "psrlw $8, %%mm7\n"
+ "paddw %%mm1, %%mm0\n"
+ "paddw %%mm6, %%mm7\n"
+ "packuswb %%mm0, %%mm0\n"
+ "movd %%mm0, (%%edi)\n"
+ "packuswb %%mm7, %%mm7\n"
+ "movd %%mm7, 4(%%edi)\n"
+ "add $8, %%esi\n"
+ "add $8, %%edi\n"
+ "dec %%ecx\n"
+ "jnz _blitAlpha_Loop2\n"
+ "mov %%esi, %1\n"
+ "mov %%edi, %0\n"
+
+ : "=m"(dest), "=m"(src)
+ : "0"(dest), "1"(src), "m"(xp)
+ : "%eax", "%ecx", "%esi", "%edi");
+#endif
+ }
+ if (xp&1) *dest++ = Blenders::BLEND_ADJ2_MMX(*dest, *src++);
+ } // HAS_MMX
+#endif // ifndef NO_MMX
+ }
+ else // both
+ {
+ if (!HAS_MMX)
+ while (xp--) *dest++ = Blenders::BLEND_ADJ3(*dest, *src++, alpha);
+#ifndef NO_MMX
+ else
+ {
+#ifdef WIN32
+ if (xp > 1) __asm
+ {
+ movd mm5, [alpha]
+ mov ecx, xp
+
+ packuswb mm5, mm5
+ shr ecx, 1
+
+ paddusw mm5, [SkinBitmap_mmx_one]
+
+ punpcklwd mm5, mm5
+ mov edi, dest
+
+ punpckldq mm5, mm5
+ mov esi, src
+
+ align 16
+_blitAlpha_Loop3:
+
+ movd mm3, [esi] // VVVVVVVV
+ movd mm4, [esi+4] // VVVVVVVV
+
+ movd mm0, [edi]
+ psrld mm3, 24
+
+ movd mm1, [esi]
+ psrld mm4, 24
+
+ paddusw mm3, [SkinBitmap_mmx_one]
+ paddusw mm4, [SkinBitmap_mmx_one]
+
+ movd mm7, [edi+4]
+ punpcklwd mm3, mm3
+
+ movd mm6, [esi+4]
+ punpcklwd mm4, mm4
+
+ punpckldq mm3, mm3
+ punpckldq mm4, mm4
+
+ pmullw mm3, mm5
+ pmullw mm4, mm5
+
+ punpcklbw mm7, [SkinBitmap_mmx_zero]
+ punpcklbw mm6, [SkinBitmap_mmx_zero]
+
+ movq mm2, [SkinBitmap_mmx_revn2]
+ psrlw mm3, 8
+
+ psrlw mm4, 8
+
+ punpcklbw mm0, [SkinBitmap_mmx_zero]
+ punpcklbw mm1, [SkinBitmap_mmx_zero]
+
+ psubw mm2, mm3
+ pmullw mm0, mm2
+
+ pmullw mm1, mm5
+ add esi, 8
+
+ movq mm2, [SkinBitmap_mmx_revn2]
+ pmullw mm6, mm5
+
+ paddusw mm0, mm1
+ psubw mm2, mm4
+
+ pmullw mm7, mm2
+ psrlw mm0, 8
+
+ packuswb mm0, mm0
+ paddusw mm7, mm6
+
+ movd [edi], mm0
+ psrlw mm7, 8
+
+ packuswb mm7, mm7
+
+ movd [edi+4], mm7
+
+ add edi, 8
+
+ dec ecx
+ jnz _blitAlpha_Loop3
+ mov src, esi
+ mov dest, edi
+#else
+ if (xp > 1)
+ {
+ __asm__ volatile(
+ "movd %5, %%mm5\n"
+ "mov %4, %%ecx\n"
+ "packuswb %%mm5, %%mm5 \n"
+ "shr $1, %%ecx\n"
+ "paddusw (SkinBitmap_mmx_one), %%mm5\n"
+ "punpcklwd %%mm5, %%mm5\n"
+ "mov %0, %%edi\n"
+ "punpckldq %%mm5, %%mm5\n"
+ "mov %1, %%esi\n"
+ ".align 16\n"
+ "_blitAlpha_Loop3:\n"
+ "movd (%%esi), %%mm3\n"
+ "movd 4(%%esi), %%mm4\n"
+ "movd (%%edi), %%mm0\n"
+ "psrld $24, %%mm3\n"
+ "movd (%%esi), %%mm1\n"
+ "psrld $24, %%mm4\n"
+ "paddusw (SkinBitmap_mmx_one), %%mm3\n"
+ "paddusw (SkinBitmap_mmx_one), %%mm4\n"
+ "movd 4(%%edi), %%mm7\n"
+ "punpcklwd %%mm3, %%mm3\n"
+ "movd 4(%%esi), %%mm6\n"
+ "punpcklwd %%mm4, %%mm4\n"
+ "punpckldq %%mm3, %%mm3\n"
+ "punpckldq %%mm4, %%mm4\n"
+ "pmullw %%mm5, %%mm3\n"
+ "pmullw %%mm5, %%mm4\n"
+ "punpcklbw (SkinBitmap_mmx_zero), %%mm7\n"
+ "punpcklbw (SkinBitmap_mmx_zero), %%mm6\n"
+ "movq (SkinBitmap_mmx_revn2), %%mm2\n"
+ "psrlw $8, %%mm3\n"
+ "psrlw $8, %%mm4\n"
+ "punpcklbw (SkinBitmap_mmx_zero), %%mm0\n"
+ "punpcklbw (SkinBitmap_mmx_zero), %%mm1\n"
+ "psubw %%mm3, %%mm2\n"
+ "pmullw %%mm2, %%mm0\n"
+ "pmullw %%mm5, %%mm1\n"
+ "add $8, %%esi\n"
+ "movq (SkinBitmap_mmx_revn2), %%mm2\n"
+ "pmullw %%mm5, %%mm6\n"
+ "paddusw %%mm1, %%mm0\n"
+ "psubw %%mm4, %%mm2\n"
+ "pmullw %%mm2, %%mm7\n"
+ "psrlw $8, %%mm0\n"
+ "packuswb %%mm0, %%mm0\n"
+ "paddusw %%mm6, %%mm7\n"
+ "movd %%mm0, (%%edi)\n"
+ "psrlw $8, %%mm7\n"
+ "packuswb %%mm7, %%mm7\n"
+ "movd %%mm7, 4(%%edi)\n"
+ "add $8, %%edi\n"
+ "dec %%ecx\n"
+ "jnz _blitAlpha_Loop3\n"
+ "mov %%esi, %1\n"
+ "mov %%edi, %0\n"
+
+ : "=m"(dest), "=m"(src)
+ : "0"(dest), "1"(src), "m"(xp), "m"(alpha)
+ : "%eax", "%ecx", "%esi", "%edi");
+#endif
+ }
+ if (xp&1) *dest++ = Blenders::BLEND_ADJ3_MMX(*dest, *src++, alpha);
+ } // HAS_MMX
+#endif // ifndef NO_MMX
+ }
+ }
+#ifndef NO_MMX
+ Blenders::BLEND_MMX_END();
+#endif
+ // write bits back to dib.
+
+ if (usingBlitCanvas)
+ {
+ blitToRectCanvas->blit(0, 0, &clone, destrect.left, destrect.top, cwidth, cheight);
+ }
+}
+
+#ifdef WIN32
+#pragma warning(pop)
+#endif
+
+void SkinBitmap::stretch(ifc_canvas *canvas, int x, int y, int w, int h)
+{
+ RECT src, dst;
+ src.left=0;
+ src.top=0;
+ src.right=getWidth();
+ src.bottom=getHeight();
+ dst.left=x;
+ dst.right=x+w;
+ dst.top=y;
+ dst.bottom=y+h;
+ stretchToRectAlpha(canvas,&src,&dst,255);
+}
+
+void SkinBitmap::stretchToRect(ifc_canvas *canvas, RECT *r)
+{
+ stretch(canvas, r->left, r->top, r->right - r->left, r->bottom - r->top);
+}
+
+void SkinBitmap::stretchRectToRect(ifc_canvas *canvas, RECT *src, RECT *dst)
+{
+ stretchToRectAlpha(canvas,src,dst,255);
+}
+
+
+void SkinBitmap::stretchToRectAlpha(ifc_canvas *canvas, RECT *r, int alpha)
+{
+ RECT re;
+ re.left=0; re.top=0;
+ re.right=getWidth(); re.bottom=getHeight();
+ stretchToRectAlpha(canvas,&re,r,alpha);
+}
+
+void SkinBitmap::blitAlpha(ifc_canvas *canvas, int x, int y, int alpha)
+{
+ RECT dst,src;
+ dst.left=x;
+ dst.top=y;
+ src.left=0;
+ src.top=0;
+ src.bottom=getHeight();
+ src.right=getWidth();
+ blitToRect(canvas,&src,&dst,alpha);
+}
+
+#ifdef WIN32
+#pragma warning(push)
+#pragma warning(disable : 4799)
+#endif
+
+template <class C>
+class Stretcher
+{
+public:
+ static void _stretchToRectAlpha(SkinBitmap *bitmap, int ys, int ye, int xe, int xs, int xstart, int yv, void *dib, int pitch, int dxv, int dyv, int alpha)
+ {
+ int bitmap_x = bitmap->getX();
+ int bitmap_y = bitmap->getY();
+ int bmpheight = bitmap->getHeight();
+ int fullimage_w = bitmap->getFullWidth();
+ void *bits = bitmap->getBits();
+ int xp=xe-xs;
+ for (int yp = ys; yp < ye; yp ++)
+ {
+ int t=yv>>16;
+ if (t < 0) t=0;
+ if (t >= bmpheight) t=bmpheight-1;
+ int *psrc=((int*)bits) + (t+bitmap_y)*fullimage_w + bitmap_x;
+ int *dest=((int*)dib) + pitch*yp + xs;
+
+ C::stretch(xp, psrc, dest, xstart, dxv, alpha);
+
+ yv+=dyv;
+ }
+ }
+};
+
+// no alpha, just stretch
+class Stretch
+{
+public:
+ static void stretch(int xp, int *psrc, int *dest, int xv, int dxv, int alpha)
+ {
+ while (xp--) //JFtodo: assembly optimize - these first two modes aren't used that much anyway
+ {
+ *dest++ = psrc[xv>>16];
+ xv+=dxv;
+ }
+ }
+};
+
+// no alpha channel, just a global alpha val
+class StretchGlobal
+{
+public:
+ static void stretch(int xp, int *psrc, int *dest, int xv, int dxv, int alpha)
+ {
+ while (xp--) //JFTODO: make MMX optimized version
+ {
+ *dest++ = Blenders::BLEND_ADJ1(psrc[xv>>16], *dest, alpha);
+ xv+=dxv;
+ }
+ }
+};
+
+// alpha channel, no global alpha val
+class StretchChannel
+{
+public:
+ static void stretch(int xp, int *psrc, int *dest, int xv, int dxv, int alpha)
+ {
+ while (xp--)
+ {
+ *dest++ = Blenders::BLEND_ADJ2(*dest, psrc[xv>>16]);
+ xv+=dxv;
+ }
+ }
+};
+
+class StretchGlobalChannel
+{
+public:
+ static void stretch(int xp, int *psrc, int *dest, int xv, int dxv, int alpha)
+ {
+ while (xp--)
+ {
+ *dest++ = Blenders::BLEND_ADJ3(*dest, psrc[xv>>16], alpha);
+ xv+=dxv;
+ }
+ }
+};
+
+
+#ifndef NO_MMX
+
+// no alpha channel, just a global alpha val
+class StretchGlobalMMX
+{
+public:
+ static void stretch(int xp, int *psrc, int *dest, int xv, int dxv, int alpha)
+ {
+ while (xp--) //JFTODO: make MMX optimized version
+ {
+ *dest++ = Blenders::BLEND_ADJ1_MMX(psrc[xv>>16], *dest, alpha);
+ xv+=dxv;
+ }
+ }
+};
+
+
+// alpha channel, no global alpha val
+class StretchChannelMMX
+{
+public:
+ static void stretch(int xp, int *psrc, int *dest, int xv, int dxv, int alpha)
+ {
+#ifdef WIN32
+ if (xp>1) __asm
+ {
+ mov ecx, xp
+ mov edi, dest
+
+ shr ecx, 1
+ mov esi, psrc
+
+ mov edx, xv
+ mov ebx, dxv
+
+ align 16
+_stretchAlpha_Loop2:
+
+ mov eax, edx
+ movd mm0, [edi]
+
+ movq mm4, [SkinBitmap_mmx_revn2]
+ shr eax, 16
+
+ movq mm2, [SkinBitmap_mmx_revn2]
+ punpcklbw mm0, [SkinBitmap_mmx_zero]
+
+ movd mm3, [esi+eax*4]
+ movd mm1, [esi+eax*4]
+
+ lea eax, [edx+ebx]
+ shr eax, 16
+
+ movd mm7, [edi+4]
+ psrld mm3, 24
+
+ packuswb mm3, mm3 // 0000HHVV
+ movd mm5, [esi+eax*4]
+
+ movd mm6, [esi+eax*4]
+ psrld mm5, 24
+
+ paddusw mm3, [SkinBitmap_mmx_one]
+ punpcklbw mm6, [SkinBitmap_mmx_zero]
+
+ packuswb mm5, mm5 // 0000HHVV
+ lea edx, [edx+ebx*2]
+
+ paddusw mm5, [SkinBitmap_mmx_one]
+ punpcklwd mm3, mm3 // HHVVHHVV
+
+ punpcklwd mm5, mm5 // HHVVHHVV
+ add edi, 8
+
+ punpckldq mm3, mm3 // HHVVHHVV HHVVHHVV
+
+ punpckldq mm5, mm5 // HHVVHHVV HHVVHHVV
+
+ psubw mm4, mm5
+
+ psubw mm2, mm3
+
+ punpcklbw mm7, [SkinBitmap_mmx_zero]
+ pmullw mm0, mm2
+
+ pmullw mm7, mm4
+ punpcklbw mm1, [SkinBitmap_mmx_zero]
+
+ psubw mm2, mm3
+
+ psrlw mm0, 8
+ psrlw mm7, 8
+ paddw mm0, mm1
+
+ paddw mm7, mm6
+ packuswb mm0, mm0
+
+ movd [edi-8], mm0
+ packuswb mm7, mm7
+
+ movd [edi-4], mm7
+
+ dec ecx
+ jnz _stretchAlpha_Loop2
+ mov dest, edi
+ mov xv, edx
+ }
+#else
+ if (xp>1)
+ {
+ __asm__ volatile(
+ "mov %5, %%ecx\n"
+ "mov %0, %%edi\n"
+ "shr $1, %%ecx\n"
+ "mov %1, %%esi\n"
+ "mov %2, %%edx\n"
+ "mov %7, %%ebx\n"
+ ".align 16\n"
+ "_stretchAlpha_Loop2:\n"
+ "mov %%edx, %%eax\n"
+ "movd (%%edi), %%mm0\n"
+ "movq (SkinBitmap_mmx_revn2), %%mm4\n"
+ "shr $16, %%eax\n"
+ "movq (SkinBitmap_mmx_revn2), %%mm2\n"
+ "punpcklbw (SkinBitmap_mmx_zero), %%mm0\n"
+ "movd (%%esi,%%eax,4), %%mm3\n"
+ "movd (%%esi,%%eax,4), %%mm1\n"
+ "lea (%%edx,%%ebx), %%eax\n"
+ "shr $16, %%eax\n"
+ "movd 4(%%edi), %%mm7\n"
+ "psrld $24, %%mm3\n"
+ "packuswb %%mm3, %%mm3\n"
+ "movd (%%esi,%%eax,4), %%mm5\n"
+ "movd (%%esi,%%eax,4), %%mm6\n"
+ "psrld $24, %%mm5\n"
+ "paddusw (SkinBitmap_mmx_one), %%mm3\n"
+ "punpcklbw (SkinBitmap_mmx_zero), %%mm6\n"
+ "packuswb %%mm5, %%mm5\n"
+ "lea (%%edx,%%ebx,2), %%edx\n"
+ "paddusw (SkinBitmap_mmx_one), %%mm5\n"
+ "punpcklwd %%mm3, %%mm3\n"
+ "punpcklwd %%mm5, %%mm5\n"
+ "add $8, %%edi\n"
+ "punpckldq %%mm3, %%mm3\n"
+ "punpckldq %%mm5, %%mm5\n"
+ "psubw %%mm5, %%mm4\n"
+ "psubw %%mm3, %%mm2\n"
+ "punpcklbw (SkinBitmap_mmx_zero), %%mm7\n"
+ "pmullw %%mm2, %%mm0\n"
+ "pmullw %%mm4, %%mm7\n"
+ "punpcklbw (SkinBitmap_mmx_zero), %%mm1\n"
+ "psubw %%mm3, %%mm2\n"
+ "psrlw $8, %%mm0\n"
+ "psrlw $8, %%mm7\n"
+ "paddw %%mm1, %%mm0\n"
+ "paddw %%mm6, %%mm7\n"
+ "packuswb %%mm0, %%mm0\n"
+ "movd %%mm0, -8(%%edi)\n"
+ "packuswb %%mm7, %%mm7\n"
+ "movd %%mm7, -4(%%edi)\n"
+ "dec %%ecx\n"
+ "jnz _stretchAlpha_Loop2\n"
+ "mov %%edi, %0\n"
+ "mov %%edx, %2\n"
+
+ : "=m"(dest), "=m"(psrc), "=m"(xv)
+ : "0"(dest), "1"(psrc), "m"(xp),
+ "2"(xv), "m"(dxv), "m"(alpha)
+ : "%eax", "%ebx", "%ecx", "%edx",
+ "%esi", "%edi");
+
+ }
+#endif
+
+ if (xp&1) *dest++ = Blenders::BLEND_ADJ2_MMX(*dest, psrc[xv>>16]);
+ }
+};
+
+
+class StretchGlobalChannelMMX
+{
+public:
+ static void stretch(int xp, int *psrc, int *dest, int xv, int dxv, int alpha)
+ {
+#ifdef WIN32
+ if (xp>1) __asm
+ {
+ movd mm5, [alpha]
+ mov ecx, xp
+
+ packuswb mm5, mm5
+ shr ecx, 1
+
+ paddusw mm5, [SkinBitmap_mmx_one]
+
+ punpcklwd mm5, mm5
+ mov edi, dest
+
+ punpckldq mm5, mm5
+ mov esi, psrc
+
+ mov edx, xv
+ mov ebx, dxv
+
+ align 16
+_stretchAlpha_Loop3:
+ movd mm0, [edi]
+ mov eax, edx
+
+ movd mm7, [edi+4]
+ shr eax, 16
+
+ movd mm1, [esi+eax*4]
+ movd mm3, [esi+eax*4] // VVVVVVVV
+
+ lea eax, [edx+ebx]
+ psrld mm3, 24
+
+ paddusw mm3, [SkinBitmap_mmx_one]
+
+ punpcklwd mm3, mm3
+ shr eax, 16
+
+ punpckldq mm3, mm3
+
+ pmullw mm3, mm5
+
+ movd mm4, [esi+eax*4] // VVVVVVVV
+ movd mm6, [esi+eax*4]
+
+ movq mm2, [SkinBitmap_mmx_revn2]
+ psrld mm4, 24
+
+ paddusw mm4, [SkinBitmap_mmx_one]
+ punpcklbw mm7, [SkinBitmap_mmx_zero]
+
+ punpcklwd mm4, mm4
+ lea edx, [edx+ebx*2]
+
+ punpckldq mm4, mm4
+ add edi, 8
+
+ punpcklbw mm6, [SkinBitmap_mmx_zero]
+ pmullw mm4, mm5
+
+ psrlw mm3, 8
+
+ punpcklbw mm0, [SkinBitmap_mmx_zero]
+
+ punpcklbw mm1, [SkinBitmap_mmx_zero]
+ psubw mm2, mm3
+
+ pmullw mm0, mm2
+ pmullw mm1, mm5
+
+ pmullw mm6, mm5
+ psrlw mm4, 8
+
+ movq mm2, [SkinBitmap_mmx_revn2]
+ paddusw mm0, mm1
+ psubw mm2, mm4
+
+ pmullw mm7, mm2
+ psrlw mm0, 8
+
+ packuswb mm0, mm0
+ paddusw mm7, mm6
+
+ movd [edi-8], mm0
+ psrlw mm7, 8
+
+ packuswb mm7, mm7
+
+ movd [edi-4], mm7
+
+ dec ecx
+ jnz _stretchAlpha_Loop3
+ mov xv, edx
+ mov dest, edi
+ }
+#else
+ if (xp>1)
+ {
+ __asm__ volatile(
+ "movd %8, %%mm5\n"
+ "mov %5, %%ecx\n"
+ "packuswb %%mm5, %%mm5 \n"
+ "shr $1, %%ecx\n"
+ "paddusw (SkinBitmap_mmx_one), %%mm5\n"
+ "punpcklwd %%mm5, %%mm5\n"
+ "mov %0, %%edi\n"
+ "punpckldq %%mm5, %%mm5\n"
+ "mov %1, %%esi\n"
+ "mov %6, %%edx\n"
+ "mov %7, %%ebx\n"
+ ".align 16\n"
+ "_stretchAlpha_Loop3:\n"
+ "movd (%%edi), %%mm0\n"
+ "mov %%edx, %%eax\n"
+ "movd 4(%%edi), %%mm7\n"
+ "shr $16, %%eax\n"
+ "movd (%%esi,%%eax,4), %%mm1\n"
+ "movd (%%esi,%%eax,4), %%mm3\n"
+ "lea (%%edx,%%ebx), %%eax\n"
+ "psrld $24, %%mm3\n"
+ "paddusw (SkinBitmap_mmx_one), %%mm3\n"
+ "punpcklwd %%mm3, %%mm3\n"
+ "shr $16, %%eax\n"
+ "punpckldq %%mm3, %%mm3\n"
+ "pmullw %%mm5, %%mm3\n"
+ "movd (%%esi,%%eax,4), %%mm4\n"
+ "movd (%%esi,%%eax,4), %%mm6\n"
+ "movq (SkinBitmap_mmx_revn2), %%mm2\n"
+ "psrld $24, %%mm4\n"
+ "paddusw (SkinBitmap_mmx_one), %%mm4\n"
+ "punpcklbw (SkinBitmap_mmx_zero), %%mm7\n"
+ "punpcklwd %%mm4, %%mm4\n"
+ "lea (%%edx,%%ebx,2), %%edx\n"
+ "punpckldq %%mm4, %%mm4\n"
+ "add $8, %%edi\n"
+ "punpcklbw (SkinBitmap_mmx_zero), %%mm6\n"
+ "pmullw %%mm5, %%mm4\n"
+ "psrlw $8, %%mm3\n"
+ "punpcklbw (SkinBitmap_mmx_zero), %%mm0\n"
+ "punpcklbw (SkinBitmap_mmx_zero), %%mm1\n"
+ "psubw %%mm3, %%mm2\n"
+ "pmullw %%mm2, %%mm0\n"
+ "pmullw %%mm5, %%mm1\n"
+ "pmullw %%mm5, %%mm6\n"
+ "psrlw $8, %%mm4\n"
+ "movq (SkinBitmap_mmx_revn2), %%mm2\n"
+ "paddusw %%mm1, %%mm0\n"
+ "psubw %%mm4, %%mm2\n"
+ "pmullw %%mm2, %%mm7\n"
+ "psrlw $8, %%mm0\n"
+ "packuswb %%mm0, %%mm0\n"
+ "paddusw %%mm6, %%mm7\n"
+ "movd %%mm0, -8(%%edi)\n"
+ "psrlw $8, %%mm7\n"
+ "packuswb %%mm7, %%mm7\n"
+ "movd %%mm7, -4(%%edi)\n"
+ "dec %%ecx\n"
+ "jnz _stretchAlpha_Loop3\n"
+ "mov %%edi, %0\n"
+ "mov %%edx, %2\n"
+
+ : "=m"(dest), "=m"(psrc), "=m"(xv)
+ : "0"(dest), "1"(psrc), "m"(xp),
+ "m"(xv), "m"(dxv), "m"(alpha)
+ : "%eax", "%ebx", "%ecx", "%edx",
+ "%esi", "%edi");
+
+ }
+#endif
+
+ if (xp&1) *dest++ = Blenders::BLEND_ADJ3_MMX(*dest, psrc[xv>>16], alpha);
+ }
+};
+#endif
+
+
+class __Stretch : public Stretcher<Stretch> {};
+class __StretchGlobal : public Stretcher<StretchGlobal> {};
+class __StretchChannel : public Stretcher<StretchChannel> {};
+class __StretchGlobalChannel : public Stretcher<StretchGlobalChannel> {};
+
+#ifndef NO_MMX
+class __StretchGlobalMMX : public Stretcher<StretchGlobalMMX> {};
+class __StretchChannelMMX : public Stretcher<StretchChannelMMX> {};
+class __StretchGlobalChannelMMX : public Stretcher<StretchGlobalChannelMMX> {};
+#endif
+
+#ifdef WIN32
+#pragma warning(pop)
+#endif
+
+
+void SkinBitmap::stretchToRectAlpha(ifc_canvas *canvas, RECT *_src, RECT *_dst, int alpha)
+{
+
+ if (alpha <= 0) return;
+ if (alpha > 255) alpha = 255;
+
+ RECT src=*_src;
+ RECT dst=*_dst;
+
+ if ((src.right-src.left) == (dst.right-dst.left) &&
+ (src.bottom-src.top) == (dst.bottom-dst.top))
+ {
+ blitToRect(canvas,_src,_dst,alpha);
+ return;
+ }
+ //FG> this is a hack, we should support subpixels instead
+ if (src.left == src.right)
+ {
+ if (src.right < getWidth())
+ src.right++;
+ else
+ src.left--;
+ }
+ if (src.top== src.bottom)
+ {
+ if (src.bottom < getHeight())
+ src.bottom++;
+ else
+ src.top--;
+ }
+
+ if (src.left >= src.right || src.top >= src.bottom) return;
+ if (dst.left >= dst.right || dst.top >= dst.bottom) return;
+
+ BltCanvas *blitToRectCanvas=0;
+ void *dib=canvas->getBits();
+ bool usingBlitCanvas = false;
+ BaseCloneCanvas clone(canvas);
+ int cwidth, cheight, pitch;
+
+ int dyv=((src.bottom-src.top)<<16)/(dst.bottom-dst.top);
+ int dxv=((src.right-src.left)<<16)/(dst.right-dst.left);
+ int yv=(src.top<<16);
+ int xstart=(src.left<<16);
+
+ RECT c;
+ int ctype=canvas->getClipBox(&c);
+ if (c.top > dst.top)
+ {
+ yv+=(c.top-dst.top)*dyv;
+ dst.top=c.top;
+ }
+ if (c.left > dst.left)
+ {
+ xstart+=(c.left-dst.left)*dxv;
+ dst.left=c.left;
+ }
+ if (c.bottom < dst.bottom)
+ dst.bottom=c.bottom;
+ if (c.right < dst.right)
+ dst.right=c.right;
+
+ if (dst.right <= dst.left || dst.bottom <= dst.top) return;
+
+ int xs,xe,ys,ye;
+
+#ifdef NO_SIMPLEFASTMODE
+ dib=NULL;
+#endif
+ if (!dib || canvas->getDim(NULL,&cheight,&cwidth) || !cwidth || cheight < 1 || ctype == COMPLEXREGION)
+ {
+ cwidth=dst.right-dst.left;
+ cheight=dst.bottom-dst.top;
+
+ /* create cached canvas for this thread if it doesn't exist */
+ blitToRectCanvas = (BltCanvas *)TlsGetValue(bitmap_cache_tls);
+ if (!blitToRectCanvas)
+ {
+ blitToRectCanvas = new BltCanvas(cwidth, cheight);
+ TlsSetValue(bitmap_cache_tls, (LPVOID)blitToRectCanvas);
+ }
+ int cacheWidth, cacheHeight;
+ blitToRectCanvas->getDim(&cacheWidth, &cacheHeight, NULL);
+
+ /* resize cache, if necessary */
+ if (cwidth > cacheWidth || cheight > cacheHeight)
+ {
+ cacheWidth=MAX(cacheWidth, cwidth);
+ cacheHeight=MAX(cacheHeight, cheight);
+ blitToRectCanvas->DestructiveResize(cacheWidth, cacheHeight);
+ }
+
+ dib = blitToRectCanvas->getBits();
+ if (has_alpha || alpha < 255)
+ clone.blit(dst.left, dst.top, blitToRectCanvas, 0, 0, cwidth, cheight);
+
+ xs=0;
+ ys=0;
+ xe=cwidth;
+ ye=cheight;
+ pitch=cacheWidth;
+ usingBlitCanvas=true;
+ }
+ else
+ {
+ xs=dst.left;
+ xe=dst.right;
+ ys=dst.top;
+ ye=dst.bottom;
+ cwidth/=4;
+ pitch=cwidth;
+ }
+
+ // stretch and blend bitmap to dib
+
+ if (xstart < 0) xstart=0;
+
+ // Martin> TODO
+ // we should separate the stretching from this function and move it to the Shrink() function (avoiding breaks from this fragile class)
+ // HQSkinBitmap will then override the Shrink funtion in order to apply it's own resizing stuff.
+ // and if we ever want a new algorithm we can just create a new UltraFastAndCoolSkinBitmap class overriding the function again
+
+ if (xs<xe)
+ {
+ if (!has_alpha) // doesn't have alpha channel
+ {
+ if (!high_quality_resampling || dxv<65536 || dyv<65536)
+ {
+ if (alpha == 255) // no global alpha
+ {
+ __Stretch::_stretchToRectAlpha(this, ys, ye, xe, xs, xstart, yv, dib, pitch, dxv, dyv, alpha);
+ }
+ else // has global alpha
+ {
+#ifndef NO_MMX
+ if (HAS_MMX)
+ {
+ __StretchGlobalMMX::_stretchToRectAlpha(this, ys, ye, xe, xs, xstart, yv, dib, pitch, dxv, dyv, alpha);
+ }
+ else
+#endif
+ {
+ __StretchGlobal::_stretchToRectAlpha(this, ys, ye, xe, xs, xstart, yv, dib, pitch, dxv, dyv, alpha);
+ }
+ }
+ }
+ else
+ {
+ Shrink(this, ys,ye,xe,xs, xstart,yv, (ARGB32 *)dib, pitch, dxv, dyv, alpha);
+ }
+ }
+ else // has alpha channel
+ {
+ // FUCKO: JF> BRENNAN FIX THESE BITCHES :)
+ if (alpha == 255) // no global alpha
+ {
+ if (!high_quality_resampling || dxv<65536 || dyv<65536)
+ {
+#ifndef NO_MMX
+ if (HAS_MMX)
+ {
+ __StretchChannelMMX::_stretchToRectAlpha(this, ys, ye, xe, xs, xstart, yv, dib, pitch, dxv, dyv, alpha);
+ }
+ else
+#endif
+ {
+ __StretchChannel::_stretchToRectAlpha(this, ys, ye, xe, xs, xstart, yv, dib, pitch, dxv, dyv, alpha);
+ }
+ }
+ else
+ {
+ Shrink(this, ys,ye,xe,xs, xstart,yv, (ARGB32 *)dib, pitch, dxv, dyv, alpha);
+ }
+ }
+ else // has global alpha
+ {
+ if (!high_quality_resampling || dxv<65536 || dyv<65536)
+ {
+#ifndef NO_MMX
+ if (HAS_MMX)
+ {
+ __StretchGlobalChannelMMX::_stretchToRectAlpha(this, ys, ye, xe, xs, xstart, yv, dib, pitch, dxv, dyv, alpha);
+ }
+ else
+#endif
+ {
+ __StretchGlobalChannel::_stretchToRectAlpha(this, ys, ye, xe, xs, xstart, yv, dib, pitch, dxv, dyv, alpha);
+ }
+ }
+ else
+ {
+ Shrink(this, ys, ye, xe, xs, xstart, yv, (ARGB32 *)dib, pitch, dxv, dyv,alpha);
+ }
+ }
+ }
+ }
+
+#ifndef NO_MMX
+ Blenders::BLEND_MMX_END();
+#endif
+ // write bits back to dib.
+
+ if (usingBlitCanvas)
+ {
+ blitToRectCanvas->blit(0, 0, &clone, dst.left, dst.top, cwidth, cheight);
+ }
+}
+
+COLORREF SkinBitmap::getPixel(int x, int y)
+{
+ ASSERT(bits != NULL);
+ if (x < 0 || y < 0 || x >= getFullWidth()-getX() || y>= getFullHeight()-getY()) return (COLORREF)0;
+ return (COLORREF)(((int*)bits)[x+getX()+(y+getY())*getFullWidth()]);
+}
+
+void *SkinBitmap::getBits()
+{
+ return bits;
+}
+
+int SkinBitmap::isInvalid()
+{
+ return last_failed;
+}
+
+void SkinBitmap::setHasAlpha(int ha)
+{
+ has_alpha=ha;
+}
+
+const wchar_t *SkinBitmap::getBitmapName()
+{
+ return bitmapname;
+}
+
+void SkinBitmap::AddRef()
+{
+ references++;
+}
+
+void SkinBitmap::Release()
+{
+ if (--references == 0)
+ delete this;
+} \ No newline at end of file
diff --git a/Src/tataki/bitmap/win/bitmap.h b/Src/tataki/bitmap/win/bitmap.h
new file mode 100644
index 00000000..67640cf8
--- /dev/null
+++ b/Src/tataki/bitmap/win/bitmap.h
@@ -0,0 +1,113 @@
+//NONPORTABLE
+#ifndef _BITMAP_H
+#define _BITMAP_H
+
+#pragma warning( disable: 4251 )
+// http://www.unknownroad.com/rtfm/VisualStudio/warningC4251.html
+
+#include <tataki/export.h>
+#include <bfc/platform/platform.h>
+class ifc_canvas; // see canvas.h
+
+//#define NO_MMX
+
+class api_region;
+
+// a skinnable bitmap
+class TATAKIAPI SkinBitmap
+{
+public:
+ void AddRef();
+ void Release();
+#ifndef _NOSTUDIO
+#ifdef _WIN32
+ SkinBitmap(HINSTANCE hInst, int _id, const wchar_t *colorgroup = NULL); //NONPORTABLE
+#endif
+ SkinBitmap(const wchar_t *elementname, int cached = 1);
+#endif
+ // SkinBitmap(SkinBitmap *source, int w, int h);
+ SkinBitmap(int w, int h, ARGB32 bgcolor = RGBA(255,255,255,255)); //untested --BU
+#ifdef _WIN32
+ SkinBitmap(HBITMAP bitmap);
+ SkinBitmap(HBITMAP bitmap, HDC dc, int has_alpha = 0, void *bits = NULL);
+#endif
+ SkinBitmap(ARGB32 *bits, int w, int h, bool own=false); // added by benski, use if you have raw image bits
+ SkinBitmap(ifc_canvas *canvas);
+ ~SkinBitmap();
+
+int getWidth() const { return subimage_w == -1 ? fullimage_w : subimage_w; };
+int getHeight() const { return subimage_h == -1 ? fullimage_h : subimage_h; };
+ int getFullWidth() const { return fullimage_w; };
+ int getFullHeight() const { return fullimage_h; };
+int getX() const { return x_offset == -1 ? 0 : x_offset; };
+int getY() const { return y_offset == -1 ? 0 : y_offset; };
+ int getBpp() const { return 32; };
+ int getAlpha() const { return has_alpha; };
+ void setHasAlpha(int ha);
+ virtual void *getBits();
+ int isInvalid();
+
+ const wchar_t *getBitmapName();
+
+ void blit(ifc_canvas *canvas, int x, int y);
+ void blitAlpha(ifc_canvas *canvas, int x, int y, int alpha = 255);
+ // blits a chunk of source into dest rect
+ void blitToRect(ifc_canvas *canvas, RECT *src, RECT *dst, int alpha = 255);
+ void blitTile(ifc_canvas *canvas, RECT *dest, int xoffs = 0, int yoffs = 0, int alpha = 255);
+ void blitRectToTile(ifc_canvas *canvas, RECT *dest, RECT *src, int xoffs = 0, int yoffs = 0, int alpha = 255);
+ void stretch(ifc_canvas *canvas, int x, int y, int w, int h);
+ void stretchToRect(ifc_canvas *canvas, RECT *r);
+ void stretchRectToRect(ifc_canvas *canvas, RECT *src, RECT *dst);
+
+ void stretchToRectAlpha(ifc_canvas *canvas, RECT *r, int alpha = 255);
+ void stretchToRectAlpha(ifc_canvas *canvas, RECT *src, RECT *dst, int alpha = 255);
+ ARGB32 getPixel(int x, int y);
+
+private:
+#ifdef _WIN32
+ void bmpToBits(HBITMAP hbmp, HDC defaultDC = NULL);
+#endif
+
+ int has_alpha;
+
+ int x_offset, y_offset, subimage_w, subimage_h, fullimage_w, fullimage_h;
+
+ ARGB32 *bits;
+ int ownbits;
+ int last_failed;
+ wchar_t *bitmapname;
+ int fromskin;
+ size_t references;
+ enum
+ {
+ OWNBITS_NOTOURS =0 ,
+ OWNBITS_USEIMGLDR = 1,
+ OWNBITS_USESTDFREE = 2,
+ OWNBITS_USECFREE = 3,
+ OWNBITS_USESYSFREE = 4,
+ };
+protected:
+ bool high_quality_resampling;
+};
+#ifndef _NOSTUDIO
+class HQSkinBitmap : public SkinBitmap
+{
+public:
+ HQSkinBitmap(ARGB32 *bits, int w, int h, bool own=false) : SkinBitmap(bits, w, h, own)
+ {
+ high_quality_resampling=true;
+ }
+
+ HQSkinBitmap(const wchar_t *elementname, int cached = 1) : SkinBitmap(elementname, cached)
+ {
+ high_quality_resampling=true;
+ }
+#ifdef _WIN32
+ HQSkinBitmap(HINSTANCE hInst, int _id, const wchar_t *colorgroup = NULL) : SkinBitmap(hInst, _id, colorgroup)
+ {
+ high_quality_resampling=true;
+ }
+#endif
+};
+#endif
+#endif
diff --git a/Src/tataki/blending/blending.cpp b/Src/tataki/blending/blending.cpp
new file mode 100644
index 00000000..24b04e5c
--- /dev/null
+++ b/Src/tataki/blending/blending.cpp
@@ -0,0 +1,54 @@
+#include "blending.h"
+
+#if !defined(WIN32) && !defined(LINUX)
+#error port me!
+#endif
+
+class BlenderInit
+{
+public:
+ BlenderInit() { Blenders::init(); }
+};
+static BlenderInit blender_init;
+
+void Blenders::init()
+{
+ if (!alphatable[127][127])
+ {
+ int i, j;
+ for (j = 0;j < 256;j++)
+ for (i = 0;i < 256;i++)
+ alphatable[i][j] = (i * (j + 1)) >> 8;
+#ifndef NO_MMX
+ DWORD retval1, retval2;
+#ifdef WIN32
+ __try {
+ _asm {
+ mov eax, 1 // set up CPUID to return processor version and features
+ // 0 = vendor string, 1 = version info, 2 = cache info
+ _emit 0x0f // code bytes = 0fh, 0a2h
+ _emit 0xa2
+ mov retval1, eax
+ mov retval2, edx
+ }
+ } __except(EXCEPTION_EXECUTE_HANDLER) { retval1 = retval2 = 0;}
+#else
+ __asm__ volatile ( "movl $1, %%eax\n"
+ ".byte 15, 162\n"
+ "movl %%eax, %0\n"
+ "movl %%edx, %1\n"
+ : "=m" (retval1), "=m" (retval2)
+ : // No inputs...
+ : "%eax", "%edx" );
+#endif
+ mmx_available = retval1 && (retval2 & 0x800000);
+#endif //ndef NO_MMX
+
+ }
+}
+
+#ifndef NO_MMX
+int Blenders::mmx_available = 0;
+#endif
+
+unsigned char Blenders::alphatable[256][256] = {0};
diff --git a/Src/tataki/blending/blending.h b/Src/tataki/blending/blending.h
new file mode 100644
index 00000000..238ff08f
--- /dev/null
+++ b/Src/tataki/blending/blending.h
@@ -0,0 +1,542 @@
+#ifndef _BLENDING_H_
+#define _BLENDING_H_
+
+//#include <bfc/common.h>
+#include <bfc/platform/types.h>
+#include <tataki/export.h>
+
+#ifdef _WIN64
+#define NO_MMX
+#endif
+
+class TATAKIAPI Blenders
+{
+public:
+ static void init();
+ static unsigned int inline BLEND_ADJ1(unsigned int a, unsigned int b, int alpha);
+ static unsigned int inline BLEND_ADJ2(unsigned int a, unsigned int b);
+ static unsigned int inline BLEND_ADJ3(unsigned int a, unsigned int b, int alpha);
+ static unsigned int inline BLEND_MUL(unsigned int a, int v);
+ static unsigned int inline BLEND_AVG(unsigned int a, unsigned int b);
+ static unsigned int inline BLEND4(unsigned int *p1, unsigned int w, int xp, int yp);
+
+#ifndef NO_MMX
+ static int inline MMX_AVAILABLE() { return mmx_available; }
+ static unsigned int inline BLEND_ADJ1_MMX(unsigned int a, unsigned int b, int alpha);
+ static unsigned int inline BLEND_ADJ2_MMX(unsigned int a, unsigned int b);
+ static unsigned int inline BLEND_ADJ3_MMX(unsigned int a, unsigned int b, int alpha);
+ static unsigned int inline BLEND_MUL_MMX(unsigned int a, int v);
+ static unsigned int inline BLEND_AVG_MMX(unsigned int a, unsigned int b);
+ static unsigned int inline BLEND4_MMX(unsigned int *p1, unsigned int w, int xp, int yp);
+ static void inline BLEND_MMX_END()
+ {
+#if defined(WIN32) && !defined(_WIN64)
+ if (mmx_available) __asm emms;
+#endif
+#ifdef LINUX
+if (mmx_available) __asm__ volatile ( "emms" : : );
+#endif
+
+ }
+#endif
+
+//private:
+ static uint8_t alphatable[256][256];
+#ifndef NO_MMX
+ static int mmx_available;
+#endif
+};
+
+
+// NON MMX
+
+// average blend of a and b.
+unsigned int inline Blenders::BLEND_AVG(unsigned int a, unsigned int b)
+{
+ return ((a >> 1)&~((1 << 7) | (1 << 15) | (1 << 23))) + ((b >> 1)&~((1 << 7) | (1 << 15) | (1 << 23)));
+}
+
+
+// multiplies 32 bit color A by scalar V (0-255)
+unsigned int inline Blenders::BLEND_MUL(unsigned int a, int v)
+{
+ register int t;
+ t = Blenders::alphatable[a & 0xFF][v];
+ t |= Blenders::alphatable[(a & 0xFF00) >> 8][v] << 8;
+ t |= Blenders::alphatable[(a & 0xFF0000) >> 16][v] << 16;
+ t |= Blenders::alphatable[(a & 0xFF000000) >> 24][v] << 24;
+ return t;
+}
+
+
+// V is scalar (0-255), (1.0-V)*b + V*a
+unsigned int inline Blenders::BLEND_ADJ1(unsigned int a, unsigned int b, int v)
+{
+ register int t;
+ t = Blenders::alphatable[b & 0xFF][0xFF - v] + Blenders::alphatable[a & 0xFF][v];
+ t |= (Blenders::alphatable[(b & 0xFF00) >> 8][0xFF - v] + Blenders::alphatable[(a & 0xFF00) >> 8][v]) << 8;
+ t |= (Blenders::alphatable[(b & 0xFF0000) >> 16][0xFF - v] + Blenders::alphatable[(a & 0xFF0000) >> 16][v]) << 16;
+ t |= (Blenders::alphatable[(b & 0xFF000000) >> 24][0xFF - v] + Blenders::alphatable[(a & 0xFF000000) >> 24][v]) << 24;
+ return t;
+}
+
+// returns a*(1.0-Alpha(b)) + b
+unsigned int inline Blenders::BLEND_ADJ2(unsigned int a, unsigned int b)
+{
+ register int t, z;
+ int v = 0xff - ((b >> 24) & 0xff);
+ t = Blenders::alphatable[a & 0xFF][v] + (b & 0xFF);
+ if (t > 0xFF) t = 0xff;
+ z = (Blenders::alphatable[(a & 0xFF00) >> 8][v] << 8) + (b & 0xFF00);
+ if (z > 0xFF00) z = 0xff00;
+ t |= z;
+ z = (Blenders::alphatable[(a & 0xFF0000) >> 16][v] << 16) + ((b & 0xFF0000));
+ if (z > 0xFF0000) z = 0xff0000;
+ t |= z;
+ z = (Blenders::alphatable[(a & 0xFF000000) >> 24][v]) + ((b & 0xFF000000) >> 24);
+ if (z > 0xFF) z = 0xff;
+ return t | (z << 24);
+}
+
+// returns a*(1-Alpha(b)*W) + b*W, clamped (W is scalar 0-0xff).
+unsigned int inline Blenders::BLEND_ADJ3(unsigned int a, unsigned int b, int w)
+{
+ register int t, z;
+ int v = 0xff - Blenders::alphatable[(b >> 24) & 0xff][w];
+
+ t = Blenders::alphatable[a & 0xFF][v] + Blenders::alphatable[b & 0xFF][w];
+ if (t > 0xFF) t = 0xFF;
+ z = Blenders::alphatable[(a & 0xFF00) >> 8][v] + Blenders::alphatable[(b & 0xFF00) >> 8][w];
+ if (z > 0xFF) z = 0xFF;
+ t |= z << 8;
+ z = Blenders::alphatable[(a & 0xFF0000) >> 16][v] + Blenders::alphatable[(b & 0xFF0000) >> 16][w];
+ if (z > 0xFF) z = 0xFF;
+ t |= z << 16;
+ z = Blenders::alphatable[(a & 0xFF000000) >> 24][v] + Blenders::alphatable[(b & 0xFF000000) >> 24][w];
+ if (z > 0xFF) z = 0xFF;
+ return t | (z << 24);
+}
+
+unsigned int __inline Blenders::BLEND4(unsigned int *p1, unsigned int w, int xp, int yp)
+{
+ register int t;
+ uint8_t a1, a2, a3, a4;
+ xp = (xp >> 8) & 0xff;
+ yp = (yp >> 8) & 0xff;
+ a1 = alphatable[255 - xp][255 - yp];
+ a2 = alphatable[xp][255 - yp];
+ a3 = alphatable[255 - xp][yp];
+ a4 = alphatable[xp][yp];
+ t = alphatable[p1[0] & 0xff][a1] + alphatable[p1[1] & 0xff][a2] + alphatable[p1[w] & 0xff][a3] + alphatable[p1[w + 1] & 0xff][a4];
+ t |= (alphatable[(p1[0] >> 8) & 0xff][a1] + alphatable[(p1[1] >> 8) & 0xff][a2] + alphatable[(p1[w] >> 8) & 0xff][a3] + alphatable[(p1[w + 1] >> 8) & 0xff][a4]) << 8;
+ t |= (alphatable[(p1[0] >> 16) & 0xff][a1] + alphatable[(p1[1] >> 16) & 0xff][a2] + alphatable[(p1[w] >> 16) & 0xff][a3] + alphatable[(p1[w + 1] >> 16) & 0xff][a4]) << 16;
+ t |= (alphatable[(p1[0] >> 24) & 0xff][a1] + alphatable[(p1[1] >> 24) & 0xff][a2] + alphatable[(p1[w] >> 24) & 0xff][a3] + alphatable[(p1[w + 1] >> 24) & 0xff][a4]) << 24;
+ return t;
+}
+
+
+
+
+#ifndef NO_MMX
+
+
+#ifdef WIN32
+#pragma warning( push, 1 )
+#pragma warning(disable: 4799)
+#endif
+
+#ifdef WIN32
+#define MMX_CONST const
+#else
+#define MMX_CONST
+#endif
+
+static unsigned int MMX_CONST Blenders__mmx_revn2[2] = {0x01000100, 0x01000100};
+static unsigned int MMX_CONST Blenders__mmx_zero[2];
+static unsigned int MMX_CONST Blenders__mmx_one[2] = {1, 0};
+
+#undef MMX_CONST
+
+/// MMX
+
+// average blend of a and b.
+unsigned int inline Blenders::BLEND_AVG_MMX(unsigned int a, unsigned int b)
+{
+ return ((a >> 1)&~((1 << 7) | (1 << 15) | (1 << 23))) + ((b >> 1)&~((1 << 7) | (1 << 15) | (1 << 23)));
+}
+
+// multiplies 32 bit color A by scalar V (0-255)
+unsigned int inline Blenders::BLEND_MUL_MMX(unsigned int a, int v)
+{
+#ifdef WIN32
+ __asm
+ {
+ movd mm3, [v] // VVVVVVVV
+
+ movd mm0, [a]
+ packuswb mm3, mm3 // 0000HHVV
+
+ punpcklbw mm0, [Blenders__mmx_zero]
+ punpcklwd mm3, mm3 // HHVVHHVV
+
+ punpckldq mm3, mm3 // HHVVHHVV HHVVHHVV
+
+ pmullw mm0, mm3
+
+ psrlw mm0, 8
+
+ packuswb mm0, mm0
+
+ movd eax, mm0
+ }
+#else
+ __asm__ volatile (
+ "movd %0, %%mm3\n"
+ "movd %1, %%mm0\n"
+ "packuswb %%mm3, %%mm3\n"
+ "punpcklbw (Blenders__mmx_zero), %%mm0\n"
+ "punpcklwd %%mm3, %%mm3\n"
+ "punpckldq %%mm3, %%mm3\n"
+ "pmullw %%mm3, %%mm0\n"
+ "psrlw $8, %%mm0\n"
+ "packuswb %%mm0, %%mm0\n"
+ "movd %%mm0, %%eax\n"
+ :
+ : "m" (v), "m" (a)
+ : "%mm0", "%mm3" );
+#endif
+}
+
+
+// V is scalar (0-255), (1.0-V)*b + V*a
+unsigned int inline Blenders::BLEND_ADJ1_MMX(unsigned int a, unsigned int b, int v)
+{
+#ifdef WIN32
+ __asm
+ {
+ movd mm3, [v] // VVVVVVVV
+
+ movd mm0, [a]
+ packuswb mm3, mm3 // 0000HHVV
+
+ movd mm1, [b]
+ paddusw mm3, [Blenders__mmx_one]
+
+ movq mm4, [Blenders__mmx_revn2]
+ punpcklwd mm3, mm3 // HHVVHHVV
+
+ punpcklbw mm0, [Blenders__mmx_zero]
+ punpckldq mm3, mm3 // HHVVHHVV HHVVHHVV
+
+ punpcklbw mm1, [Blenders__mmx_zero]
+ psubw mm4, mm3
+
+ pmullw mm0, mm3
+ pmullw mm1, mm4
+
+ paddw mm0, mm1
+
+ psrlw mm0, 8
+
+ packuswb mm0, mm0
+
+ movd eax, mm0
+ }
+#else
+ __asm__ volatile (
+ "movd %0, %%mm3\n"
+ "movd %1, %%mm0\n"
+ "packuswb %%mm3, %%mm3\n"
+ "movd %2, %%mm1\n"
+ "paddusw (Blenders__mmx_one), %%mm3\n"
+ "movq (Blenders__mmx_revn2), %%mm4\n"
+ "punpcklwd %%mm3, %%mm3\n"
+ "punpcklbw (Blenders__mmx_zero), %%mm0\n"
+ "punpckldq %%mm3, %%mm3\n"
+ "punpcklbw (Blenders__mmx_zero), %%mm1\n"
+ "psubw %%mm3, %%mm4\n"
+ "pmullw %%mm3, %%mm0\n"
+ "pmullw %%mm4, %%mm1\n"
+ "paddw %%mm1, %%mm0\n"
+ "psrlw $8, %%mm0\n"
+ "packuswb %%mm0, %%mm0\n"
+ "movd %%mm0, %%eax\n"
+ :
+ : "m" (v), "m" (a), "m" (b)
+ : "%mm0", "%mm1", "%mm3", "%mm4" );
+#endif
+}
+
+// returns a*(1.0-Alpha(b)) + b
+unsigned int inline Blenders::BLEND_ADJ2_MMX(unsigned int a, unsigned int b)
+{
+#ifdef WIN32
+ __asm
+ {
+ movd mm3, [b] // VVVVVVVV
+ movq mm4, [Blenders__mmx_revn2]
+
+ movd mm0, [a]
+ psrld mm3, 24
+
+ movd mm1, [b]
+ paddusw mm3, [Blenders__mmx_one]
+
+ punpcklwd mm3, mm3 // HHVVHHVV
+ punpcklbw mm0, [Blenders__mmx_zero]
+
+ punpckldq mm3, mm3 // HHVVHHVV HHVVHHVV
+ punpcklbw mm1, [Blenders__mmx_zero]
+
+ psubw mm4, mm3
+
+ pmullw mm0, mm4
+ // stall
+
+ // stall
+
+ // stall
+
+ psrlw mm0, 8
+ // stall
+
+ paddw mm0, mm1
+ // stall
+
+ packuswb mm0, mm0
+ // stall
+
+ movd eax, mm0
+ }
+#else
+ __asm__ volatile (
+ "movd %1, %%mm3\n"
+ "movq (Blenders__mmx_revn2), %%mm4\n"
+ "movd %0, %%mm0\n"
+ "psrld $24, %%mm3\n"
+ "movd %1, %%mm1\n"
+ "paddusw (Blenders__mmx_one), %%mm3\n"
+ "punpcklwd %%mm3, %%mm3\n"
+ "punpcklbw (Blenders__mmx_zero), %%mm0\n"
+ "punpckldq %%mm3, %%mm3\n"
+ "punpcklbw (Blenders__mmx_zero), %%mm1\n"
+ "psubw %%mm3, %%mm4\n"
+ "pmullw %%mm4, %%mm0\n"
+ "psrlw $8, %%mm0\n"
+ "paddw %%mm1, %%mm0\n"
+ "packuswb %%mm0, %%mm0\n"
+ "movd %%mm0, %%eax\n"
+ :
+ : "m" (a), "m" (b)
+ : "%esi", "%mm0", "%mm1", "%mm3", "%mm4" );
+#endif
+}
+
+// returns a*(1-Alpha(b)*W) + b*W, clamped (W is scalar 0-0xff).
+unsigned int inline Blenders::BLEND_ADJ3_MMX(unsigned int a, unsigned int b, int w)
+{
+#ifdef WIN32
+ __asm
+ {
+ movd mm3, [b] // VVVVVVVV
+ movd mm5, [w]
+
+ movd mm0, [a]
+ psrld mm3, 24
+
+ movd mm1, [b]
+ paddusw mm3, [Blenders__mmx_one]
+
+ movq mm4, [Blenders__mmx_revn2]
+ pmullw mm3, mm5
+
+ packuswb mm5, mm5
+ punpcklbw mm0, [Blenders__mmx_zero]
+
+ punpcklwd mm5, mm5
+ punpcklbw mm1, [Blenders__mmx_zero]
+
+ psrlw mm3, 8
+ punpckldq mm5, mm5
+
+ paddusw mm3, [Blenders__mmx_one]
+
+ punpcklwd mm3, mm3 // HHVVHHVV
+
+ punpckldq mm3, mm3 // HHVVHHVV HHVVHHVV
+
+
+ psubw mm4, mm3
+
+ pmullw mm0, mm4
+ pmullw mm1, mm5
+
+ paddusw mm0, mm1
+
+ psrlw mm0, 8
+
+ packuswb mm0, mm0
+
+ movd eax, mm0
+ }
+#else
+ __asm__ volatile (
+ "movd %2, %%mm3\n"
+ "movd %0, %%mm5\n"
+ "movd %1, %%mm0\n"
+ "psrld $24, %%mm3\n"
+ "movd %2, %%mm1\n"
+ "paddusw (Blenders__mmx_one), %%mm3\n"
+ "movq (Blenders__mmx_revn2), %%mm4\n"
+ "pmullw %%mm5, %%mm3\n"
+ "packuswb %%mm5, %%mm5 \n"
+ "punpcklbw (Blenders__mmx_zero), %%mm0\n"
+ "punpcklwd %%mm5, %%mm5\n"
+ "punpcklbw (Blenders__mmx_zero), %%mm1\n"
+ "psrlw $8, %%mm3\n"
+ "punpckldq %%mm5, %%mm5\n"
+ "paddusw (Blenders__mmx_one), %%mm3\n"
+ "punpcklwd %%mm3, %%mm3\n"
+ "punpckldq %%mm3, %%mm3\n"
+ "psubw %%mm3, %%mm4\n"
+ "pmullw %%mm4, %%mm0\n"
+ "pmullw %%mm5, %%mm1\n"
+ "paddusw %%mm1, %%mm0\n"
+ "psrlw $8, %%mm0\n"
+ "packuswb %%mm0, %%mm0\n"
+ "movd %%mm0, %%eax\n"
+
+ :
+ : "m" (w), "m" (a), "m" (b)
+ : "%mm0", "%mm1", "%mm4", "%mm3", "%mm5" );
+#endif
+}
+
+// does bilinear filtering. p1 is upper left pixel, w is width of framebuffer
+// xp and yp's low 16 bits are used for the subpixel positioning.
+unsigned int inline Blenders::BLEND4_MMX(unsigned int *p1, unsigned int w, int xp, int yp)
+{
+#ifdef WIN32
+ __asm
+ {
+ movd mm6, xp
+ mov eax, p1
+
+ movd mm7, yp
+ mov esi, w
+
+ movq mm4, Blenders__mmx_revn2
+ psrlw mm6, 8
+
+ movq mm5, Blenders__mmx_revn2
+ psrlw mm7, 8
+
+ movd mm0, [eax]
+ punpcklwd mm6, mm6
+
+ movd mm1, [eax + 4]
+ punpcklwd mm7, mm7
+
+ movd mm2, [eax + esi*4]
+ punpckldq mm6, mm6
+
+ movd mm3, [eax + esi*4 + 4]
+ punpckldq mm7, mm7
+
+ punpcklbw mm0, [Blenders__mmx_zero]
+ psubw mm4, mm6
+
+ punpcklbw mm1, [Blenders__mmx_zero]
+ pmullw mm0, mm4
+
+ punpcklbw mm2, [Blenders__mmx_zero]
+ pmullw mm1, mm6
+
+ punpcklbw mm3, [Blenders__mmx_zero]
+ psubw mm5, mm7
+
+ pmullw mm2, mm4
+ pmullw mm3, mm6
+
+ paddw mm0, mm1
+ // stall (mm0)
+
+ psrlw mm0, 8
+ // stall (waiting for mm3/mm2)
+
+ paddw mm2, mm3
+ pmullw mm0, mm5
+
+ psrlw mm2, 8
+ // stall (mm2)
+
+ pmullw mm2, mm7
+ // stall
+
+ // stall (mm2)
+
+ paddw mm0, mm2
+ // stall
+
+ psrlw mm0, 8
+ // stall
+
+ packuswb mm0, mm0
+ // stall
+
+ movd eax, mm0
+ }
+#else
+ __asm__ volatile (
+ "movd %2, %%mm6\n"
+ "mov %0, %%eax\n"
+ "movd %3, %%mm7\n"
+ "mov %1, %%esi\n"
+ "movq (Blenders__mmx_revn2), %%mm4\n"
+ "psrlw $8, %%mm6\n"
+ "movq (Blenders__mmx_revn2), %%mm5\n"
+ "psrlw $8, %%mm7\n"
+ "movd (%%eax), %%mm0\n"
+ "punpcklwd %%mm6,%%mm6\n"
+ "movd 4(%%eax), %%mm1\n"
+ "punpcklwd %%mm7,%%mm7\n"
+ "movd (%%eax,%%esi,4), %%mm2\n"
+ "punpckldq %%mm6,%%mm6\n"
+ "movd 4(%%eax,%%esi,4), %%mm3\n"
+ "punpckldq %%mm7,%%mm7\n"
+ "punpcklbw (Blenders__mmx_zero), %%mm0\n"
+ "psubw %%mm6, %%mm4\n"
+ "punpcklbw (Blenders__mmx_zero), %%mm1\n"
+ "pmullw %%mm4, %%mm0\n"
+ "punpcklbw (Blenders__mmx_zero), %%mm2\n"
+ "pmullw %%mm6, %%mm1\n"
+ "punpcklbw (Blenders__mmx_zero), %%mm3\n"
+ "psubw %%mm7, %%mm5\n"
+ "pmullw %%mm4, %%mm2\n"
+ "pmullw %%mm6, %%mm3\n"
+ "paddw %%mm1, %%mm0\n"
+ "psrlw $8, %%mm0\n"
+ "paddw %%mm3, %%mm2\n"
+ "pmullw %%mm5, %%mm0\n"
+ "psrlw $8, %%mm2\n"
+ "pmullw %%mm7, %%mm2\n"
+ "paddw %%mm2, %%mm0\n"
+ "psrlw $8, %%mm0\n"
+ "packuswb %%mm0, %%mm0\n"
+ "movd %%mm0, %%eax\n"
+
+ :
+ : "m" (p1), "m" (w), "m" (xp), "m" (yp)
+ : "%mm0", "%mm1", "%mm4", "%mm3", "%mm5" );
+
+#endif
+}
+
+#ifdef WIN32
+#pragma warning( pop )
+#endif
+
+#endif // ndef NO_MMX
+
+
+#endif
diff --git a/Src/tataki/canvas/PaintCanvas.h b/Src/tataki/canvas/PaintCanvas.h
new file mode 100644
index 00000000..f32e74e4
--- /dev/null
+++ b/Src/tataki/canvas/PaintCanvas.h
@@ -0,0 +1,3 @@
+#ifdef __APPLE__
+#include "mac/PaintCanvas.h"
+#endif \ No newline at end of file
diff --git a/Src/tataki/canvas/bltcanvas.h b/Src/tataki/canvas/bltcanvas.h
new file mode 100644
index 00000000..6ffa07a5
--- /dev/null
+++ b/Src/tataki/canvas/bltcanvas.h
@@ -0,0 +1,5 @@
+#ifdef _WIN32
+#include "win/bltcanvas.h"
+#elif defined(__APPLE__)
+#include "mac/bltcanvas.h"
+#endif
diff --git a/Src/tataki/canvas/canvas.h b/Src/tataki/canvas/canvas.h
new file mode 100644
index 00000000..b645a654
--- /dev/null
+++ b/Src/tataki/canvas/canvas.h
@@ -0,0 +1,5 @@
+#ifdef _WIN32
+#include "win/canvas.h"
+#elif defined(__APPLE__)
+#include "mac/canvas.h"
+#endif \ No newline at end of file
diff --git a/Src/tataki/canvas/ifc_canvas.cpp b/Src/tataki/canvas/ifc_canvas.cpp
new file mode 100644
index 00000000..b209c9de
--- /dev/null
+++ b/Src/tataki/canvas/ifc_canvas.cpp
@@ -0,0 +1 @@
+#include "ifc_canvas.h" \ No newline at end of file
diff --git a/Src/tataki/canvas/ifc_canvas.h b/Src/tataki/canvas/ifc_canvas.h
new file mode 100644
index 00000000..6c7796cf
--- /dev/null
+++ b/Src/tataki/canvas/ifc_canvas.h
@@ -0,0 +1,165 @@
+#ifndef NULLSOFT_TATAKI_IFC_CANVAS_H
+#define NULLSOFT_TATAKI_IFC_CANVAS_H
+
+#include <bfc/dispatch.h>
+#include <bfc/platform/platform.h>
+#include <api/service/svcs/svc_font.h> // for STDFONT_* stuff. should make a std_font thingy later
+#include <bfc/wasabi_std.h> // for WASABI_DEFAULT_FONTNAMEW
+
+namespace Wasabi
+{
+ // benski> move this to std_font later
+struct FontInfo
+{
+ FontInfo()
+ {
+ // defaults
+ face = WASABI_DEFAULT_FONTNAMEW;
+ pointSize = 12;
+ bold = 0;
+ opaque = false;
+ underline = false;
+ italic = false;
+ alignFlags = STDFONT_LEFT;
+ antialias = 1;
+ bgColor = RGBA(255, 255, 255, 255);
+ color = RGBA(0, 0, 0, 0);
+ }
+
+ const wchar_t *face;
+ unsigned int pointSize;
+ int bold; // bold level
+ bool opaque;
+ bool underline;
+ bool italic;
+ int alignFlags;
+ int antialias; // anti-alias level
+ ARGB32 color;
+ ARGB32 bgColor;
+};
+}
+
+class ifc_window;
+// abstract base class: safe to use in API
+class NOVTABLE ifc_canvas : public Dispatchable
+{
+protected:
+ ifc_canvas()
+ {} // protect constructor
+ ~ifc_canvas()
+ {}
+
+public:
+ DISPATCH_CODES
+ {
+ GETHDC = 100,
+ GETROOTWND = 200,
+ GETBITS = 300,
+ GETOFFSETS = 400,
+ ISFIXEDCOORDS = 500,
+ GETDIM = 600,
+ GETTEXTFONT = 700,
+ GETTEXTSIZE = 710,
+ GETTEXTBOLD = 720,
+ GETTEXTOPAQUE = 730,
+ GETTEXTALIGN = 740,
+ GETTEXTCOLOR = 750,
+ GETTEXTBKCOLOR = 760,
+ GETTEXTAA = 770,
+ GETTEXTUNDERLINE = 780,
+ GETTEXTITALIC = 790,
+ GETCLIPBOX = 800,
+ };
+public:
+ HDC getHDC();
+ ifc_window *getRootWnd();
+ void *getBits();
+ void getOffsets(int *x, int *y);
+ bool isFixedCoords(); //FG> allows onPaint to handle double buffers as well as normal DCs
+ bool getDim(int *w, int *h = NULL, int *p = NULL); // w & h in pixels, pitch in bytes. 0 on success.
+ int getClipBox(RECT *r); // returns 0 if no clipping region
+ const wchar_t *getTextFont();
+ int getTextSize();
+ int getTextBold();
+ int getTextAntialias();
+ int getTextOpaque();
+ int getTextUnderline();
+ int getTextItalic();
+ int getTextAlign();
+ ARGB32 getTextColor();
+ ARGB32 getTextBkColor();
+};
+
+
+inline HDC ifc_canvas::getHDC()
+{
+ return _call(ifc_canvas::GETHDC, (HDC)0);
+}
+inline ifc_window *ifc_canvas::getRootWnd()
+{
+ return _call(ifc_canvas::GETROOTWND, (ifc_window*)0);
+}
+inline void *ifc_canvas::getBits()
+{
+ return _call(ifc_canvas::GETBITS, (void *)0);
+}
+inline void ifc_canvas::getOffsets(int *x, int *y)
+{
+ _voidcall(ifc_canvas::GETOFFSETS, x, y);
+}
+inline bool ifc_canvas::isFixedCoords()
+{ //FG> allows onPaint to handle double buffers as well as normal DCs
+ return _call(ifc_canvas::ISFIXEDCOORDS, false);
+}
+inline bool ifc_canvas::getDim(int *w, int *h, int *p)
+{ // w & h in pixels, pitch in bytes. 0 on success.
+ return _call(ifc_canvas::GETDIM, false, w, h, p);
+}
+inline int ifc_canvas::getClipBox(RECT *r)
+{ // returns 0 if no clipping region
+ return _call(ifc_canvas::GETCLIPBOX, 0, r);
+}
+
+inline const wchar_t *ifc_canvas::getTextFont()
+{
+ return _call(ifc_canvas::GETTEXTFONT, L"");
+}
+inline int ifc_canvas::getTextSize()
+{
+ return _call(ifc_canvas::GETTEXTSIZE, -1);
+}
+inline int ifc_canvas::getTextBold()
+{
+ return _call(ifc_canvas::GETTEXTBOLD, 0);
+}
+inline int ifc_canvas::getTextAntialias()
+{
+ return _call(ifc_canvas::GETTEXTAA, 0);
+}
+inline int ifc_canvas::getTextOpaque()
+{
+ return _call(ifc_canvas::GETTEXTOPAQUE, 0);
+}
+inline int ifc_canvas::getTextUnderline()
+{
+ return _call(ifc_canvas::GETTEXTUNDERLINE, 0);
+}
+inline int ifc_canvas::getTextItalic()
+{
+ return _call(ifc_canvas::GETTEXTITALIC, 0);
+}
+inline int ifc_canvas::getTextAlign()
+{
+ return _call(ifc_canvas::GETTEXTALIGN, -1);
+}
+inline ARGB32 ifc_canvas::getTextColor()
+{
+ return _call(ifc_canvas::GETTEXTCOLOR, RGB(0, 0, 0));
+}
+inline ARGB32 ifc_canvas::getTextBkColor()
+{
+ return _call(ifc_canvas::GETTEXTBKCOLOR, RGB(255, 255, 255));
+}
+
+typedef ifc_canvas api_canvas;
+#endif
diff --git a/Src/tataki/canvas/mac/PaintCanvas.cpp b/Src/tataki/canvas/mac/PaintCanvas.cpp
new file mode 100644
index 00000000..6cfeb126
--- /dev/null
+++ b/Src/tataki/canvas/mac/PaintCanvas.cpp
@@ -0,0 +1,51 @@
+#include "PaintCanvas.h"
+
+PaintCanvas::PaintCanvas()
+{
+ qdcontext=0;
+}
+
+bool PaintCanvas::beginPaint(BaseWnd *wnd)
+{
+ HIWindowRef macWnd = wnd->getOsWindowHandle();
+
+ qdcontext = GetWindowPort(macWnd);
+ QDBeginCGContext(qdcontext, &context);
+
+ return true;
+}
+
+PaintCanvas::~PaintCanvas()
+{
+ if (qdcontext)
+ QDEndCGContext(qdcontext, &context);
+}
+
+WndCanvas::WndCanvas()
+{
+ qdcontext=0;
+}
+
+WndCanvas::~WndCanvas()
+{
+ if (qdcontext)
+ QDEndCGContext(qdcontext, &context);
+}
+
+int WndCanvas::attachToClient(BaseWnd *basewnd)
+{
+ HIWindowRef macWnd = basewnd->getOsWindowHandle();
+
+ qdcontext = GetWindowPort(macWnd);
+ QDBeginCGContext(qdcontext, &context);
+ return 1;
+}
+
+
+TextInfoCanvas::TextInfoCanvas(BaseWnd */*unused*/)
+{
+}
+
+TextInfoCanvas::~TextInfoCanvas()
+{
+}
diff --git a/Src/tataki/canvas/mac/PaintCanvas.h b/Src/tataki/canvas/mac/PaintCanvas.h
new file mode 100644
index 00000000..58379508
--- /dev/null
+++ b/Src/tataki/canvas/mac/PaintCanvas.h
@@ -0,0 +1,46 @@
+#ifndef NULLSOFT_WASABI_OSX_PAINTCANVAS_H
+#define NULLSOFT_WASABI_OSX_PAINTCANVAS_H
+
+#include <tataki/export.h>
+#include <tataki/canvas/canvas.h>
+#include <api/wnd/basewnd.h>
+
+class TATAKIAPI PaintCanvas : public Canvas
+{
+public:
+ PaintCanvas();
+ ~PaintCanvas();
+ bool beginPaint(BaseWnd *wnd);
+protected:
+ CGrafPtr qdcontext;
+};
+
+class TATAKIAPI PaintBltCanvas : public PaintCanvas
+{
+public:
+ bool beginPaintNC(BaseWnd *wnd)
+ {
+ return beginPaint(wnd);
+ }
+};
+#warning port PaintBltCanvas
+class TATAKIAPI WndCanvas : public Canvas
+{
+public:
+ WndCanvas();
+ virtual ~WndCanvas();
+
+ // address client area
+ int attachToClient(BaseWnd *basewnd);
+
+private:
+ CGrafPtr qdcontext;
+};
+
+class TATAKIAPI TextInfoCanvas : public Canvas
+{
+public:
+ TextInfoCanvas(BaseWnd *baseWnd);
+ virtual ~TextInfoCanvas();
+};
+#endif \ No newline at end of file
diff --git a/Src/tataki/canvas/mac/bltcanvas.h b/Src/tataki/canvas/mac/bltcanvas.h
new file mode 100644
index 00000000..e1005dc8
--- /dev/null
+++ b/Src/tataki/canvas/mac/bltcanvas.h
@@ -0,0 +1,27 @@
+#ifndef _BLTCANVAS_H
+#define _BLTCANVAS_H
+
+#include <tataki/export.h>
+#include "canvas.h"
+
+class TATAKIAPI BltCanvas : public Canvas
+{
+public:
+ BltCanvas();
+ BltCanvas(int width, int height, OSWINDOWHANDLE wnd);
+
+ // override blit and stretchblit so we can use CGContextDrawLayerAtPoint/CGContextDrawLayerInRect
+ virtual void blit(int srcx, int srcy, Canvas *dest, int dstx, int dsty, int dstw, int dsth);
+ void blitToRect(api_canvas *canvas, RECT *src, RECT *dst, int alpha = 255);
+
+ virtual void stretchblit(int srcx, int srcy, int srcw, int srch, Canvas *dest, int dstx, int dsty, int dstw, int dsth);
+ void stretchToRectAlpha(api_canvas *canvas, RECT *src, RECT *dst, int alpha = 255);
+
+ void DestructiveResize(int w, int h, int nb_bpp = 32); // resizes the bitmap, destroying the contents
+ void fillBits(ARGB32 color);
+
+protected:
+ CGLayerRef layer;
+};
+
+#endif
diff --git a/Src/tataki/canvas/mac/canvas.h b/Src/tataki/canvas/mac/canvas.h
new file mode 100644
index 00000000..5258af4e
--- /dev/null
+++ b/Src/tataki/canvas/mac/canvas.h
@@ -0,0 +1,70 @@
+#ifndef NULLSOFT_WASABI_CANVAS_H
+#define NULLSOFT_WASABI_CANVAS_H
+
+#include <tataki/export.h>
+#include <Carbon/Carbon.h>
+#include <tataki/canvas/api_canvas.h>
+#include <bfc/platform/platform.h>
+#include <api/service/svcs/svc_font.h> // for STDFONT_* stuff. should make a std_font thingy later
+#include <bfc/std.h> // for WASABI_DEFAULT_FONTNAMEW
+class BaseWnd;
+class api_region;
+
+class TATAKIAPI Canvas : public api_canvas
+{
+public:
+ Canvas() :context(0), wnd(0) {}
+ Canvas(CGContextRef _context) : context(_context), wnd(0) {}
+ Canvas(CGrafPtr _context);
+ HDC getHDC();
+ void fillRect(const RECT *r, RGB32 color);
+ void fillRgn(api_region *r, RGB32 color);
+ void setBaseWnd(BaseWnd *_wnd) { wnd=_wnd; }
+ void selectClipRgn(api_region *r);
+
+ virtual void blit(int srcx, int srcy, Canvas *dest, int dstx, int dsty, int dstw, int dsth);
+ virtual void stretchblit(int srcx, int srcy, int srcw, int srch, Canvas *dest, int dstx, int dsty, int dstw, int dsth);
+
+ void textOut(int x, int y, const wchar_t *txt, const Wasabi::FontInfo *fontInfo);
+
+ static float getSystemFontScale() { return 1.0f; }
+
+ int getTextWidth(const wchar_t *text, const Wasabi::FontInfo *fontInfo);
+ int getTextHeight(const wchar_t *text, const Wasabi::FontInfo *fontInfo);
+ int getTextHeight(const Wasabi::FontInfo *fontInfo)
+ {
+ return getTextHeight(L"M", fontInfo);
+ }
+ void getTextExtent(const wchar_t *text, int *w, int *h, const Wasabi::FontInfo *fontInfo);
+ void textOutCentered(RECT *r, const wchar_t *txt, const Wasabi::FontInfo *fontInfo);
+ void textOut(int x, int y, int w, int h, const wchar_t *txt, const Wasabi::FontInfo *fontInfo);
+ void textOutEllipsed(int x, int y, int w, int h, const wchar_t *txt, const Wasabi::FontInfo *fontInfo);
+
+ void drawSysObject(const RECT *r, int sysobj, int alpha=255);
+protected:
+ RECVS_DISPATCH;
+
+ CGContextRef context;
+ BaseWnd *wnd; // TODO: not 100% sure we'll need this. win32 version has it so we'll keep it for now
+};
+
+class TATAKIAPI BaseCloneCanvas : public Canvas
+{
+public:
+ BaseCloneCanvas(api_canvas *cloner=NULL);
+ virtual ~BaseCloneCanvas();
+
+ int clone(api_canvas *cloner);
+};
+
+namespace DrawSysObj {
+ enum {
+ BUTTON, BUTTON_PUSHED, BUTTON_DISABLED,
+ OSBUTTON, OSBUTTON_PUSHED, OSBUTTON_DISABLED,
+ OSBUTTON_CLOSE, OSBUTTON_CLOSE_PUSHED, OSBUTTON_CLOSE_DISABLED,
+ OSBUTTON_MINIMIZE, OSBUTTON_MINIMIZE_PUSHED, OSBUTTON_MINIMIZE_DISABLED,
+ OSBUTTON_MAXIMIZE, OSBUTTON_MAXIMIZE_PUSHED, OSBUTTON_MAXIMIZE_DISABLED,
+ };
+};
+
+#endif
diff --git a/Src/tataki/canvas/mac/osx_canvas_layer.cpp b/Src/tataki/canvas/mac/osx_canvas_layer.cpp
new file mode 100644
index 00000000..c6f80347
--- /dev/null
+++ b/Src/tataki/canvas/mac/osx_canvas_layer.cpp
@@ -0,0 +1,95 @@
+#include <tataki/canvas/bltcanvas.h>
+
+inline float QuartzBlue(RGB32 color)
+{
+ unsigned char *pixel = (unsigned char *)&color;
+ return pixel[0] / 255.f;
+}
+
+inline float QuartzGreen(RGB32 color)
+{
+ unsigned char *pixel = (unsigned char *)&color;
+ return pixel[1] / 255.f;
+}
+
+inline float QuartzRed(RGB32 color)
+{
+ unsigned char *pixel = (unsigned char *)&color;
+ return pixel[2] / 255.f;
+}
+
+inline float QuartzAlpha(RGB32 color)
+{
+ unsigned char *pixel = (unsigned char *)&color;
+ return pixel[3] / 255.f;
+}
+
+BltCanvas::BltCanvas(int width, int height, OSWINDOWHANDLE wnd)
+{
+ CGrafPtr qdcontext = GetWindowPort(wnd);
+ CGContextRef temp;
+ QDBeginCGContext(qdcontext, &temp);
+ CGSize size = CGSizeMake(width, height);
+ layer = CGLayerCreateWithContext(temp, size, NULL);
+ context = CGLayerGetContext(layer);
+ QDEndCGContext(qdcontext, &temp);
+}
+
+void BltCanvas::blit(int srcx, int srcy, Canvas *dest, int dstx, int dsty, int dstw, int dsth)
+{
+ CGPoint point = CGPointMake(dstx-srcx, dsty-srcy);
+ CGContextDrawLayerAtPoint(dest->getHDC(), point, layer);
+}
+
+void BltCanvas::blitToRect(api_canvas *canvas, RECT *src, RECT *dst, int alpha)
+{
+ CGContextRef dest = canvas->getHDC();
+ CGContextSaveGState(dest);
+ CGContextSetAlpha(dest, (float)alpha/255.f);
+ // TODO: deal with width properly
+ CGRect rect = CGRectMake(dst->left - src->left, dst->top - src->top, dst->right - dst->left, dst->bottom - dst->top);
+ CGContextDrawLayerInRect(dest, rect, layer);
+ CGContextRestoreGState(dest);
+}
+
+void BltCanvas::stretchblit(int srcx, int srcy, int srcw, int srch, Canvas *dest, int dstx, int dsty, int dstw, int dsth)
+{
+ CGContextSaveGState(context);
+ CGContextTranslateCTM(context, srcx, srcy);
+ CGRect rect = CGRectMake(dstx, dsty, dstw, dsth);
+ CGContextDrawLayerInRect(dest->getHDC(), rect, layer);
+ CGContextRestoreGState(context);
+}
+
+void BltCanvas::stretchToRectAlpha(api_canvas *canvas, RECT *src, RECT *dst, int alpha)
+{
+ CGContextRef dest = canvas->getHDC();
+ CGContextSaveGState(dest);
+ CGContextSetAlpha(dest, (float)alpha/255.f);
+// TODO: deal with width properly
+ CGRect rect = CGRectMake(dst->left - src->left, dst->top - src->top, dst->right - dst->left, dst->bottom - dst->top);
+ CGContextDrawLayerInRect(dest, rect, layer);
+ CGContextRestoreGState(dest);
+}
+
+void BltCanvas::DestructiveResize(int w, int h, int nb_bpp)
+{
+ CGSize size = CGSizeMake(w, h);
+ CGLayerRef newlayer = CGLayerCreateWithContext(context, size, NULL);
+ CGContextRelease(context);
+ CGLayerRelease(layer);
+ layer = newlayer;
+ context = CGLayerGetContext(layer);
+}
+
+void BltCanvas::fillBits(ARGB32 color)
+{
+ CGContextSetRGBFillColor(context,
+ QuartzRed(color), // red
+ QuartzGreen(color), // green
+ QuartzBlue(color), // blue
+ QuartzAlpha(color) // alpha
+ );
+
+ CGContextFillRect(context, CGRectInfinite);
+} \ No newline at end of file
diff --git a/Src/tataki/canvas/mac/osx_canvas_quartz.cpp b/Src/tataki/canvas/mac/osx_canvas_quartz.cpp
new file mode 100644
index 00000000..dcbae59f
--- /dev/null
+++ b/Src/tataki/canvas/mac/osx_canvas_quartz.cpp
@@ -0,0 +1,275 @@
+#include <bfc/platform/types.h>
+#include <Carbon/Carbon.h>
+#include <tataki/canvas/canvas.h>
+#include <api/wnd/basewnd.h>
+#include <tataki/region/api_region.h>
+
+
+
+/* various functions that might help out
+
+for drawSysObject:
+HIThemeDrawButton
+HIThemeDrawTitleBarWidget for minimize, maximize, exit
+*/
+
+inline float QuartzBlue(RGB32 color)
+{
+ unsigned char *pixel = (unsigned char *)&color;
+ return pixel[0] / 255.f;
+}
+
+inline float QuartzGreen(RGB32 color)
+{
+ unsigned char *pixel = (unsigned char *)&color;
+ return pixel[1] / 255.f;
+
+}
+
+inline float QuartzRed(RGB32 color)
+{
+ unsigned char *pixel = (unsigned char *)&color;
+ return pixel[2] / 255.f;
+
+}
+
+inline float QuartzAlpha(RGB32 color)
+{
+ unsigned char *pixel = (unsigned char *)&color;
+ return pixel[3] / 255.f;
+
+}
+
+Canvas::Canvas(CGrafPtr _context)
+{
+
+}
+
+void Canvas::fillRect(const RECT *r, ARGB32 color)
+{
+ CGContextSetRGBFillColor(context,
+ QuartzRed(color), // red
+ QuartzGreen(color), // green
+ QuartzBlue(color), // blue
+ QuartzAlpha(color) // alpha
+ );
+
+ HIRect rect = HIRectFromRECT(r);
+ CGContextFillRect(context, rect);
+}
+
+void Canvas::fillRgn(api_region *r, ARGB32 color)
+{
+ CGContextSetRGBFillColor(context,
+ QuartzRed(color), // red
+ QuartzGreen(color), // green
+ QuartzBlue(color), // blue
+ QuartzAlpha(color) // alpha
+ );
+
+ HIShapeRef shape = r->getOSHandle();
+ HIShapeReplacePathInCGContext(shape, context);
+ CGContextFillPath(context);
+}
+
+void Canvas::blit(int srcx, int srcy, Canvas *dest, int dstx, int dsty, int dstw, int dsth)
+{
+ // clip dest
+ // Create CGImage from context
+ // CGContextDrawImage
+}
+
+HDC Canvas::getHDC()
+{
+ return context;
+}
+
+void Canvas::selectClipRgn(api_region *r)
+{
+ if (r)
+ {
+ HIShapeRef shape = r->getOSHandle();
+ HIShapeReplacePathInCGContext(shape, context);
+ CGContextClip(context);
+ }
+ else
+ {
+ CGContextClipToRect(context, CGRectInfinite);
+ }
+}
+
+void Canvas::stretchblit(int srcx, int srcy, int srcw, int srch, Canvas *dest, int dstx, int dsty, int dstw, int dsth)
+{
+ // Create CGImage from context
+ // CGContextDrawImage
+}
+
+void Canvas::textOut(int x, int y, const wchar_t *txt, const Wasabi::FontInfo *fontInfo)
+{
+ // TODO: turn this code into a svc_fontI, and use api_font here instead
+ size_t len = wcslen(txt);
+ UniChar *unistr = (UniChar *)malloc((len + 1) * sizeof(UniChar));
+ UniChar *copy = unistr;
+ while (*txt)
+ *copy++=*txt++;
+ *copy=0;
+
+ ATSUStyle style;
+ ATSUCreateStyle(&style);
+
+ CGContextSaveGState(context);
+ CGContextSetRGBFillColor(context,
+ QuartzRed(fontInfo->color), // red
+ QuartzGreen(fontInfo->color), // green
+ QuartzBlue(fontInfo->color), // blue
+ QuartzAlpha(fontInfo->color) // alpha
+ );
+
+ ATSUTextLayout layout;
+ ATSUCreateTextLayout(&layout);
+
+ ATSUSetTextPointerLocation(layout, unistr, kATSUFromTextBeginning, kATSUToTextEnd, len);
+
+ ATSUSetRunStyle(layout, style, kATSUFromTextBeginning, kATSUToTextEnd);
+
+ Rect imageRect;
+ ATSUMeasureTextImage(layout, kATSUFromTextBeginning, kATSUToTextEnd, 0, 0, &imageRect);
+ y-=(imageRect.bottom - imageRect.top);
+ CGContextScaleCTM(context, 1.0, -1.0);
+
+ ATSUAttributeTag tags[] = {kATSUCGContextTag};
+ ATSUAttributeValuePtr values[] = {&context};
+ ByteCount sizes[] = {sizeof(CGContextRef)};
+ ATSUSetLayoutControls(layout, 1, tags, sizes, values);
+ ATSUDrawText(layout, kATSUFromTextBeginning, kATSUToTextEnd, FloatToFixed(x), FloatToFixed(y));
+ ATSUDisposeTextLayout(layout);
+ ATSUDisposeStyle(style);
+ CGContextRestoreGState(context);
+ free(unistr);
+}
+
+void Canvas::drawSysObject(const RECT *r, int sysobj, int alpha)
+{
+#warning TODO
+ using namespace DrawSysObj;
+ switch(sysobj)
+ {
+ case OSBUTTON:
+ {
+ HIRect buttonRect = HIRectFromRECT(r);
+ HIThemeButtonDrawInfo buttonDrawInfo;
+ buttonDrawInfo.version=0;
+ buttonDrawInfo.state = kThemeStateActive;
+ buttonDrawInfo.kind = kThemePushButton;
+ buttonDrawInfo.value = kThemeButtonOn;
+ buttonDrawInfo.adornment = kThemeAdornmentNone;
+ buttonDrawInfo.animation.time.start = 0;
+ buttonDrawInfo.animation.time.current=0;
+ HIThemeDrawButton(&buttonRect, &buttonDrawInfo, context, /*kHIThemeOrientationNormal*/kHIThemeOrientationInverted, 0);
+ }
+ break;
+ case OSBUTTON_PUSHED:
+ {
+ HIRect buttonRect = HIRectFromRECT(r);
+ HIThemeButtonDrawInfo buttonDrawInfo;
+ buttonDrawInfo.version=0;
+ buttonDrawInfo.state = kThemeStatePressed;
+ buttonDrawInfo.kind = kThemePushButton;
+ buttonDrawInfo.value = kThemeButtonOn;
+ buttonDrawInfo.adornment = kThemeAdornmentNone;
+ buttonDrawInfo.animation.time.start = 0;
+ buttonDrawInfo.animation.time.current=0;
+ HIThemeDrawButton(&buttonRect, &buttonDrawInfo, context, /*kHIThemeOrientationNormal*/kHIThemeOrientationInverted, 0);
+ }
+ break;
+ case OSBUTTON_DISABLED:
+ {
+ HIRect buttonRect = HIRectFromRECT(r);
+ HIThemeButtonDrawInfo buttonDrawInfo;
+ buttonDrawInfo.version=0;
+ buttonDrawInfo.state = kThemeStateInactive;
+ buttonDrawInfo.kind = kThemePushButton;
+ buttonDrawInfo.value = kThemeButtonOn;
+ buttonDrawInfo.adornment = kThemeAdornmentNone;
+ buttonDrawInfo.animation.time.start = 0;
+ buttonDrawInfo.animation.time.current=0;
+ HIThemeDrawButton(&buttonRect, &buttonDrawInfo, context, /*kHIThemeOrientationNormal*/kHIThemeOrientationInverted, 0);
+ }
+ break;
+ }
+}
+
+void Canvas::getTextExtent(const wchar_t *text, int *w, int *h, const Wasabi::FontInfo *fontInfo)
+{
+ // TODO: turn this code into a svc_fontI, and use api_font here instead
+ size_t len = wcslen(text);
+ UniChar *unistr = (UniChar *)malloc((len + 1) * sizeof(UniChar));
+ UniChar *copy = unistr;
+ while (*text)
+ *copy++=*text++;
+ *copy=0;
+
+ ATSUStyle style;
+ ATSUCreateStyle(&style);
+
+ ATSUTextLayout layout;
+ ATSUCreateTextLayout(&layout);
+
+ ATSUSetTextPointerLocation(layout, unistr, kATSUFromTextBeginning, kATSUToTextEnd, len);
+
+ ATSUSetRunStyle(layout, style, kATSUFromTextBeginning, kATSUToTextEnd);
+
+ Rect imageRect;
+ ATSUMeasureTextImage(layout, kATSUFromTextBeginning, kATSUToTextEnd, 0, 0, &imageRect);
+ *h=(imageRect.bottom - imageRect.top);
+ *w = (imageRect.right - imageRect.left);
+
+ ATSUDisposeTextLayout(layout);
+ ATSUDisposeStyle(style);
+ free(unistr);
+}
+
+void Canvas::textOutCentered(RECT *r, const wchar_t *txt, const Wasabi::FontInfo *fontInfo)
+{
+ textOut(r->left, r->top, txt, fontInfo);
+}
+
+
+#define CBCLASS Canvas
+START_DISPATCH;
+CB(GETHDC, getHDC);
+END_DISPATCH;
+#undef CBCLASS
+
+BaseCloneCanvas::BaseCloneCanvas(api_canvas *cloner)
+{
+ if (cloner != NULL) clone(cloner);
+}
+
+int BaseCloneCanvas::clone(api_canvas *cloner)
+{
+ ASSERTPR(context == NULL, "can't clone twice");
+ context = cloner->getHDC();
+ CGContextRetain(context);
+// bits = cloner->getBits();
+// cloner->getDim(&width, &height, &pitch);
+ // srcwnd = cloner->getBaseWnd();
+// cloner->getOffsets(&xoffset, &yoffset);
+// setTextFont(cloner->getTextFont());
+// setTextSize(cloner->getTextSize());
+// setTextBold(cloner->getTextBold());
+// setTextOpaque(cloner->getTextOpaque());
+// setTextUnderline(cloner->getTextUnderline());
+// setTextItalic(cloner->getTextItalic());
+// setTextAlign(cloner->getTextAlign());
+// setTextColor(cloner->getTextColor());
+// setTextBkColor(cloner->getTextBkColor());
+ return (context != NULL);
+}
+
+BaseCloneCanvas::~BaseCloneCanvas()
+{
+ CGContextRelease(context);
+ context = NULL;
+}
+
diff --git a/Src/tataki/canvas/win/BltCanvas.cpp b/Src/tataki/canvas/win/BltCanvas.cpp
new file mode 100644
index 00000000..5b9a94bc
--- /dev/null
+++ b/Src/tataki/canvas/win/BltCanvas.cpp
@@ -0,0 +1,295 @@
+#include "bltcanvas.h"
+#include <tataki/bitmap/bitmap.h>
+
+BltCanvas::~BltCanvas()
+{
+ if (hdc == NULL) return ;
+
+ // kill the bitmap and its DC
+ SelectObject(hdc, prevbmp);
+ if (ourbmp)
+ {
+ //GdiFlush();
+ DeleteObject(hbmp);
+ }
+ DeleteDC(hdc);
+ hdc = NULL;
+
+ if (skinbmps)
+ {
+ for (int i=0;i<skinbmps->getNumItems();i++)
+ skinbmps->enumItem(i)->Release();
+
+ delete skinbmps;
+ }
+ if (envelope)
+ envelope->Release();
+}
+
+BltCanvas::BltCanvas(HBITMAP bmp)
+{
+ prevbmp = NULL;
+ bits = NULL;
+ fcoord = TRUE;
+ ourbmp = FALSE;
+ skinbmps = NULL;
+ envelope = NULL;
+
+ hbmp = bmp;
+ ASSERT(hbmp != NULL);
+
+ // create tha DC
+ hdc = CreateCompatibleDC(NULL);
+ prevbmp = (HBITMAP)SelectObject(hdc, hbmp);
+}
+
+BltCanvas::BltCanvas()
+{
+ hbmp = NULL;
+ prevbmp = NULL;
+ bits = NULL;
+ fcoord = TRUE;
+ ourbmp = FALSE;
+ bpp = 32; // TODO: benski> pass as parameter?
+ skinbmps = NULL;
+ envelope = NULL;
+ hdc = CreateCompatibleDC(NULL);
+}
+
+BltCanvas::BltCanvas(int w, int h, HWND wnd, int nb_bpp/*, unsigned char *pal, int palsize*/)
+{
+ hbmp = NULL;
+ prevbmp = NULL;
+ bits = NULL;
+ fcoord = TRUE;
+ ourbmp = FALSE;
+ bpp = nb_bpp;
+ skinbmps = NULL;
+ envelope = NULL;
+ hdc = CreateCompatibleDC(NULL);
+ AllocBitmap(w,h,nb_bpp);
+
+ if (hbmp)
+ {
+ // create tha DC
+
+ if (!hdc) {
+// int x = GetLastError();
+ }
+ prevbmp = (HBITMAP)SelectObject(hdc, hbmp);
+ }
+}
+
+void BltCanvas::AllocBitmap(int w, int h, int nb_bpp)
+{
+ ASSERT(!hbmp);
+ ASSERT(w != 0 && h != 0);
+ if (w == 0) w = 1;
+ if (h == 0) h = 1;
+
+ BITMAPINFO bmi;
+ MEMZERO(&bmi, sizeof(BITMAPINFO));
+ //bmi.bmiHeader.biClrUsed = 0; // we memzero above, no need
+ //bmi.bmiHeader.biClrImportant = 0; // we memzero above, no need
+ bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ bmi.bmiHeader.biWidth = ABS(w);
+ bmi.bmiHeader.biHeight = -ABS(h);
+ bmi.bmiHeader.biPlanes = 1;
+ bmi.bmiHeader.biBitCount = nb_bpp;
+ bmi.bmiHeader.biCompression = BI_RGB;
+ //bmi.bmiHeader.biSizeImage = 0; // we memzero above, no need
+ //bmi.bmiHeader.biXPelsPerMeter = 0; // we memzero above, no need
+ //bmi.bmiHeader.biYPelsPerMeter = 0; // we memzero above, no need
+ //GdiFlush();
+ hbmp = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, &bits, NULL, 0);
+
+ if (hbmp == NULL)
+ {
+ return ;
+ }
+
+ ourbmp=TRUE;
+ GetObject(hbmp, sizeof(BITMAP), &bm);
+ width = bm.bmWidth;
+ height = ABS(bm.bmHeight);
+ pitch = bm.bmWidthBytes;
+}
+
+void *BltCanvas::getBits()
+{
+ return bits;
+}
+
+HBITMAP BltCanvas::getBitmap()
+{
+ return hbmp;
+}
+
+SkinBitmap *BltCanvas::getSkinBitmap()
+{
+ // make a SkinBitmap envelope
+ if (!envelope)
+ envelope = new SkinBitmap(getBitmap(), getHDC(), 1, getBits());
+
+ // do not delete envelope, it's deleted in destructor
+ return envelope;
+}
+
+SkinBitmap *BltCanvas::makeSkinBitmap()
+{
+ // make a clone of the bitmap - JF> what was that crap about envelopes?
+ SkinBitmap *clone = new SkinBitmap(getBitmap(), getHDC(), 1);
+
+ if (!skinbmps)
+ skinbmps = new PtrList<SkinBitmap>;
+ skinbmps->addItem(clone);
+
+ return clone;
+}
+
+void BltCanvas::disposeSkinBitmap(SkinBitmap *b)
+{
+ if (skinbmps->haveItem(b))
+ {
+ skinbmps->removeItem(b);
+ b->Release();
+ }
+ else
+ {
+ DebugString("disposeSkinBitmap called on unknown pointer, you should call it from the object used to makeSkinBitmap()\n");
+ }
+}
+
+void BltCanvas::fillBits(COLORREF color)
+{
+ if (bpp == 32)
+ { // clear out the bits
+ DWORD *dwbits = (DWORD *)bits;
+ MEMFILL<DWORD>(dwbits, color, bm.bmWidth * bm.bmHeight);
+ }
+}
+
+void BltCanvas::vflip(int vert_cells)
+{
+ ASSERT(bits != NULL);
+ // BITMAP bm;
+ // int r = GetObject(hbmp, sizeof(BITMAP), &bm);
+ // if (r == 0) return;
+ int w = bm.bmWidth, h = bm.bmHeight;
+ int bytes = 4 * w;
+ __int8 *tmpbuf = (__int8 *)MALLOC(bytes);
+ if (tmpbuf)
+ {
+ int cell_h = h / vert_cells;
+ for (int j = 0; j < vert_cells; j++)
+ for (int i = 0; i < cell_h / 2; i++)
+ {
+ char *p1, *p2;
+ p1 = (__int8 *)bits + bytes * i + (j * cell_h * bytes);
+ p2 = (__int8 *)bits + bytes * ((cell_h - 1) - i) + (j * cell_h * bytes);
+ if (p1 == p2) continue;
+ MEMCPY(tmpbuf, p1, bytes);
+ MEMCPY(p1, p2, bytes);
+ MEMCPY(p2, tmpbuf, bytes);
+ }
+ FREE(tmpbuf);
+ }
+}
+
+void BltCanvas::hflip(int hor_cells)
+{
+ ASSERT(bits != NULL);
+ // todo: optimize
+ int w = bm.bmWidth, h = bm.bmHeight;
+ for (int i = 0;i < hor_cells;i++)
+ for (int x = 0;x < w / 2 / hor_cells;x++)
+ for (int y = 0;y < h;y++)
+ {
+ int *p = ((int *)bits) + x + y * w + (i * w / hor_cells);
+ int *d = ((int *)bits) + ((w / hor_cells) - x) + y * w + (i * w / hor_cells) - 1;
+ int t = *p;
+ *p = *d;
+ *d = t;
+ }
+}
+
+void BltCanvas::maskColor(COLORREF from, COLORREF to)
+{
+ int n = bm.bmWidth * bm.bmHeight;
+ //GdiFlush();
+ DWORD *b = (DWORD *)getBits();
+ from &= 0xffffff;
+ while (n--)
+ {
+ if ((*b & 0xffffff) == from)
+ {
+ *b = to;
+ }
+ else *b |= 0xff000000; // force all other pixels non masked
+ b++;
+ }
+}
+
+void BltCanvas::makeAlpha(int newalpha)
+{
+ int w, h;
+ getDim(&w, &h, NULL);
+ premultiply((ARGB32 *)getBits(), w*h, newalpha);
+}
+
+#if 0
+void BltCanvas::premultiply(ARGB32 *m_pBits, int nwords, int newalpha)
+{
+ if (newalpha == -1)
+ {
+ for (; nwords > 0; nwords--, m_pBits++)
+ {
+ unsigned char *pixel = (unsigned char *)m_pBits;
+ unsigned int alpha = pixel[3];
+ if (alpha == 255) continue;
+ pixel[0] = (pixel[0] * alpha) >> 8; // blue
+ pixel[1] = (pixel[1] * alpha) >> 8; // green
+ pixel[2] = (pixel[2] * alpha) >> 8; // red
+ }
+ }
+ else
+ {
+ for (; nwords > 0; nwords--, m_pBits++)
+ {
+ unsigned char *pixel = (unsigned char *)m_pBits;
+ pixel[0] = (pixel[0] * newalpha) >> 8; // blue
+ pixel[1] = (pixel[1] * newalpha) >> 8; // green
+ pixel[2] = (pixel[2] * newalpha) >> 8; // red
+ pixel[3] = (pixel[3] * newalpha) >> 8; // alpha
+ }
+ }
+}
+#endif
+
+// benski> this may not be completely safe. it's meant for skinbitmap::blittorect
+// it doesn't take into account skin bitmaps, enveloped bitmaps, or any other things like that
+void BltCanvas::DestructiveResize(int w, int h, int nb_bpp)
+{
+ if (hdc != NULL)
+ {
+ SelectObject(hdc, prevbmp);
+ prevbmp=0;
+ }
+
+ if (ourbmp && hbmp)
+ {
+ DeleteObject(hbmp);
+ hbmp=NULL;
+ ourbmp=FALSE;
+ }
+
+ // create tha DC
+ if (hdc == NULL)
+ hdc = CreateCompatibleDC(NULL);
+
+ AllocBitmap(w,h,nb_bpp);
+
+ prevbmp = (HBITMAP)SelectObject(hdc, hbmp);
+ if (envelope) envelope->Release();
+ envelope=0;
+}
diff --git a/Src/tataki/canvas/win/bltcanvas.h b/Src/tataki/canvas/win/bltcanvas.h
new file mode 100644
index 00000000..250e8ba3
--- /dev/null
+++ b/Src/tataki/canvas/win/bltcanvas.h
@@ -0,0 +1,41 @@
+#ifndef _BLTCANVAS_H
+#define _BLTCANVAS_H
+
+#include "canvas.h"
+#include <tataki/export.h>
+#include <bfc/ptrlist.h>
+class TATAKIAPI BltCanvas : public Canvas
+{
+public:
+ BltCanvas();
+ BltCanvas(int w, int h, HWND wnd=NULL, int nb_bpp=32/*, unsigned __int8 *pal=NULL,int palsize=0*/);
+ BltCanvas(HBITMAP bmp);
+ virtual ~BltCanvas();
+ void *getBits();
+ HBITMAP getBitmap();
+ SkinBitmap *makeSkinBitmap(); // this one makes a new, with own bits
+ SkinBitmap *getSkinBitmap(); // this one gives a skinbitmap envoloppe of this bltcanvas
+ void disposeSkinBitmap(SkinBitmap *b); // call only after makeSkinBitmap
+
+ void fillBits(COLORREF color);
+
+ void vflip(int vert_cells=1);
+ void hflip(int hor_cells=1);
+ void maskColor(COLORREF from, COLORREF to);
+ void makeAlpha(int newalpha=-1); // -1 = premultiply using current alpha
+
+ void DestructiveResize(int w, int h, int nb_bpp = 32); // resizes the bitmap, destroying the contents
+private: // NONPORTABLE
+
+ void AllocBitmap(int w, int h, int nb_bpp);
+ HBITMAP hbmp, prevbmp;
+ PtrList<SkinBitmap> *skinbmps;
+ SkinBitmap *envelope;
+ BITMAP bm;
+ bool ourbmp;
+ int bpp;
+
+ //void premultiply(ARGB32 *m_pBits, int nwords, int newalpha=-1);
+};
+
+#endif
diff --git a/Src/tataki/canvas/win/canvas.h b/Src/tataki/canvas/win/canvas.h
new file mode 100644
index 00000000..179e3498
--- /dev/null
+++ b/Src/tataki/canvas/win/canvas.h
@@ -0,0 +1,368 @@
+//NONPORTABLE: the interface is portable, but the implementation sure isn't
+#ifndef _CANVAS_H
+#define _CANVAS_H
+
+#if defined _WIN64 || defined _WIN32
+#include <ddraw.h>
+#endif
+
+//#include <bfc/common.h>
+#include <tataki/export.h>
+
+class Canvas;
+class MemCanvasBmp;
+class BaseWnd;
+class ifc_window;
+class api_region;
+class SkinBitmap;
+
+#include <bfc/stack.h>
+#include <api/service/svcs/svc_font.h> // for STDFONT_* stuff. should make a std_font thingy later
+#include <bfc/dispatch.h>
+
+enum {
+#ifdef WIN32
+ PENSTYLE_SOLID = PS_SOLID,
+ PENSTYLE_DASH = PS_DASH,
+ PENSTYLE_DOT = PS_DOT,
+#else
+ PENSTYLE_SOLID = LineSolid,
+ PENSTYLE_DASH = LineDoubleDash,
+ PENSTYLE_DOT = LineDoubleDash,
+#endif
+};
+
+#include <tataki/canvas/ifc_canvas.h>
+class ifc_canvas;
+class RegionI;
+typedef struct
+{
+ int style;
+ int width;
+ COLORREF color;
+ HPEN hpen;
+}
+penstruct;
+
+class TATAKIAPI NOVTABLE Canvas : public ifc_canvas
+{
+protected:
+ Canvas();
+public:
+ virtual ~Canvas();
+
+// ifc_canvas stuff
+ HDC getHDC();
+ ifc_window *getRootWnd();
+ void *getBits();
+ void getOffsets(int *x, int *y);
+ bool isFixedCoords();
+ bool getDim(int *w, int *h, int *p);
+ void setBaseWnd(BaseWnd *b);
+// end ifc_canvas stuff
+
+ virtual BaseWnd *getBaseWnd();
+
+ // graphics commands
+ void fillRect(const RECT *r, COLORREF color);
+ void fillRectAlpha(const RECT *r, COLORREF color, int alpha);
+ void fillRgn(RegionI *r, COLORREF color);
+ void drawRect(const RECT *r, int solid, COLORREF color, int alpha = 255);
+
+ // text commands
+ const wchar_t *getTextFont();
+ int getTextSize();
+ int getTextBold();
+ int getTextAntialias();
+ int getTextOpaque();
+ int getTextUnderline();
+ int getTextItalic();
+ int getTextAlign();
+ COLORREF getTextColor();
+ COLORREF getTextBkColor();
+
+ void pushPen(COLORREF color);
+ void pushPen(int style, int width, COLORREF color);
+ void popPen();
+
+ int getPenStyle();
+ COLORREF getPenColor();
+ int getPenWidth();
+
+ // normal text
+ void textOut(int x, int y, const wchar_t *txt, const Wasabi::FontInfo *fontInfo);
+ void textOut(int x, int y, int w, int h, const wchar_t *txt, const Wasabi::FontInfo *fontInfo);
+ void textOutEllipsed(int x, int y, int w, int h, const wchar_t *txt, const Wasabi::FontInfo *fontInfo);
+ // returns height used
+ void textOutWrapped(int x, int y, int w, int h, const wchar_t *txt, const Wasabi::FontInfo *fontInfo);
+ void textOutWrappedPathed(int x, int y, int w, const wchar_t *txt, const Wasabi::FontInfo *fontInfo);
+ void textOutCentered(RECT *r, const wchar_t *txt, const Wasabi::FontInfo *fontInfo);
+
+ int getTextWidth(const wchar_t *text, const Wasabi::FontInfo *fontInfo);
+ int getTextHeight(const wchar_t *text, const Wasabi::FontInfo *fontInfo);
+ void getTextExtent(const wchar_t *text, int *w, int *h, const Wasabi::FontInfo *fontInfo);
+ int getTextHeight(const Wasabi::FontInfo *fontInfo)
+ {
+ return getTextHeight(L"M", fontInfo);
+ }
+
+ void selectClipRgn(api_region *r);
+ int getClipBox(RECT *r); // returns 0 if no clipping region
+ int getClipRgn(api_region *r); // returns 0 if no clipping region
+
+ // Deprecated?
+ void moveTo(int x, int y);
+ void lineTo(int x, int y);
+
+ void lineDraw(int fromX, int fromY, int toX, int toY);
+
+ void drawSysObject(const RECT *r, int sysobj, int alpha = 255);
+
+ void blit(int srcx, int srcy, Canvas *dest, int dstx, int dsty, int dstw, int dsth);
+ void blitAlpha(ifc_canvas *canvas, int x, int y, int alpha = 255);
+ void blitToRect(ifc_canvas *canvas, RECT *src, RECT *dst, int alpha = 255);
+ void stretch(ifc_canvas *canvas, int x, int y, int w, int h);
+ // src* are in 16.16 fixed point
+ void stretchblit(int srcx, int srcy, int srcw, int srch, Canvas *dest, int dstx, int dsty, int dstw, int dsth);
+ void stretchToRectAlpha(ifc_canvas *canvas, RECT *src, RECT *dst, int alpha = 255);
+ void antiAliasTo(Canvas *dest, int w, int h, int aafactor);
+
+ int getXOffset() const
+ {
+ return xoffset;
+ }
+ int getYOffset() const
+ {
+ return yoffset;
+ }
+ void offsetRect(RECT *r);
+ void debug();
+
+ void colorToColor(COLORREF from, COLORREF to, RECT *r);
+ double getSystemFontScale();
+ static void premultiply(ARGB32 *m_pBits, int nwords, int newalpha = -1);
+
+protected:
+ const Wasabi::FontInfo *getFontInfo()
+ {
+ if (userFontInfo)
+ return userFontInfo;
+ else
+ return &canvasFontInfo;
+ }
+
+ RECVS_DISPATCH;
+
+ HDC hdc;
+ void *bits;
+ int width, height, pitch;
+ bool fcoord;
+ int xoffset, yoffset;
+ BaseWnd *srcwnd;
+ Wasabi::FontInfo canvasFontInfo; // to hold our defaults
+ const Wasabi::FontInfo *userFontInfo; // passed from someone calling this function. usually is NULL
+
+private:
+ Stack<penstruct> penstack;
+
+ int penstyle;
+ COLORREF pencolor;
+ int penwidth;
+
+#ifdef WIN32
+ HPEN defpen;
+ HPEN curpen;
+#endif
+#ifdef LINUX
+ int raster_x, raster_y;
+#endif
+
+};
+
+namespace DrawSysObj
+{
+enum {
+ BUTTON, BUTTON_PUSHED, BUTTON_DISABLED,
+ OSBUTTON, OSBUTTON_PUSHED, OSBUTTON_DISABLED,
+ OSBUTTON_CLOSE, OSBUTTON_CLOSE_PUSHED, OSBUTTON_CLOSE_DISABLED,
+ OSBUTTON_MINIMIZE, OSBUTTON_MINIMIZE_PUSHED, OSBUTTON_MINIMIZE_DISABLED,
+ OSBUTTON_MAXIMIZE, OSBUTTON_MAXIMIZE_PUSHED, OSBUTTON_MAXIMIZE_DISABLED,
+};
+};
+
+class TATAKIAPI WndCanvas : public Canvas
+{
+public:
+ WndCanvas();
+ WndCanvas(BaseWnd *basewnd);
+ virtual ~WndCanvas();
+
+ // address client area
+ int attachToClient(BaseWnd *basewnd);
+//CUT // address entire window
+//CUT int attachToWnd(HWND _hWnd); // NONPORTABLE: avoid! mostly for mainwnd
+
+private:
+ HWND hWnd;
+};
+
+class TATAKIAPI PaintCanvas : public Canvas
+{
+public:
+ PaintCanvas();
+ virtual ~PaintCanvas();
+
+ int beginPaint(BaseWnd *basewnd);
+ int beginPaint(HWND wnd);
+ void getRcPaint(RECT *r);
+
+private: // NONPORTABLE
+ HWND hWnd;
+ PAINTSTRUCT ps;
+};
+
+class BltCanvas;
+class TATAKIAPI PaintBltCanvas : public Canvas
+{
+public:
+ PaintBltCanvas();
+ virtual ~PaintBltCanvas();
+ int beginPaint(BaseWnd *basewnd);
+ int beginPaintNC(BaseWnd *basewnd);
+
+ void *getBits();
+ void getRcPaint(RECT *r);
+
+private: // NONPORTABLE
+ HWND hWnd;
+ PAINTSTRUCT ps;
+ HDC wnddc;
+ HBITMAP hbmp, prevbmp;
+ bool nonclient;
+#ifdef LINUX
+ BltCanvas *blitter;
+#endif
+};
+
+class TATAKIAPI MemCanvas : public Canvas
+{
+public:
+ MemCanvas();
+ virtual ~MemCanvas();
+
+ int createCompatible(Canvas *canvas);
+private:
+};
+
+class TATAKIAPI DCCanvas : public Canvas
+{
+public:
+ DCCanvas(HDC clone = NULL, BaseWnd *srcWnd = NULL);
+ virtual ~DCCanvas();
+
+ int cloneDC(HDC clone, BaseWnd *srcWnd = NULL);
+};
+
+class TATAKIAPI SysCanvas : public Canvas
+{
+public:
+ SysCanvas();
+ virtual ~SysCanvas();
+};
+
+/* benski>
+ a quick Canvas class to be created on-the-fly when you need to retrieve information about fonts
+ e.g. getTextExtent
+ don't try to draw with it or bad things will happen.
+
+*/
+class TATAKIAPI TextInfoCanvas : public Canvas
+{
+public:
+ TextInfoCanvas(BaseWnd *basewnd);
+ virtual ~TextInfoCanvas();
+private:
+ HWND hWnd;
+};
+
+class TATAKIAPI DCBltCanvas : public Canvas
+{
+public:
+ DCBltCanvas();
+ virtual ~DCBltCanvas();
+
+ int cloneDC(HDC clone, RECT *r, BaseWnd *srcWnd = NULL);
+ int setOrigDC(HDC neworigdc); // set to null to prevent commitdc on delete, non null to change destination dc
+ int commitDC(void); // allows commit to DC without deleting
+#if 0
+ int cloneCanvas(ifc_canvas *clone, RECT *r);
+#endif
+
+protected:
+ HDC origdc;
+ RECT rect;
+ HBITMAP hbmp, prevbmp;
+};
+
+class TATAKIAPI DCExBltCanvas : public DCBltCanvas
+{
+public:
+ DCExBltCanvas(HWND hWnd, HRGN hrgnClip, DWORD flags);
+
+ ~DCExBltCanvas();
+private:
+ HWND hwnd;
+};
+
+
+// note: getBaseWnd() returns NULL for this class
+class TATAKIAPI BaseCloneCanvas : public Canvas
+{
+public:
+ BaseCloneCanvas(ifc_canvas *cloner = NULL);
+ virtual ~BaseCloneCanvas();
+
+ int clone(ifc_canvas *cloner);
+};
+
+
+
+#ifdef WIN32
+class TATAKIAPI DDSurfaceCanvas : public Canvas
+{
+
+public:
+
+ DDSurfaceCanvas(LPDIRECTDRAWSURFACE surface, int w, int h);
+ virtual ~DDSurfaceCanvas();
+
+ int isready();
+ void enter();
+ void exit();
+
+private:
+ LPDIRECTDRAWSURFACE surf;
+ int _w, _h;
+};
+#endif
+
+class TATAKIAPI BitsCanvas : public Canvas
+{
+public:
+ BitsCanvas(void *_bits, int _w, int _h)
+ {
+ bits=_bits;
+ width=_w;
+ height=_h;
+ pitch=_w;
+ }
+};
+
+enum
+{
+ ALIGN_LEFT,
+ ALIGN_CENTER,
+ ALIGN_RIGHT
+};
+
+#endif
diff --git a/Src/tataki/canvas/win/win32_canvas.cpp b/Src/tataki/canvas/win/win32_canvas.cpp
new file mode 100644
index 00000000..c3d2ad8b
--- /dev/null
+++ b/Src/tataki/canvas/win/win32_canvas.cpp
@@ -0,0 +1,1489 @@
+#ifndef _WIN32
+#error this file is for windows only. Don't include it in your project/makefile for other platforms
+#else
+#include <tataki/export.h>
+#include <tataki/api__tataki.h>
+#include <tataki/blending/blending.h>
+#include "canvas.h"
+#include <tataki/bitmap/bitmap.h>
+#include <tataki/region/region.h>
+#include <api/wnd/basewnd.h>
+#include <api/wnd/fontdef.h>
+#include <api/wnd/paintsets.h>
+
+#include <bfc/assert.h>
+
+#include "bltcanvas.h"
+#include <nsutil/alpha.h>
+#include <nsutil/image.h>
+
+#define CBCLASS Canvas
+START_DISPATCH;
+CB(GETHDC, getHDC);
+CB(GETROOTWND, getRootWnd);
+CB(GETBITS, getBits);
+VCB(GETOFFSETS, getOffsets);
+CB(ISFIXEDCOORDS, isFixedCoords);
+CB(GETDIM, getDim);
+CB(GETTEXTFONT, getTextFont);
+CB(GETTEXTSIZE, getTextSize);
+CB(GETTEXTBOLD, getTextBold);
+CB(GETTEXTOPAQUE, getTextOpaque);
+CB(GETTEXTUNDERLINE, getTextUnderline);
+CB(GETTEXTITALIC, getTextItalic);
+CB(GETTEXTALIGN, getTextAlign);
+CB(GETTEXTCOLOR, getTextColor);
+CB(GETTEXTBKCOLOR, getTextBkColor);
+CB(GETTEXTAA, getTextAntialias);
+CB(GETCLIPBOX, getClipBox);
+END_DISPATCH;
+#undef CBCLASS
+
+//NONPORTABLE
+
+extern const wchar_t wasabi_default_fontnameW[];
+
+Canvas::Canvas()
+ : hdc(NULL),
+ bits(NULL),
+ srcwnd(NULL),
+ fcoord(FALSE),
+ xoffset(0), yoffset(0),
+ width(0),
+ height(0),
+ pitch(0),
+ defpen(NULL),
+ curpen(NULL),
+ userFontInfo(0)
+{
+
+ //tfont = new String; // using dynamic tfont here coz we need to manage em with stack, so stacking fonts won't take sizeof(String) and their destruction will not fuxor everything
+ //tfont->setValue(wasabi_default_fontname);
+}
+
+Canvas::~Canvas()
+{
+ if (getHDC() && defpen != NULL)
+ {
+ SelectObject(getHDC(), defpen);
+ DeleteObject(curpen);
+ }
+
+ if (!penstack.isempty())
+ DebugStringW(L"Pen stack not empty in Canvas::~Canvas !");
+}
+
+void Canvas::setBaseWnd(BaseWnd *b)
+{
+ srcwnd = b;
+}
+
+HDC Canvas::getHDC()
+{
+ return hdc;
+}
+
+ifc_window *Canvas::getRootWnd()
+{
+ return srcwnd;
+}
+
+void *Canvas::getBits()
+{
+ return bits;
+}
+
+bool Canvas::getDim(int *w, int *h, int *p)
+{
+ if (w) *w = width;
+ if (h) *h = height;
+ if (p) *p = pitch;
+ return FALSE;
+}
+
+void Canvas::getOffsets(int *x, int *y)
+{
+ if (x != NULL) *x = getXOffset();
+ if (y != NULL) *y = getYOffset();
+}
+
+bool Canvas::isFixedCoords()
+{
+ return fcoord;
+}
+
+BaseWnd *Canvas::getBaseWnd()
+{
+ return srcwnd;
+}
+
+void Canvas::fillRgn(RegionI *r, COLORREF color)
+{
+ ASSERT(r != NULL);
+ HBRUSH brush = CreateSolidBrush(color);
+ FillRgn(hdc, r->getOSHandle(), brush);
+ DeleteObject(brush);
+}
+
+void Canvas::fillRect(const RECT *r, COLORREF color)
+{
+ ASSERT(r != NULL);
+#if 0
+ HBRUSH brush;
+ if (color == RGB(0, 0, 0))
+ {
+ FillRect(hdc, r, (HBRUSH)GetStockObject(BLACK_BRUSH));
+ return ;
+ }
+ RECT rr = *r;
+ offsetRect(&rr);
+
+ brush = CreateSolidBrush(color);
+ FillRect(hdc, &rr, brush);
+ DeleteObject(brush);
+#else
+// see: http://ooeygui.typepad.com/ooey_gui/2005/06/tip_fast_solid_.html
+COLORREF clrOld = SetBkColor(hdc, color);
+RECT rr = *r;
+offsetRect(&rr);
+ExtTextOutW(hdc, 0, 0, ETO_OPAQUE, &rr, NULL, 0, NULL);
+SetBkColor(hdc, clrOld);
+#endif
+}
+
+void Canvas::fillRectAlpha(const RECT *r, COLORREF color, int alpha)
+{
+ RECT blitr;
+ RECT clipr;
+ getClipBox(&clipr);
+ IntersectRect(&blitr, &clipr, r);
+ uint8_t *bits8 = (uint8_t *)(bits) + blitr.left*4 + blitr.top * pitch;
+ nsutil_image_FillRectAlpha_RGB32((RGB32 *)(bits8), pitch, blitr.right-blitr.left, blitr.bottom-blitr.top, color, alpha);
+}
+
+void Canvas::drawRect(const RECT *r, int solid, COLORREF color, int alpha)
+{
+#if 0
+ unsigned int blah = (unsigned int)alpha;
+ color = RGBTOBGR(color);
+ color = (color & 0xFFFFFF) | (blah << 24);
+ BltCanvas::premultiply(&color, 1);
+ int ox, oy;
+ getOffsets(&ox, &oy);
+ int w, h, pitch;
+ getDim(&w, &h, &pitch);
+ RECT _r = *r;
+ _r.right = MIN<int>(r->right, w);
+ _r.bottom = MIN<int>(r->bottom, h);
+ int _l = r->bottom - r->top;
+ int m = _r.bottom - _r.top;
+ int l = _l;
+ pitch /= 4;
+ int *p = (int *)bits + ox + r->left + (oy + r->top) * pitch;
+ int n = r->right - r->left;
+ int maxn = _r.right - _r.left;
+ while (l-- && m--)
+ {
+ int _n = maxn;
+ if (l == _l - 1 || !l)
+ {
+ if (solid)
+ {
+ while (_n--)
+ {
+ *p = Blenders::BLEND_ADJ2(*p, color);
+ p++;
+ }
+ }
+ else
+ {
+ while (_n--)
+ {
+ if (_n % 2) *p = Blenders::BLEND_ADJ2(*p, color);
+ p++;
+ }
+ }
+ p += n - maxn;
+ }
+ else
+ {
+ if (solid || l % 2)
+ *p = Blenders::BLEND_ADJ2(*p, color);
+ p += n - 1;
+ if (n == maxn && (solid || l % 2))
+ *p = Blenders::BLEND_ADJ2(*p, color);
+ p++;
+ }
+ p += pitch - n;
+ }
+#else
+HBRUSH oldbrush = (HBRUSH)SelectObject(hdc, GetStockObject(NULL_BRUSH));
+HPEN oldpen, pen;
+pen = CreatePen(solid ? PS_SOLID : PS_DOT, 0, color);
+oldpen = (HPEN)SelectObject(hdc, pen);
+ASSERT(r != NULL);
+RECT rr = *r;
+offsetRect(&rr);
+Rectangle(hdc, rr.left, rr.top, rr.right, rr.bottom);
+SelectObject(hdc, oldpen);
+SelectObject(hdc, oldbrush);
+DeleteObject(pen);
+#endif
+}
+
+int Canvas::getTextAlign()
+{
+ return getFontInfo()->alignFlags;
+}
+
+int Canvas::getTextOpaque()
+{
+ return getFontInfo()->opaque;
+}
+
+
+int Canvas::getTextUnderline()
+{
+ return getFontInfo()->underline;
+}
+
+int Canvas::getTextItalic()
+{
+ return getFontInfo()->italic;
+}
+
+int Canvas::getTextBold()
+{
+ return getFontInfo()->bold;
+}
+
+int Canvas::getTextAntialias()
+{
+ return getFontInfo()->antialias;
+}
+
+void Canvas::pushPen(COLORREF color)
+{
+ pushPen(PENSTYLE_SOLID, 1, color);
+}
+
+void Canvas::pushPen(int style, int width, COLORREF color)
+{
+ ASSERT(getHDC() != NULL);
+ penstyle = style;
+ penwidth = width;
+ pencolor = color;
+ penstruct s;
+ curpen = CreatePen(style, width, color);
+ HPEN oldpen = (HPEN)SelectObject(getHDC(), curpen);
+ s.style = style;
+ s.width = width;
+ s.color = color;
+ s.hpen = oldpen;
+ penstack.push(s);
+}
+
+void Canvas::popPen()
+{
+ ASSERT(getHDC() != NULL);
+ if (penstack.isempty()) return ;
+ penstruct s;
+ penstack.pop(&s);
+ SelectObject(getHDC(), s.hpen);
+ DeleteObject(curpen);
+}
+
+int Canvas::getPenStyle()
+{
+ return penstyle;
+}
+
+COLORREF Canvas::getPenColor()
+{
+ return pencolor;
+}
+
+int Canvas::getPenWidth()
+{
+ return penwidth;
+}
+
+COLORREF Canvas::getTextColor()
+{
+ return getFontInfo()->color;
+}
+
+COLORREF Canvas::getTextBkColor()
+{
+ return getFontInfo()->bgColor;
+}
+
+int Canvas::getTextSize()
+{
+ return getFontInfo()->pointSize;
+}
+
+const wchar_t *Canvas::getTextFont()
+{
+ return getFontInfo()->face;
+}
+
+void Canvas::moveTo(int x, int y)
+{
+ MoveToEx(hdc, x, y, NULL);
+}
+
+void Canvas::lineTo(int x, int y)
+{
+ LineTo(hdc, x, y);
+}
+
+void Canvas::lineDraw(int fromX, int fromY, int toX, int toY)
+{
+ MoveToEx(hdc, fromX, fromY, NULL);
+ LineTo(hdc, toX, toY);
+}
+
+void Canvas::drawSysObject(const RECT *r, int sysobj, int alpha)
+{
+#ifndef _NOSTUDIO
+ RECT i_dont_trust_ms_with_my_rect = *r;
+ switch (sysobj)
+ {
+ case DrawSysObj::BUTTON:
+ WASABI_API_WND->paintset_render(Paintset::BUTTONUP, this, r, alpha);
+ break;
+ case DrawSysObj::BUTTON_PUSHED:
+ WASABI_API_WND->paintset_render(Paintset::BUTTONDOWN, this, r, alpha);
+ break;
+ case DrawSysObj::BUTTON_DISABLED:
+ WASABI_API_WND->paintset_render(Paintset::BUTTONDISABLED, this, r, alpha);
+ break;
+#ifdef WIN32
+ case DrawSysObj::OSBUTTON:
+ {
+ DrawFrameControl(getHDC(), &i_dont_trust_ms_with_my_rect, DFC_BUTTON, DFCS_BUTTONPUSH);
+ }
+ break;
+ case DrawSysObj::OSBUTTON_PUSHED:
+ {
+ DrawFrameControl(getHDC(), &i_dont_trust_ms_with_my_rect, DFC_BUTTON, DFCS_BUTTONPUSH | DFCS_PUSHED);
+ }
+ break;
+ case DrawSysObj::OSBUTTON_DISABLED:
+ {
+ DrawFrameControl(getHDC(), &i_dont_trust_ms_with_my_rect, DFC_BUTTON, DFCS_BUTTONPUSH | DFCS_INACTIVE);
+ }
+ break;
+
+ case DrawSysObj::OSBUTTON_CLOSE:
+ {
+ DrawFrameControl(getHDC(), &i_dont_trust_ms_with_my_rect, DFC_CAPTION, DFCS_CAPTIONCLOSE);
+ }
+ break;
+ case DrawSysObj::OSBUTTON_CLOSE_PUSHED:
+ {
+ DrawFrameControl(getHDC(), &i_dont_trust_ms_with_my_rect, DFC_CAPTION, DFCS_CAPTIONCLOSE | DFCS_PUSHED);
+ }
+ break;
+ case DrawSysObj::OSBUTTON_CLOSE_DISABLED:
+ {
+ DrawFrameControl(getHDC(), &i_dont_trust_ms_with_my_rect, DFC_CAPTION, DFCS_CAPTIONCLOSE | DFCS_INACTIVE);
+ }
+ break;
+
+ case DrawSysObj::OSBUTTON_MINIMIZE:
+ {
+ DrawFrameControl(getHDC(), &i_dont_trust_ms_with_my_rect, DFC_CAPTION, DFCS_CAPTIONMIN);
+ }
+ break;
+ case DrawSysObj::OSBUTTON_MINIMIZE_PUSHED:
+ {
+ DrawFrameControl(getHDC(), &i_dont_trust_ms_with_my_rect, DFC_CAPTION, DFCS_CAPTIONMIN | DFCS_PUSHED);
+ }
+ break;
+ case DrawSysObj::OSBUTTON_MINIMIZE_DISABLED:
+ {
+ DrawFrameControl(getHDC(), &i_dont_trust_ms_with_my_rect, DFC_CAPTION, DFCS_CAPTIONMIN | DFCS_INACTIVE);
+ }
+ break;
+
+ case DrawSysObj::OSBUTTON_MAXIMIZE:
+ {
+ DrawFrameControl(getHDC(), &i_dont_trust_ms_with_my_rect, DFC_CAPTION, DFCS_CAPTIONMAX);
+ }
+ break;
+ case DrawSysObj::OSBUTTON_MAXIMIZE_PUSHED:
+ {
+ DrawFrameControl(getHDC(), &i_dont_trust_ms_with_my_rect, DFC_CAPTION, DFCS_CAPTIONMAX | DFCS_PUSHED);
+ }
+ break;
+ case DrawSysObj::OSBUTTON_MAXIMIZE_DISABLED:
+ {
+ DrawFrameControl(getHDC(), &i_dont_trust_ms_with_my_rect, DFC_CAPTION, DFCS_CAPTIONMAX | DFCS_INACTIVE);
+ }
+ break;
+#else
+#error port me!
+#endif
+ break;
+ }
+#endif
+}
+
+void Canvas::textOut(int x, int y, const wchar_t *txt, const Wasabi::FontInfo *fontInfo)
+{
+ userFontInfo = fontInfo;
+ WASABI_API_FONT->font_textOut(this, WA_FONT_TEXTOUT_NORMAL, x, y, 0, 0, txt);
+ userFontInfo = 0;
+}
+
+void Canvas::textOut(int x, int y, int w, int h, const wchar_t *txt, const Wasabi::FontInfo *fontInfo)
+{
+ userFontInfo = fontInfo;
+ WASABI_API_FONT->font_textOut(this, WA_FONT_TEXTOUT_RECT, x, y, w, h, txt);
+ userFontInfo = 0;
+}
+
+void Canvas::textOutEllipsed(int x, int y, int w, int h, const wchar_t *txt, const Wasabi::FontInfo *fontInfo)
+{
+ userFontInfo = fontInfo;
+ WASABI_API_FONT->font_textOut(this, WA_FONT_TEXTOUT_ELLIPSED, x, y, w, h, txt);
+ userFontInfo = 0;
+}
+
+void Canvas::textOutWrapped(int x, int y, int w, int h, const wchar_t *txt, const Wasabi::FontInfo *fontInfo)
+{
+ userFontInfo = fontInfo;
+ WASABI_API_FONT->font_textOut(this, WA_FONT_TEXTOUT_WRAPPED, x, y, w, h, (txt));
+ userFontInfo = 0;
+}
+
+void Canvas::textOutWrappedPathed(int x, int y, int w, const wchar_t *txt, const Wasabi::FontInfo *fontInfo)
+{
+ userFontInfo = fontInfo;
+ WASABI_API_FONT->font_textOut(this, WA_FONT_TEXTOUT_WRAPPEDPATHED, x, y, w, 0, (txt));
+ userFontInfo = 0;
+}
+
+void Canvas::textOutCentered(RECT *r, const wchar_t *txt, const Wasabi::FontInfo *fontInfo)
+{
+ userFontInfo = fontInfo;
+ WASABI_API_FONT->font_textOut(this, WA_FONT_TEXTOUT_CENTERED, r->left, r->top, r->right, r->bottom, (txt));
+ userFontInfo = 0;
+}
+
+int Canvas::getTextWidth(const wchar_t *text, const Wasabi::FontInfo *fontInfo)
+{
+ userFontInfo = fontInfo;
+ int ret = WASABI_API_FONT->font_getInfo(this, fontInfo->face, WA_FONT_GETINFO_WIDTH, (text), NULL, NULL);
+ userFontInfo = 0;
+ return ret;
+}
+
+int Canvas::getTextHeight(const wchar_t *text, const Wasabi::FontInfo *fontInfo)
+{
+ userFontInfo = fontInfo;
+ int ret = WASABI_API_FONT->font_getInfo(this, fontInfo->face, WA_FONT_GETINFO_HEIGHT, (text), NULL, NULL);
+ userFontInfo = 0;
+ return ret;
+}
+
+void Canvas::getTextExtent(const wchar_t *txt, int *w, int *h, const Wasabi::FontInfo *fontInfo)
+{
+ userFontInfo = fontInfo;
+ WASABI_API_FONT->font_getInfo(this, fontInfo->face, WA_FONT_GETINFO_WIDTHHEIGHT, (txt), w, h);
+ userFontInfo = 0;
+}
+
+void Canvas::offsetRect(RECT *r)
+{
+ ASSERT(r != NULL);
+ r->left += xoffset;
+ r->right += xoffset;
+ r->top += yoffset;
+ r->bottom += yoffset;
+}
+
+void Canvas::selectClipRgn(api_region *r)
+{
+ SelectClipRgn(hdc, r ? r->getOSHandle() : NULL);
+}
+
+int Canvas::getClipBox(RECT *r)
+{
+ RECT dummy;
+ if (!r) r = &dummy;
+ return GetClipBox(hdc, r);
+}
+
+int Canvas::getClipRgn(api_region *r)
+{
+ ASSERT(r != NULL);
+ return GetClipRgn(hdc, r->getOSHandle());
+}
+
+//FG> added blit canvas to canvas
+void Canvas::blit(int srcx, int srcy, Canvas *dest, int dstx, int dsty, int dstw, int dsth)
+{
+ char *srcbits = (char *)getBits();
+ char *destbits = (char *)dest->getBits();
+ RECT clipr;
+ if (srcbits && destbits && GetClipBox(dest->getHDC(), &clipr) == SIMPLEREGION)
+ {
+ int srcimg_w, srcimg_h, srcimg_p;
+ getDim(&srcimg_w, &srcimg_h, &srcimg_p);
+ int dstimg_w, dstimg_h, dstimg_p;
+ dest->getDim(&dstimg_w, &dstimg_h, &dstimg_p);
+
+ if (srcx < 0)
+ {
+ dstx -= srcx; dstw += srcx; srcx = 0;
+ }
+ if (srcy < 0)
+ {
+ dsty -= srcy; dsth += srcy; srcy = 0;
+ }
+ if (srcx + dstw >= srcimg_w) dstw = srcimg_w - srcx;
+ if (srcy + dsth >= srcimg_h) dsth = srcimg_h - srcy;
+
+ if (dstx < clipr.left)
+ {
+ srcx += clipr.left - dstx; dstw -= clipr.left - dstx; dstx = clipr.left;
+ }
+ if (dsty < clipr.top)
+ {
+ srcy += clipr.top - dsty; dsth -= clipr.top - dsty; dsty = clipr.top;
+ }
+
+ if (dstx + dstw >= clipr.right) dstw = clipr.right - dstx;
+ if (dsty + dsth >= clipr.bottom) dsth = clipr.bottom - dsty;
+
+ if (!dstw || !dsth) return ;
+
+ int y;
+ int yl = dsty + dsth;
+ for (y = dsty; y < yl; y++)
+ {
+ MEMCPY32(destbits + y*dstimg_p + dstx*4, srcbits + srcy*srcimg_p + srcx*4, dstw);
+ srcy++;
+ }
+ }
+ else
+ {
+ //GdiFlush();
+ BitBlt(dest->getHDC(), dstx, dsty, dstw, dsth, getHDC(), srcx, srcy, SRCCOPY);
+ }
+}
+
+#pragma comment(lib, "msimg32.lib")
+
+void Canvas::stretch(ifc_canvas *canvas, int x, int y, int w, int h)
+{
+ if (bits)
+ {
+ SkinBitmap temp((ARGB32 *)bits, width, height);
+ temp.stretch(canvas, x,y,w,h);
+ }
+ else
+ {
+ BLENDFUNCTION blendFn;
+ blendFn.BlendOp = AC_SRC_OVER;
+ blendFn.BlendFlags = 0;
+ blendFn.SourceConstantAlpha = 255;
+ blendFn.AlphaFormat = AC_SRC_ALPHA;
+
+ AlphaBlend(canvas->getHDC(),
+ x, y,
+ w, h,
+ getHDC(),
+ 0, 0,
+ width, height,
+ blendFn);
+ }
+}
+
+void Canvas::blitAlpha(ifc_canvas *canvas, int x, int y, int alpha)
+{
+ if (bits)
+ {
+ SkinBitmap temp((ARGB32 *)bits, width, height);
+ temp.blitAlpha(canvas, x,y,alpha);
+ }
+ else
+ {
+ BLENDFUNCTION blendFn;
+ blendFn.BlendOp = AC_SRC_OVER;
+ blendFn.BlendFlags = 0;
+ blendFn.SourceConstantAlpha = alpha;
+ blendFn.AlphaFormat = AC_SRC_ALPHA;
+
+ AlphaBlend(canvas->getHDC(),
+ x, y,
+ width, height,
+ getHDC(),
+ 0, 0,
+ width, height,
+ blendFn);
+ }
+}
+
+void Canvas::stretchToRectAlpha(ifc_canvas *canvas, RECT *src, RECT *dst, int alpha)
+{
+ if (bits)
+ {
+ SkinBitmap temp((ARGB32 *)bits, width, height);
+ temp.stretchToRectAlpha(canvas, src, dst, alpha);
+ }
+ else
+ {
+ BLENDFUNCTION blendFn;
+ blendFn.BlendOp = AC_SRC_OVER;
+ blendFn.BlendFlags = 0;
+ blendFn.SourceConstantAlpha = alpha;
+ blendFn.AlphaFormat = AC_SRC_ALPHA;
+
+ AlphaBlend(canvas->getHDC(),
+ dst->left, dst->top,
+ dst->right - dst->left, dst->bottom - dst->top,
+ getHDC(),
+ src->left, src->top,
+ src->right - src->left, src->bottom - src->top,
+ blendFn);
+ }
+}
+
+void Canvas::blitToRect(ifc_canvas *canvas, RECT *src, RECT *dst, int alpha)
+{
+ if (bits)
+ {
+ SkinBitmap temp((ARGB32 *)bits, width, height);
+ temp.blitToRect(canvas, src, dst, alpha);
+ }
+ else
+ {
+ BLENDFUNCTION blendFn;
+ blendFn.BlendOp = AC_SRC_OVER;
+ blendFn.BlendFlags = 0;
+ blendFn.SourceConstantAlpha = alpha;
+ blendFn.AlphaFormat = AC_SRC_ALPHA;
+
+ AlphaBlend(canvas->getHDC(),
+ dst->left, dst->top,
+ dst->right - dst->left, dst->bottom - dst->top,
+ getHDC(),
+ src->left, src->top,
+ src->right - src->left, src->bottom - src->top,
+ blendFn);
+ }
+}
+
+// src* are in fixed point
+static void scale_internal(int srcx, int srcy, int srcw, int srch, void *srcdib, int srcdib_w, int srcdib_h, int srcdib_p, int dstx, int dsty, int dstw, int dsth, void *dstdib, int nofilter)
+{
+ // scaling up
+ if ((dstw << 16) >= srcw && (dsth << 16) >= srch)
+ {
+ int y;
+ int SY, dX, dY;
+ int Xend = (srcdib_w - 2) << 16;
+ SY = srcy;
+ dX = srcw / dstw;
+ dY = srch / dsth;
+
+ int xstart = 0;
+ int xp = srcx >> 16;
+ if (xp < 0)
+ {
+ xstart = -xp;
+ srcx += xstart * dX;
+ }
+
+ int xend = dstw;
+ xp = (srcx + (dX * (xend - xstart))) >> 16;
+ if (xp > srcdib_w)
+ {
+ xend = xstart + srcdib_w - (srcx >> 16);
+ }
+
+ for (y = 0; y < dsth; y ++)
+ {
+ int yp = (SY >> 16);
+ if (yp >= 0)
+ {
+ int x;
+ int SX = srcx;
+ unsigned int *out = (unsigned int*)dstdib + xstart + y * dstw;
+ int end = yp >= srcdib_h - 1;
+ if (nofilter || end)
+ {
+ if (end) yp = srcdib_h - 1;
+ unsigned int *in = (unsigned int*)((char *)srcdib + yp * srcdib_p);
+ for (x = xstart; x < xend; x ++) // quick hack to draw last line
+ {
+ *out++ = in[SX >> 16];
+ SX += dX;
+ }
+ if (end) break;
+ }
+ else
+ {
+ unsigned int *in = (unsigned int*)((char *)srcdib + yp * srcdib_p);
+
+#ifndef NO_MMX
+ if (Blenders::MMX_AVAILABLE())
+ {
+ for (x = xstart; x < xend; x ++)
+ {
+ if (SX > Xend) *out++ = Blenders::BLEND4_MMX(in + (Xend >> 16), srcdib_w, 0xffff, SY);
+ else *out++ = Blenders::BLEND4_MMX(in + (SX >> 16), srcdib_w, SX, SY);
+ SX += dX;
+ }
+ }
+ else
+#endif
+
+ {
+ for (x = xstart; x < xend; x ++)
+ {
+ if (SX > Xend) *out++ = Blenders::BLEND4(in + (Xend >> 16), srcdib_w, 0xffff, SY);
+ else *out++ = Blenders::BLEND4(in + (SX >> 16), srcdib_w, SX, SY);
+ SX += dX;
+ }
+ }
+ }
+ }
+ SY += dY;
+ }
+ // end of scaling up
+ }
+ else // we are scaling down -- THIS IS SLOW AND MAY BREAK THINGS. :)
+ {
+ int y;
+ int SY, dX, dY;
+ SY = srcy;
+ dX = srcw / dstw;
+ dY = srch / dsth;
+
+ int xstart = 0;
+ int xp = srcx >> 16;
+ if (xp < 0)
+ {
+ xstart = -xp;
+ srcx += xstart * dX;
+ }
+
+ int xend = dstw;
+ xp = (srcx + (dX * (xend - xstart))) >> 16;
+ if (xp > srcdib_w)
+ {
+ xend = xstart + srcdib_w - (srcx >> 16);
+ }
+
+ for (y = 0; y < dsth; y ++)
+ {
+ // start and end of y source block
+ int vStart = SY;
+ int vEnd = SY + dY;
+
+ int x;
+ int SX = srcx;
+ unsigned char *out = (unsigned char *)((unsigned int*)dstdib + xstart + y * dstw);
+ for (x = xstart; x < xend; x ++)
+ {
+ if (((char *)out+4) >= ((char *)dstdib + 4*dstw*dsth))
+ break;
+ int uStart = SX;
+ int uEnd = SX + dX;
+ // calculate sum of rectangle.
+
+ int cnt = 0;
+ __int64 accum[4] = {0, };
+ int v, u;
+ for (v = vStart; v < vEnd; v += 65536)
+ {
+ unsigned int vscale = 65535;
+
+ if (v == vStart)
+ {
+ vscale = 65535 - (v & 0xffff);
+ }
+ else if ((vEnd - v) < 65536)
+ {
+ vscale = (vEnd - v) & 0xffff;
+ }
+
+ int vp = v >> 16;
+ unsigned char *in = (unsigned char*)((char *)srcdib + vp * srcdib_p + 4 * (uStart >> 16));
+ for (u = uStart; u < uEnd; u += 65536)
+ {
+ if (((char *)in+4) >= ((char *)srcdib + srcdib_p*srcdib_h))
+ break;
+ unsigned int uscale = vscale;
+ if (u == uStart)
+ {
+ uscale *= 65535 - (u & 0xffff);
+ uscale >>= 16;
+ }
+ else if ((uEnd - u) < 65536)
+ {
+ uscale *= (uEnd - u) & 0xffff;
+ uscale >>= 16;
+ }
+ cnt += uscale;
+ if (uscale == 65535)
+ {
+ accum[0] += (in[0] << 16) - in[0];
+ accum[1] += (in[1] << 16) - in[1];
+ accum[2] += (in[2] << 16) - in[2];
+ accum[3] += (in[3] << 16) - in[3];
+ }
+ else
+ {
+ accum[0] += in[0] * uscale;
+ accum[1] += in[1] * uscale;
+ accum[2] += in[2] * uscale;
+ accum[3] += in[3] * uscale;
+ }
+ in += 4;
+ }
+ }
+ if (!cnt) cnt++;
+
+ out[0] = (uint8_t)(accum[0] / cnt);
+ out[1] = (uint8_t)(accum[1] / cnt);
+ out[2] = (uint8_t)(accum[2] / cnt);
+ out[3] = (uint8_t)(accum[3] / cnt);
+ out += 4;
+
+ SX += dX;
+ }
+ SY += dY;
+ }
+ // end of scaling down
+ }
+
+#ifndef NO_MMX
+ Blenders::BLEND_MMX_END();
+#endif
+}
+
+
+// src* are in fixed point
+void Canvas::stretchblit(int srcx, int srcy, int srcw, int srch, Canvas *dest, int dstx, int dsty, int dstw, int dsth)
+{
+ //GdiFlush();
+ int done = 0;
+ void *srcdib = getBits();
+
+ if (!dstw || !dsth || !srcw || !srch) return ;
+ if (srcdib)
+ {
+ int srcdib_w, srcdib_h, srcdib_p;
+ getDim(&srcdib_w, &srcdib_h, &srcdib_p);
+
+ void *dstdib;
+ BITMAPINFO dstbmi = {0};
+ HDC hMemDC;
+ HBITMAP hsrcdib;
+ dstbmi.bmiHeader.biSize = sizeof(dstbmi.bmiHeader);
+ dstbmi.bmiHeader.biWidth = dstw;
+ dstbmi.bmiHeader.biHeight = -ABS(dsth);
+ dstbmi.bmiHeader.biPlanes = 1;
+ dstbmi.bmiHeader.biBitCount = 32;
+ dstbmi.bmiHeader.biCompression = BI_RGB;
+ hMemDC = CreateCompatibleDC(NULL);
+ hsrcdib = CreateDIBSection(hMemDC, &dstbmi, DIB_RGB_COLORS, &dstdib, NULL, 0);
+ if (hsrcdib)
+ {
+ HBITMAP hprev = (HBITMAP)SelectObject(hMemDC, hsrcdib);
+
+ scale_internal(srcx,srcy,srcw,srch,srcdib,srcdib_w,srcdib_h,srcdib_p,dstx,dsty,dstw,dsth,dstdib,0);
+
+ BitBlt(dest->getHDC(), dstx, dsty, dstw, dsth, hMemDC, 0, 0, SRCCOPY);
+ done++;
+
+ SelectObject(hMemDC, hprev);
+ DeleteObject(hsrcdib);
+ }
+ DeleteDC(hMemDC);
+ }
+
+ if (!done)
+ {
+ SetStretchBltMode(dest->getHDC(), COLORONCOLOR);
+ StretchBlt(dest->getHDC(), dstx, dsty, dstw, dsth, getHDC(), srcx >> 16, srcy >> 16, srcw >> 16, srch >> 16, SRCCOPY);
+ }
+}
+
+#define DEBUG_SCREEN_SHIFT 0
+void Canvas::debug()
+{
+ SysCanvas c;
+ int w, h;
+ getDim(&w, &h, NULL);
+ blit(0, 0, &c, DEBUG_SCREEN_SHIFT, 0, w, h);
+}
+
+#define BF2 (~((3<<24)|(3<<16)|(3<<8)|3))
+
+void Canvas::antiAliasTo(Canvas *dest, int w, int h, int aafactor)
+{
+ ASSERT(aafactor != 0);
+ if (aafactor == 1)
+ {
+ blit(0, 0, dest, 0, 0, w, h);
+ return ;
+ }
+ ASSERT(getBits() != NULL);
+ ASSERT(dest->getBits() != NULL);
+ if (getBits() == NULL || dest->getBits() == NULL) return ;
+ ASSERTPR(aafactor <= 2, "too lazy to generalize the code right now :)");
+ //GdiFlush();
+ // we should really store the bpp too
+ int aaw = w * aafactor;
+ unsigned long *s1 = (unsigned long *)getBits(), *s2 = s1 + 1;
+ unsigned long *s3 = s1 + aaw, *s4 = s3 + 1;
+ unsigned long *d = (unsigned long *)dest->getBits();
+#if 1
+ for (int y = 0; y < h; y++)
+ {
+ for (int x = 0; x < w; x++)
+ {
+ unsigned long tmp = ((*s1 & BF2) >> 2) + ((*s2 & BF2) >> 2) + ((*s3 & BF2) >> 2) + ((*s4 & BF2) >> 2);
+ *d++ = tmp;
+
+ s1 += 2; s2 += 2;
+ s3 += 2; s4 += 2;
+ }
+ s1 += aaw; s2 += aaw;
+ s3 += aaw; s4 += aaw;
+ }
+#else
+for (int x = 0; x < w * h; x++) d[x] = s1[x];
+#endif
+}
+
+void Canvas::colorToColor(COLORREF from, COLORREF to, RECT *r)
+{
+ int w, h, ox, oy;
+
+ // convert to bitmap order
+ from = RGBTOBGR(from);
+ to = RGBTOBGR(to);
+
+ COLORREF *p;
+ getDim(&w, &h, NULL);
+ p = (COLORREF *)getBits();
+ getOffsets(&ox, &oy);
+ p += ox + r->left + (oy + r->top) * w;
+ int rw = r->right - r->left;
+ for (int j = r->top;j < r->bottom;j++)
+ {
+ for (int i = r->left;i < r->right;i++)
+ {
+ if (*p == from)
+ *p = to;
+ p++;
+ }
+ p += w - rw;
+ }
+}
+
+double Canvas::getSystemFontScale()
+{
+ if (WASABI_API_CONFIG)
+ {
+ int v = WASABI_API_CONFIG->getIntPublic(L"manualsysmetrics", -1);
+ if (v != -1) return (v / 100.0f);
+ }
+
+ int nLogDPIX = GetDeviceCaps(getHDC(), LOGPIXELSX);
+ return ((float)nLogDPIX / 96.0f);
+}
+
+void Canvas::premultiply(ARGB32 *m_pBits, int nwords, int newalpha)
+{
+ if (newalpha == -1)
+ {
+ nsutil_alpha_Premultiply_RGB32(m_pBits, nwords, nwords, 1);
+ /*
+ for (; nwords > 0; nwords--, m_pBits++)
+ {
+ unsigned char *pixel = (unsigned char *)m_pBits;
+ unsigned int alpha = pixel[3];
+ if (alpha == 255) continue;
+ pixel[0] = (pixel[0] * alpha) >> 8; // blue
+ pixel[1] = (pixel[1] * alpha) >> 8; // green
+ pixel[2] = (pixel[2] * alpha) >> 8; // red
+ }
+ */
+ }
+ else
+ {
+ nsutil_alpha_PremultiplyValue_RGB8(m_pBits, nwords, nwords, 1, newalpha);
+ /*
+ for (; nwords > 0; nwords--, m_pBits++)
+ {
+ unsigned char *pixel = (unsigned char *)m_pBits;
+ pixel[0] = (pixel[0] * newalpha) >> 8; // blue
+ pixel[1] = (pixel[1] * newalpha) >> 8; // green
+ pixel[2] = (pixel[2] * newalpha) >> 8; // red
+ pixel[3] = (pixel[3] * newalpha) >> 8; // alpha
+ }
+ */
+ }
+}
+
+TextInfoCanvas::TextInfoCanvas(BaseWnd *basewnd)
+{
+ ASSERT(basewnd != NULL);
+ hWnd = basewnd->gethWnd();
+ hdc = GetDC(hWnd);
+}
+
+TextInfoCanvas::~TextInfoCanvas()
+{
+ if (hdc)
+ ReleaseDC(hWnd, hdc);
+}
+
+WndCanvas::WndCanvas(BaseWnd *basewnd)
+{
+ attachToClient(basewnd);
+}
+
+WndCanvas::WndCanvas()
+{
+ hWnd = NULL;
+}
+
+WndCanvas::~WndCanvas()
+{
+ if (hWnd != NULL && hdc != NULL) ReleaseDC(hWnd, hdc);
+ hdc = NULL;
+}
+
+int WndCanvas::attachToClient(BaseWnd *basewnd)
+{
+ if (basewnd == NULL)
+ return 0;
+
+ hWnd = basewnd->gethWnd();
+ if (hWnd == NULL)
+ return 0;
+
+ hdc = GetDC(hWnd);
+ if (hdc == NULL)
+ return 0;
+
+ srcwnd = basewnd;
+ return 1;
+}
+
+#if 0//CUT
+int WndCanvas::attachToWnd(HWND _hWnd)
+{
+ hWnd = _hWnd;
+ ASSERT(hWnd != NULL);
+ hdc = GetWindowDC(hWnd);
+ ASSERT(hdc != NULL);
+ return 1;
+}
+#endif
+
+PaintCanvas::PaintCanvas()
+{
+ hWnd = NULL;
+}
+
+PaintCanvas::~PaintCanvas()
+{
+
+ if (hdc != NULL) EndPaint(hWnd, &ps);
+ hdc = NULL;
+}
+
+void PaintCanvas::getRcPaint(RECT *r)
+{
+ *r = ps.rcPaint;
+}
+
+int PaintCanvas::beginPaint(BaseWnd *basewnd)
+{
+ hWnd = basewnd->gethWnd(); // NONPORTABLE
+ ASSERT(hWnd != NULL);
+ hdc = BeginPaint(hWnd, &ps);
+ ASSERT(hdc != NULL);
+ srcwnd = basewnd;
+ return 1;
+}
+
+int PaintCanvas::beginPaint(HWND wnd)
+{
+ hWnd = wnd; // NONPORTABLE
+ ASSERT(hWnd != NULL);
+ hdc = BeginPaint(hWnd, &ps);
+ ASSERT(hdc != NULL);
+ srcwnd = NULL;
+ return 1;
+}
+
+PaintBltCanvas::PaintBltCanvas()
+{
+ hWnd = NULL;
+ wnddc = NULL;
+ hbmp = NULL;
+ prevbmp = NULL;
+ bits = NULL;
+ fcoord = TRUE;
+ nonclient = FALSE;
+}
+
+PaintBltCanvas::~PaintBltCanvas()
+{
+ RECT r;
+
+ if (hdc == NULL) return ;
+
+ ASSERT(srcwnd != NULL);
+ if (nonclient) //FG> nonclient painting fix
+ srcwnd->getNonClientRect(&r);
+ else
+ srcwnd->getClientRect(&r);
+
+ // blt here
+ //GdiFlush();
+ BitBlt(wnddc, r.left, r.top, r.right - r.left, r.bottom - r.top, hdc, 0, 0, SRCCOPY);
+
+ //SelectClipRgn(hdc, NULL);
+ // kill the bitmap and its DC
+ SelectObject(hdc, prevbmp);
+ DeleteDC(hdc);
+ hdc = NULL;
+ DeleteObject(hbmp);
+ bits = NULL;
+ width = 0;
+ height = 0;
+ pitch = 0;
+
+ EndPaint(hWnd, &ps); // end of wnddc
+ wnddc = NULL;
+}
+
+//FG> nonclient painting fix
+int PaintBltCanvas::beginPaintNC(BaseWnd *basewnd)
+{
+ nonclient = TRUE;
+ return beginPaint(basewnd);
+}
+
+void PaintBltCanvas::getRcPaint(RECT *r)
+{
+ *r = ps.rcPaint;
+}
+
+int PaintBltCanvas::beginPaint(BaseWnd *basewnd)
+{
+
+ RECT r;
+
+ if (nonclient)
+ basewnd->getNonClientRect(&r); //FG> nonclient painting fix
+ else
+ basewnd->getClientRect(&r);
+
+ if (r.right - r.left <= 0 || r.bottom - r.top <= 0) return 0;
+
+ hWnd = basewnd->gethWnd(); // NONPORTABLE
+ ASSERT(hWnd != NULL);
+
+ BITMAPINFO bmi;
+ ZeroMemory(&bmi, sizeof bmi);
+ bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ bmi.bmiHeader.biWidth = r.right - r.left;
+ bmi.bmiHeader.biHeight = -(r.bottom - r.top);
+ bmi.bmiHeader.biPlanes = 1;
+ bmi.bmiHeader.biBitCount = 32;
+ bmi.bmiHeader.biCompression = BI_RGB;
+ bmi.bmiHeader.biSizeImage = 0;
+ bmi.bmiHeader.biXPelsPerMeter = 0;
+ bmi.bmiHeader.biYPelsPerMeter = 0;
+ bmi.bmiHeader.biClrUsed = 0;
+ bmi.bmiHeader.biClrImportant = 0;
+
+ wnddc = BeginPaint(hWnd, &ps);
+
+ ASSERT(wnddc != NULL);
+
+ //GdiFlush();
+ width = r.right - r.left;
+ height = -ABS(r.bottom - r.top);
+ pitch = width * 4;
+ hbmp = CreateDIBSection(wnddc, &bmi, DIB_RGB_COLORS, &bits, NULL, 0);
+
+ if (hbmp == NULL)
+ {
+ EndPaint(hWnd, &ps); // end of wnddc
+ wnddc = NULL;
+ return 0;
+ }
+
+ // create tha DC
+ hdc = CreateCompatibleDC(wnddc);
+ if (hdc == NULL)
+ {
+ DeleteObject(hbmp);
+ EndPaint(hWnd, &ps); // end of wnddc
+ wnddc = NULL;
+ return 0;
+ }
+ prevbmp = (HBITMAP)SelectObject(hdc, hbmp);
+
+ RegionI clip(&ps.rcPaint);
+
+ selectClipRgn(&clip);
+
+ srcwnd = basewnd;
+
+ return 1;
+}
+
+void *PaintBltCanvas::getBits()
+{
+ return bits;
+}
+
+MemCanvas::MemCanvas()
+{}
+
+MemCanvas::~MemCanvas()
+{
+ DeleteDC(hdc);
+ hdc = NULL;
+}
+
+int MemCanvas::createCompatible(Canvas *canvas)
+{
+ ASSERT(canvas != NULL);
+ ASSERT(canvas->getHDC() != NULL);
+ hdc = CreateCompatibleDC(canvas->getHDC());
+ ASSERT(hdc != NULL);
+ srcwnd = canvas->getBaseWnd();
+ return 1;
+}
+
+
+DCCanvas::DCCanvas(HDC clone, BaseWnd *srcWnd)
+{
+ if (clone != NULL) cloneDC(clone, srcWnd);
+}
+
+DCCanvas::~DCCanvas()
+{
+ hdc = NULL;
+}
+
+int DCCanvas::cloneDC(HDC clone, BaseWnd *srcWnd)
+{
+ ASSERT(clone != NULL);
+ hdc = clone;
+ srcwnd = srcWnd;
+ return 1;
+}
+
+SysCanvas::SysCanvas()
+{
+ hdc = GetDC(NULL);
+}
+
+SysCanvas::~SysCanvas()
+{
+ ReleaseDC(NULL, hdc);
+ hdc = NULL;
+}
+
+DCBltCanvas::DCBltCanvas()
+{
+ origdc = NULL;
+ hbmp = prevbmp = NULL;
+}
+
+DCBltCanvas::~DCBltCanvas()
+{
+
+ commitDC();
+
+ // kill the bitmap and its DC
+ SelectObject(hdc, prevbmp);
+ DeleteDC(hdc);
+ hdc = NULL;
+ DeleteObject(hbmp);
+
+ // don't kill origdc, it's been cloned
+}
+
+int DCBltCanvas::setOrigDC(HDC neworigdc)
+{
+ // FG> allows custom draw on lists to be much faster
+ origdc = neworigdc;
+ return 1;
+}
+
+int DCBltCanvas::commitDC(void)
+{
+ //FG
+
+ if (origdc)
+ {
+
+ RECT c;
+
+ if (GetClipBox(origdc, &c) == NULLREGION)
+ c = rect;
+
+ // shlap it down in its original spot
+ //GdiFlush();
+ BitBlt(origdc, c.left, c.top,
+ c.right - c.left, c.bottom - c.top, hdc, c.left-rect.left, c.top-rect.top, SRCCOPY);
+
+ }
+
+ return 1;
+}
+
+int DCBltCanvas::cloneDC(HDC clone, RECT *r, BaseWnd *srcWnd)
+{
+ origdc = clone;
+
+ srcwnd = srcWnd;
+
+ ASSERT(r != NULL);
+ rect = *r;
+
+#if 1
+ BITMAPINFO bmi;
+ ZeroMemory(&bmi, sizeof bmi);
+ bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ bmi.bmiHeader.biWidth = r->right - r->left;
+ bmi.bmiHeader.biHeight = -ABS(r->bottom - r->top);
+ bmi.bmiHeader.biPlanes = 1;
+ bmi.bmiHeader.biBitCount = 32;
+ bmi.bmiHeader.biCompression = BI_RGB;
+ bmi.bmiHeader.biSizeImage = 0;
+ bmi.bmiHeader.biXPelsPerMeter = 0;
+ bmi.bmiHeader.biYPelsPerMeter = 0;
+ bmi.bmiHeader.biClrUsed = 0;
+ bmi.bmiHeader.biClrImportant = 0;
+ hbmp = CreateDIBSection(origdc, &bmi, DIB_RGB_COLORS, &bits, NULL, 0);
+ width = bmi.bmiHeader.biWidth;
+ height = ABS(bmi.bmiHeader.biHeight);
+ pitch = width * 4;
+#else
+hbmp = CreateCompatibleBitmap(clone, r->right - r->left, r->bottom - r->top);
+#endif
+ ASSERT(hbmp != NULL);
+
+ // create tha DC
+ hdc = CreateCompatibleDC(origdc);
+ prevbmp = (HBITMAP)SelectObject(hdc, hbmp);
+
+ // adjust their rect for them
+ r->right -= r->left;
+ r->left = 0;
+ r->bottom -= r->top;
+ r->top = 0;
+
+ return 1;
+}
+
+DCExBltCanvas::DCExBltCanvas(HWND hWnd, HRGN hrgnClip, DWORD flags) : hwnd(hWnd)
+{
+ origdc = GetDCEx(hWnd, hrgnClip, flags);
+ RECT r;
+ GetWindowRect(hWnd, &r);
+ OffsetRect(&r, -r.left, -r.top);
+ cloneDC(origdc, &r);
+}
+
+DCExBltCanvas::~DCExBltCanvas()
+{
+ commitDC();
+ ReleaseDC(hwnd, origdc);
+ origdc=0;
+}
+
+
+BaseCloneCanvas::BaseCloneCanvas(ifc_canvas *cloner)
+{
+ if (cloner != NULL) clone(cloner);
+}
+
+int BaseCloneCanvas::clone(ifc_canvas *cloner)
+{
+ ASSERTPR(hdc == NULL, "can't clone twice");
+ hdc = cloner->getHDC();
+ bits = cloner->getBits();
+ cloner->getDim(&width, &height, &pitch);
+ // srcwnd = cloner->getBaseWnd();
+ cloner->getOffsets(&xoffset, &yoffset);
+
+ canvasFontInfo.face = cloner->getTextFont(); // just copies the pointer so be careful
+ canvasFontInfo.pointSize = cloner->getTextSize();
+ canvasFontInfo.bold = cloner->getTextBold();
+ canvasFontInfo.opaque = !!cloner->getTextOpaque();
+ canvasFontInfo.underline = !!cloner->getTextUnderline();
+ canvasFontInfo.italic = !!cloner->getTextItalic();
+ canvasFontInfo.alignFlags = cloner->getTextAlign();
+ canvasFontInfo.color = cloner->getTextColor();
+ canvasFontInfo.bgColor = cloner->getTextBkColor();
+
+ return (hdc != NULL);
+}
+
+BaseCloneCanvas::~BaseCloneCanvas()
+{
+ hdc = NULL;
+}
+
+DDSurfaceCanvas::DDSurfaceCanvas(LPDIRECTDRAWSURFACE surface, int w, int h)
+{
+ surf = surface;
+ _w = w;
+ _h = h;
+ hdc = NULL;
+ bits = NULL;
+}
+
+DDSurfaceCanvas::~DDSurfaceCanvas()
+{
+ if (isready())
+ exit();
+}
+
+int DDSurfaceCanvas::isready()
+{
+ return bits != NULL;
+}
+
+void DDSurfaceCanvas::enter()
+{
+ DDSURFACEDESC d = {sizeof(d), };
+ if ((surf->Lock(NULL, &d, DDLOCK_WAIT, NULL)) != DD_OK)
+ return ;
+
+ surf->GetDC(&hdc);
+
+ bits = d.lpSurface;
+}
+
+void DDSurfaceCanvas::exit()
+{
+ surf->ReleaseDC(hdc);
+ surf->Unlock(bits);
+ bits = NULL;
+ hdc = NULL;
+}
+
+
+#endif//WIN32
diff --git a/Src/tataki/color/filteredcolor.cpp b/Src/tataki/color/filteredcolor.cpp
new file mode 100644
index 00000000..119fe3b9
--- /dev/null
+++ b/Src/tataki/color/filteredcolor.cpp
@@ -0,0 +1,78 @@
+#include "filteredcolor.h"
+#include <tataki/api__tataki.h>
+#include <bfc/bfc_assert.h>
+
+static const int *skin_iterator=0;
+
+FilteredColor::FilteredColor(ARGB32 _color, const wchar_t *colorgroupname)
+{
+ group=0;
+ color = _color;
+ filteredcolor = _color;
+ if (colorgroupname)
+ group = _wcsdup(colorgroupname);
+ skin_iterator = NULL;
+ latest_iteration = -1;
+ need_filter = 1;
+}
+
+FilteredColor::~FilteredColor()
+{
+ free(group);
+}
+
+void FilteredColor::setColor(ARGB32 _color)
+{
+ color = _color;
+ filteredcolor = color;
+}
+
+void FilteredColor::setColorGroup(const wchar_t *_group)
+{
+ free(group);
+ if (_group)
+ group = _wcsdup(_group);
+ else
+ group = 0;
+ need_filter = 1;
+}
+
+ARGB32 FilteredColor::getColor()
+{
+ ensureFiltered();
+ return filteredcolor;
+}
+
+ARGB32 *FilteredColor::getColorRef()
+{
+ if (!WASABI_API_SKIN)
+ return 0;
+
+ ensureFiltered();
+ return &filteredcolor;
+}
+
+void FilteredColor::ensureFiltered()
+{
+ // fetch iterator pointer if necessary
+ if (skin_iterator == NULL)
+ {
+ skin_iterator = WASABI_API_PALETTE->getSkinPartIteratorPtr();
+ ASSERT(skin_iterator != NULL);
+ }
+
+ // see if we're current
+ if (*skin_iterator != latest_iteration)
+ {
+ need_filter = 1; // pointer now invalid, must re-get
+ latest_iteration = *skin_iterator; // and then we'll be current
+ }
+
+ if (need_filter && WASABI_API_SKIN)
+ {
+ filteredcolor = WASABI_API_SKIN->filterSkinColor(color, getColorName(), group);
+ need_filter = 0;
+ }
+
+}
+
diff --git a/Src/tataki/color/filteredcolor.h b/Src/tataki/color/filteredcolor.h
new file mode 100644
index 00000000..9499b1c8
--- /dev/null
+++ b/Src/tataki/color/filteredcolor.h
@@ -0,0 +1,29 @@
+#ifndef TATAKI_FILTEREDCOLOR_H
+#define TATAKI_FILTEREDCOLOR_H
+
+#include <tataki/export.h>
+
+class TATAKIAPI FilteredColor
+{
+public:
+ FilteredColor(ARGB32 _color=0, const wchar_t *colorgroupname=L"");
+ virtual ~FilteredColor();
+
+ virtual void setColor(ARGB32 _color);
+ virtual void setColorGroup(const wchar_t *group);
+ ARGB32 getColor();
+ ARGB32 *getColorRef();
+ virtual const wchar_t *getColorName() { return NULL; }
+
+private:
+ void ensureFiltered();
+
+ ARGB32 color;
+ ARGB32 filteredcolor;
+ wchar_t *group;
+ int need_filter;
+ int latest_iteration;
+};
+
+
+#endif
diff --git a/Src/tataki/color/skinclr.cpp b/Src/tataki/color/skinclr.cpp
new file mode 100644
index 00000000..9edacb85
--- /dev/null
+++ b/Src/tataki/color/skinclr.cpp
@@ -0,0 +1,134 @@
+#include "skinclr.h"
+#include <bfc/assert.h>
+#include <tataki/api__tataki.h>
+
+static const int *skin_iterator = 0;
+
+SkinColor::SkinColor(const wchar_t *_name, const wchar_t *colorgroup)
+: FilteredColor(0, (colorgroup == NULL || !*colorgroup) ? L"Text" : colorgroup)
+{
+ name = 0;
+ latest_iteration = -1;
+ //CUT skin_iterator = NULL;
+ setElementName(_name);
+ ovr_grp = colorgroup;
+ dooverride = 0;
+ color_override = 0;
+
+}
+
+SkinColor::~SkinColor()
+{
+ if (name) free(name);
+}
+
+ARGB32 SkinColor::v(ARGB32 defaultColor)
+{
+ if (!name || !*name) return defaultColor;
+
+ if (!iteratorValid())
+ {
+ val = NULL; // pointer now invalid, must re-get
+ latest_iteration = *skin_iterator; // and then we'll be current
+ // new pointer please
+
+ const wchar_t *grp = NULL;
+ ARGB32 r;
+ if (dooverride)
+ r = color_override;
+ else
+ r = WASABI_API_PALETTE->getColorElement(name, &grp);
+ if (ovr_grp == NULL && grp != NULL)
+ setColorGroup(grp);
+ FilteredColor::setColor(r);
+ val = getColorRef();
+ }
+ if (val == NULL) return defaultColor;
+
+ return *val;
+}
+
+void SkinColor::setElementName(const wchar_t *_name)
+{
+ if (name) free(name);
+ if (_name)
+ name = _wcsdup(_name);
+ else
+ name = 0;
+ val = NULL;
+ latest_iteration = 0;
+}
+
+void SkinColor::setColor(ARGB32 c)
+{
+ dooverride = 1;
+ color_override = c;
+ FilteredColor::setColor(color_override);
+}
+
+int SkinColor::iteratorValid()
+{
+ // fetch iterator pointer if necessary
+ if (skin_iterator == NULL)
+ {
+ skin_iterator = WASABI_API_PALETTE->getSkinPartIteratorPtr();
+ ASSERT(skin_iterator != NULL);
+ }
+
+ // see if we're current
+ return (*skin_iterator == latest_iteration);
+}
+
+const wchar_t *SkinColor::operator =(const wchar_t *name) { setElementName(name); return name;}
+const wchar_t *SkinColor::getColorName() { return name; }
+
+ARGB32 SkinColor::GetColor(const wchar_t *name, const wchar_t *group, ARGB32 defaultColor)
+{
+ const wchar_t *colorGroup = NULL;
+ const ARGB32 *color = WASABI_API_PALETTE->getColorElementRef(name, &colorGroup);
+
+ if (!color)
+ return defaultColor;
+
+ /* TODO: benski> if we ever add color themes to Classic, we'll need to change this */
+ if (WASABI_API_SKIN)
+ {
+ if (group)
+ colorGroup = group;
+
+ if (!colorGroup)
+ colorGroup = L"Text";
+
+ return WASABI_API_SKIN->filterSkinColor(*color, name, colorGroup);
+ }
+ else
+ {
+ return *color;
+ }
+}
+
+bool SkinColor::TryGetColor(ARGB32 *returned_color, const wchar_t *name, const wchar_t *group)
+{
+ const wchar_t *colorGroup = NULL;
+ const ARGB32 *color = WASABI_API_PALETTE->getColorElementRef(name, &colorGroup);
+
+ if (!color)
+ return false;
+
+ /* TODO: benski> if we ever add color themes to Classic, we'll need to change this */
+ if (WASABI_API_SKIN)
+ {
+ if (group)
+ colorGroup = group;
+
+ if (!colorGroup)
+ colorGroup = L"Text";
+
+ *returned_color = WASABI_API_SKIN->filterSkinColor(*color, name, colorGroup);
+ }
+ else
+ {
+ *returned_color = *color;
+ }
+ return true;
+} \ No newline at end of file
diff --git a/Src/tataki/color/skinclr.h b/Src/tataki/color/skinclr.h
new file mode 100644
index 00000000..743eaa9c
--- /dev/null
+++ b/Src/tataki/color/skinclr.h
@@ -0,0 +1,39 @@
+#ifndef TATAKI_SKINCLR_H
+#define TATAKI_SKINCLR_H
+
+#include <tataki/export.h>
+#include "filteredcolor.h"
+
+// note: only pass in a const char *
+class TATAKIAPI SkinColor : public FilteredColor
+{
+public:
+ explicit SkinColor(const wchar_t *name=NULL, const wchar_t *colorgroup=NULL);
+ ~SkinColor();
+ virtual void setColor(ARGB32 c);
+
+ ARGB32 v(ARGB32 defaultColor=0xFFFF00FF);
+ operator int() { return v(); }
+
+ void setElementName(const wchar_t *name);
+ const wchar_t *operator =(const wchar_t *name);
+ virtual const wchar_t *getColorName();
+
+ int iteratorValid(); // if FALSE, color might have changed
+
+ // if you just need to do a one-off skin color query, use this function
+// because SkinColor class does some malloc'ing
+ static ARGB32 GetColor(const wchar_t *name, const wchar_t *group = 0, ARGB32 defaultColor=0xFFFF00FF);
+ static bool TryGetColor(ARGB32 *color, const wchar_t *name, const wchar_t *group = 0);
+private:
+ wchar_t *name;
+ ARGB32 *val;
+ int latest_iteration;
+ const wchar_t *ovr_grp;
+ int color_override;
+ int dooverride;
+};
+
+
+
+#endif
diff --git a/Src/tataki/export.h b/Src/tataki/export.h
new file mode 100644
index 00000000..6229189b
--- /dev/null
+++ b/Src/tataki/export.h
@@ -0,0 +1,33 @@
+#ifndef TATAKI_EXPORT_H
+#define TATAKI_EXPORT_H
+
+#include <bfc/platform/types.h>
+#include <api/service/api_service.h>
+
+#ifdef _WIN32
+#ifdef TATAKI_STATIC
+#define TATAKIAPI
+#else
+#ifdef TATAKI_EXPORTS
+#define TATAKIAPI __declspec(dllexport)
+#else
+#define TATAKIAPI __declspec(dllimport)
+#endif
+#endif
+#elif defined(__GNUC__)
+#ifdef TATAKI_EXPORTS
+#define TATAKIAPI __attribute__ ((visibility("default")))
+#else
+#define TATAKIAPI
+#endif
+#else
+#error port me
+#endif
+
+namespace Tataki
+{
+extern "C" TATAKIAPI size_t Init(api_service *_serviceApi);
+extern "C" TATAKIAPI size_t Quit();
+}
+
+#endif \ No newline at end of file
diff --git a/Src/tataki/main.cpp b/Src/tataki/main.cpp
new file mode 100644
index 00000000..ed211aac
--- /dev/null
+++ b/Src/tataki/main.cpp
@@ -0,0 +1,122 @@
+#include "api__tataki.h"
+#include <api/service/waservicefactory.h>
+#include <tataki/export.h>
+#include <tataki/canvas/bltcanvas.h>
+#include "../nu/ServiceWatcher.h"
+
+api_service *WASABI_API_SVC=0;
+api_application *WASABI_API_APP=0;
+api_syscb *WASABI_API_SYSCB=0;
+api_font *WASABI_API_FONT=0;
+wnd_api *WASABI_API_WND=0;
+api_config *WASABI_API_CONFIG=0;
+imgldr_api *WASABI_API_IMGLDR=0;
+api_memmgr *WASABI_API_MEMMGR=0;
+api_skin *WASABI_API_SKIN=0;
+api_random *AGAVE_API_RANDOM=0;
+api_palette *WASABI_API_PALETTE=0;
+DWORD bitmap_cache_tls=TLS_OUT_OF_INDEXES;
+
+ServiceWatcher serviceWatcher;
+template <class api_t>
+api_t *GetService(GUID serviceGUID)
+{
+ waServiceFactory *sf = WASABI_API_SVC->service_getServiceByGuid(serviceGUID);
+ if (sf)
+ return reinterpret_cast<api_t *>( sf->getInterface() );
+ else
+ return 0;
+
+}
+
+template <class api_t>
+inline void ReleaseService(GUID serviceGUID, api_t *&service)
+{
+ if (service)
+ {
+ waServiceFactory *sf = WASABI_API_SVC->service_getServiceByGuid(serviceGUID);
+ if (sf)
+ sf->releaseInterface(service);
+
+ service=0;
+ }
+}
+
+static size_t refCount=0;
+TATAKIAPI size_t Tataki::Init(api_service *_serviceApi)
+{
+ refCount++;
+ if (bitmap_cache_tls == TLS_OUT_OF_INDEXES)
+ bitmap_cache_tls=TlsAlloc();
+
+ if (!WASABI_API_SVC)
+ {
+ WASABI_API_SVC = _serviceApi;
+ WASABI_API_SYSCB = GetService<api_syscb>(syscbApiServiceGuid);
+ AGAVE_API_RANDOM = GetService<api_random>(randomApiGUID);
+ WASABI_API_PALETTE = GetService<api_palette>(PaletteManagerGUID);
+
+ serviceWatcher.WatchWith(WASABI_API_SVC);
+ serviceWatcher.WatchFor(&WASABI_API_APP, applicationApiServiceGuid);
+ serviceWatcher.WatchFor(&WASABI_API_FONT, fontApiServiceGuid);
+ serviceWatcher.WatchFor(&WASABI_API_WND, wndApiServiceGuid);
+ serviceWatcher.WatchFor(&WASABI_API_CONFIG, configApiServiceGuid);
+ serviceWatcher.WatchFor(&WASABI_API_IMGLDR, imgLdrApiServiceGuid);
+ serviceWatcher.WatchFor(&WASABI_API_MEMMGR, memMgrApiServiceGuid);
+ serviceWatcher.WatchFor(&WASABI_API_SKIN, skinApiServiceGuid);
+
+ // register for service callbacks in case any of these don't exist yet
+ WASABI_API_SYSCB->syscb_registerCallback(&serviceWatcher);
+ }
+ return refCount;
+}
+
+TATAKIAPI size_t Tataki::Quit()
+{
+ if (!--refCount)
+ {
+ serviceWatcher.StopWatching();
+ serviceWatcher.Clear();
+
+ ReleaseService(syscbApiServiceGuid, WASABI_API_SYSCB);
+ ReleaseService(applicationApiServiceGuid, WASABI_API_APP);
+ ReleaseService(fontApiServiceGuid,WASABI_API_FONT);
+ ReleaseService(wndApiServiceGuid, WASABI_API_WND);
+ ReleaseService(configApiServiceGuid, WASABI_API_CONFIG);
+ ReleaseService(imgLdrApiServiceGuid, WASABI_API_IMGLDR);
+ ReleaseService(memMgrApiServiceGuid, WASABI_API_MEMMGR);
+ ReleaseService(skinApiServiceGuid, WASABI_API_SKIN);
+ ReleaseService(randomApiGUID, AGAVE_API_RANDOM);
+ ReleaseService(PaletteManagerGUID, WASABI_API_PALETTE);
+
+ // unregister callbacks
+ // release any services we have
+ WASABI_API_SVC = 0;
+ }
+ return refCount;
+}
+
+extern "C" BOOL WINAPI DllMain(
+ HINSTANCE hinstDLL,
+ DWORD fdwReason,
+ LPVOID lpvReserved
+)
+{
+ Wasabi::Std::Initialize();
+ if (fdwReason == DLL_PROCESS_DETACH && bitmap_cache_tls!=TLS_OUT_OF_INDEXES)
+ {
+ TlsFree(bitmap_cache_tls);
+ bitmap_cache_tls=TLS_OUT_OF_INDEXES;
+ }
+ else if (fdwReason == DLL_THREAD_DETACH && bitmap_cache_tls!=TLS_OUT_OF_INDEXES)
+ {
+ BltCanvas *cache_canvas = (BltCanvas *)TlsGetValue(bitmap_cache_tls);
+ if (cache_canvas)
+ {
+ delete cache_canvas;
+ TlsSetValue(bitmap_cache_tls, 0); // this is probably unnecessary but just in case
+ }
+
+ }
+ return TRUE;
+}
diff --git a/Src/tataki/region/api_region.cpp b/Src/tataki/region/api_region.cpp
new file mode 100644
index 00000000..f9c263ef
--- /dev/null
+++ b/Src/tataki/region/api_region.cpp
@@ -0,0 +1 @@
+#include "api_region.h" \ No newline at end of file
diff --git a/Src/tataki/region/api_region.h b/Src/tataki/region/api_region.h
new file mode 100644
index 00000000..2dbcd51f
--- /dev/null
+++ b/Src/tataki/region/api_region.h
@@ -0,0 +1,201 @@
+#ifndef __WASABI_API_REGION_H
+#define __WASABI_API_REGION_H
+
+#include <bfc/dispatch.h>
+#include <bfc/platform/export.h>
+
+class NOVTABLE api_region : public Dispatchable
+{
+protected:
+ api_region() {}
+ virtual ~api_region() {}
+
+public:
+ DISPATCH_CODES
+ {
+ REGION_GETOSHANDLE = 50,
+ REGION_CLONE = 100,
+ REGION_DISPOSECLONE = 110,
+ REGION_PTINREGION = 120,
+ REGION_OFFSET = 130,
+ REGION_GETBOX = 140,
+ REGION_SUBTRACTRGN = 150,
+ REGION_SUBTRACTRECT = 160,
+ REGION_ADDRECT = 170,
+ REGION_ADD = 180,
+ REGION_AND = 190,
+ REGION_SETRECT = 200,
+ REGION_EMPTY = 210,
+ REGION_ISEMPTY = 220,
+ REGION_EQUALS = 230,
+ REGION_ENCLOSED = 240,
+ REGION_INTERSECTRGN = 250,
+ REGION_DOESINTERSECTRGN = 251,
+ REGION_INTERSECTRECT = 260,
+ REGION_ISRECT = 270,
+ REGION_SCALE = 280,
+ REGION_DEBUG = 290,
+ REGION_MAKEWNDREGION = 300,
+ REGION_GETNUMRECTS = 310,
+ REGION_ENUMRECT = 320,
+ };
+public:
+ OSREGIONHANDLE getOSHandle(); // avoid as much as you can, should be used only when you need to call the OS api
+
+ api_region *clone();
+ void disposeClone(api_region *r);
+ bool ptInRegion(const POINT *pt);
+ void offset(int x, int y);
+ void getBox(RECT *r);
+ void subtractRegion(const api_region *r);
+ void subtractRgn(const api_region *r) { subtractRegion(r); } //DEPRECATED
+ void subtractRect(const RECT *r);
+ void addRect(const RECT *r);
+ void addRegion(const api_region *r);
+ void andRegion(const api_region *r);
+ void setRect(const RECT *r);
+ void empty();
+ int isEmpty();
+ int equals(const api_region *r);
+ int enclosed(const api_region *r, api_region *outside = NULL);
+ int intersectRgn(const api_region *r, api_region *intersection);
+ int doesIntersectRgn(const api_region *r);
+ int intersectRect(const RECT *r, api_region *intersection);
+
+ int isRect();
+ void scale(double sx, double sy, bool round = 0);
+ void debug(int async = 0);
+ OSREGIONHANDLE makeWindowRegion(); // gives you a handle to a clone of the OSREGION object so you can insert it into a window's region with SetWindowRgn. ANY other use is prohibited
+
+ // this is how you can enumerate the subrects that compose to make up the
+ // entire region
+ int getNumRects();
+ int enumRect(int n, RECT *r);
+};
+
+inline OSREGIONHANDLE api_region::getOSHandle()
+{
+ return _call(REGION_GETOSHANDLE, (OSREGIONHANDLE)NULL);
+}
+
+inline api_region *api_region::clone()
+{
+ return _call(REGION_CLONE, (api_region *)NULL);
+}
+
+inline void api_region::disposeClone(api_region *r)
+{
+ _voidcall(REGION_DISPOSECLONE, r);
+}
+
+inline bool api_region::ptInRegion(const POINT *pt)
+{
+ return _call(REGION_PTINREGION, false, pt);
+}
+
+inline void api_region::offset(int x, int y)
+{
+ _voidcall(REGION_OFFSET, x, y);
+}
+
+inline void api_region::getBox(RECT *r)
+{
+ _voidcall(REGION_GETBOX, r);
+}
+
+inline void api_region::subtractRegion(const api_region *reg)
+{
+ _voidcall(REGION_SUBTRACTRGN, reg);
+}
+
+inline void api_region::subtractRect(const RECT *r)
+{
+ _voidcall(REGION_SUBTRACTRECT, r);
+}
+
+inline void api_region::addRect(const RECT *r)
+{
+ _voidcall(REGION_ADDRECT, r);
+}
+
+inline void api_region::addRegion(const api_region *r)
+{
+ _voidcall(REGION_ADD, r);
+}
+
+inline void api_region::andRegion(const api_region *r)
+{
+ _voidcall(REGION_AND, r);
+}
+
+inline void api_region::setRect(const RECT *r)
+{
+ _voidcall(REGION_SETRECT, r);
+}
+
+inline void api_region::empty()
+{
+ _voidcall(REGION_EMPTY);
+}
+
+inline int api_region::isEmpty()
+{
+ return _call(REGION_ISEMPTY, 0);
+}
+
+inline int api_region::equals(const api_region *r)
+{
+ return _call(REGION_EQUALS, 0, r);
+}
+
+inline int api_region::enclosed(const api_region *r, api_region *outside)
+{
+ return _call(REGION_ENCLOSED, 0, r, outside);
+}
+
+inline int api_region::intersectRgn(const api_region *r, api_region *intersection)
+{
+ return _call(REGION_INTERSECTRGN, 0, r, intersection);
+}
+
+inline int api_region::doesIntersectRgn(const api_region *r)
+{
+ return _call(REGION_DOESINTERSECTRGN, 0, r);
+}
+
+inline int api_region::intersectRect(const RECT *r, api_region *intersection)
+{
+ return _call(REGION_INTERSECTRECT, 0, r, intersection);
+}
+
+inline int api_region::isRect()
+{
+ return _call(REGION_ISRECT, 0);
+}
+
+inline void api_region::scale(double sx, double sy, bool round)
+{
+ _voidcall(REGION_SCALE, sx, sy, round);
+}
+
+inline void api_region::debug(int async)
+{
+ _voidcall(REGION_DEBUG, async);
+}
+
+inline OSREGIONHANDLE api_region::makeWindowRegion()
+{
+ return _call(REGION_MAKEWNDREGION, (OSREGIONHANDLE)NULL);
+}
+
+inline int api_region::getNumRects()
+{
+ return _call(REGION_GETNUMRECTS, 0);
+}
+
+inline int api_region::enumRect(int n, RECT *r)
+{
+ return _call(REGION_ENUMRECT, 0, n, r);
+}
+
+#endif
diff --git a/Src/tataki/region/mac/osx_region_hishape.cpp b/Src/tataki/region/mac/osx_region_hishape.cpp
new file mode 100644
index 00000000..348ba1de
--- /dev/null
+++ b/Src/tataki/region/mac/osx_region_hishape.cpp
@@ -0,0 +1,217 @@
+#include <Carbon/Carbon.h>
+#include <tataki/region/region.h>
+#include <tataki/bitmap/bitmap.h>
+
+RegionI::RegionI() : rgn(0)
+{
+}
+
+RegionI::RegionI(const RECT *r) : rgn(0)
+{
+ setRect(r);
+}
+
+RegionI::RegionI(HIMutableShapeRef _rgn) : rgn(_rgn)
+{
+}
+
+RegionI::RegionI(HIShapeRef _rgn)
+{
+ rgn=HIShapeCreateMutableCopy(_rgn);
+}
+
+RegionI::~RegionI()
+{
+ if (rgn)
+ CFRelease(rgn);
+}
+
+RegionI::RegionI(RgnHandle qdrgn)
+{
+ HIShapeRef shape = HIShapeCreateWithQDRgn(qdrgn);
+ rgn = HIShapeCreateMutableCopy(shape);
+ CFRelease(shape);
+}
+
+RegionI::RegionI(SkinBitmap *bitmap)
+{
+ // TODO: we need to find a much better way to do this
+ RECT r;
+ r.left=0;
+ r.top=0;
+ r.right=bitmap->getWidth();
+ r.bottom=bitmap->getHeight();
+ setRect(&r);
+}
+
+
+OSREGIONHANDLE RegionI::getOSHandle()
+{
+ if (!rgn)
+ rgn = HIShapeCreateMutable();
+ return rgn;
+}
+
+api_region *RegionI::clone()
+{
+ if (!rgn)
+ return new RegionI();
+ else
+ return new RegionI(HIShapeCreateMutableCopy(rgn));
+}
+
+void RegionI::disposeClone(api_region *r)
+{
+ if (r) // yes we need to check for NULL here because r != static_cast<>(r)
+ delete static_cast<RegionI *>(r);
+}
+
+bool RegionI::ptInRegion(const POINT *pt)
+{
+ if (!rgn)
+ return false;
+ HIPoint hipt = HIPointFromPOINT(pt);
+ return !!HIShapeContainsPoint(rgn, &hipt);
+}
+
+void RegionI::offset(int x, int y)
+{
+ if (!rgn)
+ rgn = HIShapeCreateMutable();
+
+ HIShapeOffset(rgn, x, y);
+}
+
+void RegionI::getBox(RECT *r)
+{
+ if (!rgn) // TODO: we could manually set r to 0,0,0,0
+ rgn = HIShapeCreateMutable();
+
+ HIRect rect;
+ HIShapeGetBounds(rgn, &rect);
+ *r = RECTFromHIRect(&rect);
+}
+
+void RegionI::subtractRegion(const api_region *r)
+{
+ if (rgn)
+ {
+ api_region *reg = const_cast<api_region *>(r);
+ HIShapeRef sub = reg->getOSHandle();
+ HIShapeDifference(rgn,sub, rgn);
+ }
+}
+
+void RegionI::subtractRect(const RECT *r)
+{
+ if (rgn)
+ {
+ HIRect rect = HIRectFromRECT(r);
+ HIShapeRef sub = HIShapeCreateWithRect(&rect);
+ HIShapeDifference(rgn, sub, rgn);
+ }
+}
+
+void RegionI::addRect(const RECT *r)
+{
+ if (!rgn)
+ rgn = HIShapeCreateMutable();
+ HIRect rect = HIRectFromRECT(r);
+ HIShapeRef add = HIShapeCreateWithRect(&rect);
+ HIShapeUnion(rgn, add, rgn);
+}
+
+void RegionI::addRegion(const api_region *r)
+{
+ if (!rgn)
+ rgn = HIShapeCreateMutable();
+ api_region *reg = const_cast<api_region *>(r);
+ HIShapeRef add = reg->getOSHandle();
+ HIShapeUnion(rgn, add, rgn);
+}
+
+void RegionI::andRegion(const api_region *r)
+{
+ if (rgn) // intersection with empty region will always be empty
+ {
+ api_region *reg = const_cast<api_region *>(r);
+ HIShapeRef intersection = reg->getOSHandle();
+ HIShapeIntersect(rgn, intersection, rgn);
+ }
+}
+
+void RegionI::setRect(const RECT *r)
+{
+ if (rgn)
+ CFRelease(rgn);
+ HIRect rect = HIRectFromRECT(r);
+ HIShapeRef rectRgn = HIShapeCreateWithRect(&rect);
+ rgn = HIShapeCreateMutableCopy(rectRgn);
+ CFRelease(rectRgn);
+}
+
+void RegionI::empty()
+{
+ if (rgn)
+ CFRelease(rgn);
+ rgn=0;
+}
+
+int RegionI::isEmpty()
+{
+ if (!rgn)
+ return 1;
+ return !!HIShapeIsEmpty(rgn);
+}
+
+int RegionI::isRect()
+{
+ if (!rgn)
+ return 1;
+ return !!HIShapeIsRectangular(rgn);
+}
+
+int RegionI::intersectRgn(const api_region *r, api_region *intersection)
+{
+ intersection->empty();
+ intersection->addRegion(this);
+ intersection->andRegion(r);
+ return !intersection->isEmpty();
+}
+
+int RegionI::intersectRect(const RECT *r, api_region *intersection)
+{
+ intersection->setRect(r);
+ intersection->andRegion(this);
+ return !intersection->isEmpty();
+}
+
+#define CBCLASS RegionI
+START_DISPATCH;
+CB(REGION_GETOSHANDLE, getOSHandle);
+CB(REGION_CLONE, clone);
+VCB(REGION_DISPOSECLONE, disposeClone);
+CB(REGION_PTINREGION, ptInRegion);
+VCB(REGION_OFFSET, offset);
+VCB(REGION_GETBOX, getBox);
+VCB(REGION_SUBTRACTRGN, subtractRegion);
+VCB(REGION_SUBTRACTRECT, subtractRect);
+VCB(REGION_ADDRECT, addRect);
+VCB(REGION_ADD, addRegion);
+VCB(REGION_AND, andRegion);
+VCB(REGION_SETRECT, setRect);
+VCB(REGION_EMPTY, empty);
+CB(REGION_ISEMPTY, isEmpty);
+CB(REGION_ISRECT, isRect);
+CB(REGION_INTERSECTRGN, intersectRgn);
+CB(REGION_INTERSECTRECT, intersectRect);
+END_DISPATCH;
+#undef CBCLASS
+
+#define CBCLASS RegionServerI
+START_DISPATCH;
+VCB(REGIONSERVER_ADDREF, addRef);
+VCB(REGIONSERVER_DELREF, delRef);
+CB(REGIONSERVER_GETREGION, getRegion);
+END_DISPATCH;
+#undef CBCLASS \ No newline at end of file
diff --git a/Src/tataki/region/mac/region.h b/Src/tataki/region/mac/region.h
new file mode 100644
index 00000000..f3404ea2
--- /dev/null
+++ b/Src/tataki/region/mac/region.h
@@ -0,0 +1,116 @@
+#ifndef __REGION_H
+#define __REGION_H
+
+#include <tataki/export.h>
+#include <Carbon/Carbon.h>
+#include <bfc/platform/platform.h>
+#include <tataki/region/api_region.h>
+
+class SkinBitmap;
+
+class TATAKIAPI RegionI : public api_region
+{
+public:
+ RegionI();
+ RegionI(const RECT *r);
+ RegionI(RgnHandle qdrgn);
+ RegionI(HIShapeRef _rgn);
+ RegionI(SkinBitmap *bitmap);
+ ~RegionI();
+
+ // api_region
+ OSREGIONHANDLE getOSHandle();
+ api_region *clone();
+ void disposeClone(api_region *r);
+ bool ptInRegion(const POINT *pt);
+ void offset(int x, int y);
+ void getBox(RECT *r);
+ void subtractRegion(const api_region *r);
+ void subtractRect(const RECT *r);
+ void addRect(const RECT *r);
+ void addRegion(const api_region *r);
+ void andRegion(const api_region *r);
+ void setRect(const RECT *r);
+ void empty();
+ int isEmpty();
+ int equals(const api_region *r);
+ int enclosed(const api_region *r, api_region *outside = NULL);
+ int intersectRgn(const api_region *r, api_region *intersection);
+ int doesIntersectRgn(const api_region *r);
+ int intersectRect(const RECT *r, api_region *intersection);
+
+ int isRect();
+ void scale(double sx, double sy, bool round = 0);
+ void debug(int async = 0);
+ OSREGIONHANDLE makeWindowRegion(); // gives you a handle to a clone of the OSREGION object so you can insert it into a window's region with SetWindowRgn. ANY other use is prohibited
+
+ // this is how you can enumerate the subrects that compose to make up the
+ // entire region
+ int getNumRects();
+ int enumRect(int n, RECT *r);
+
+
+private:
+ RegionI(HIMutableShapeRef _rgn);
+ HIMutableShapeRef rgn;
+
+protected:
+ RECVS_DISPATCH;
+};
+
+
+// TODO: we could take of advantage of HIShapeRef's built in reference counting to implement this
+class RegionServer : public Dispatchable {
+
+protected:
+ RegionServer() {}
+ virtual ~RegionServer() {}
+
+public:
+
+ void addRef(void *client);
+ void delRef(void *client);
+ api_region *getRegion();
+
+ enum {
+ REGIONSERVER_ADDREF = 500,
+ REGIONSERVER_DELREF = 550,
+ REGIONSERVER_GETREGION = 600,
+ };
+};
+
+inline void RegionServer::addRef(void *client) {
+ _voidcall(REGIONSERVER_ADDREF, (api_region *)NULL, client);
+}
+
+inline void RegionServer::delRef(void *client) {
+ _voidcall(REGIONSERVER_DELREF, client);
+}
+
+inline api_region * RegionServer::getRegion() {
+ return _call(REGIONSERVER_GETREGION, (api_region *)NULL);
+}
+
+class TATAKIAPI RegionServerI : public RegionServer {
+public :
+
+ RegionServerI() { numrefs = 0; }
+ virtual ~RegionServerI() {}
+
+ virtual void addRef(void *client) { numrefs++; }
+ virtual void delRef(void *client) { numrefs--; }
+ virtual api_region *getRegion()=0;
+
+ virtual int getNumRefs() { return numrefs; }
+
+protected:
+
+ RECVS_DISPATCH;
+
+private:
+
+ int numrefs;
+};
+#endif
+
+
diff --git a/Src/tataki/region/region.h b/Src/tataki/region/region.h
new file mode 100644
index 00000000..cf03c01c
--- /dev/null
+++ b/Src/tataki/region/region.h
@@ -0,0 +1,5 @@
+#if defined _WIN64 || defined _WIN32
+#include "win/region.h"
+#elif defined(__APPLE__)
+#include "mac/region.h"
+#endif
diff --git a/Src/tataki/region/win/region.h b/Src/tataki/region/win/region.h
new file mode 100644
index 00000000..849fba3e
--- /dev/null
+++ b/Src/tataki/region/win/region.h
@@ -0,0 +1,137 @@
+#ifndef __REGION_H
+#define __REGION_H
+
+#include <tataki/bitmap/bitmap.h>
+#include <bfc/dispatch.h>
+#include <tataki/export.h>
+
+class BaseWnd;
+class Canvas;
+class api_region;
+class RegionServer;
+
+#include <tataki/region/api_region.h>
+
+class TATAKIAPI RegionI : public api_region
+{
+public:
+ RegionI();
+ RegionI(const RegionI *copy);
+ RegionI(const RECT *r);
+ RegionI(int l, int t, int r, int b);
+ RegionI(OSREGIONHANDLE region);
+ RegionI(SkinBitmap *bitmap, RECT *r=NULL, int xoffset=0, int yoffset=0, bool inverted=false, int dothreshold=0, __int8 threshold=0, int threversed=0, int minalpha=1);
+ RegionI(Canvas *c, RECT *defboundbox=NULL);
+ virtual ~RegionI();
+
+ api_region *clone();
+ void disposeClone(api_region *r);
+ bool ptInRegion(const POINT *pt);
+ void offset(int x, int y);
+ void getBox(RECT *r);
+ void subtractRegion(const api_region *reg);
+ void subtractRect(const RECT *r);
+ void addRect(const RECT *r);
+ void addRegion(const api_region *r);
+ void andRegion(const api_region *r);
+ void setRect(const RECT *r);
+ void empty();
+ int isEmpty();
+ int equals(const api_region *r);
+ int enclosed(const api_region *r, api_region *outside=NULL);
+ int intersectRgn(const api_region *r, api_region *intersection);
+ int doesIntersectRgn(const api_region *r);
+ int intersectRect(const RECT *r, api_region *intersection);
+ int doesIntersectRect(const RECT *r);
+ int isRect();
+ void scale(double sx, double sy, bool round=0);
+ void debug(int async=0);
+
+ // NONPORTABLE
+
+ OSREGIONHANDLE makeWindowRegion(); // gives you a handle to a clone of the OSREGION object so you can insert it into a window's region with SetWindowRgn. ANY other use is prohibited
+ OSREGIONHANDLE getOSHandle(); // avoid as much as you can, should be used only by WIN32-dependant classes
+
+ // END NONPORTABLE
+
+ int getNumRects();
+ int enumRect(int n, RECT *r);
+
+ OSREGIONHANDLE alphaToRegionRect(void *pbits32, int bmX, int bmY, int bmWidth, int bmHeight, int fullw, int fullh, int xoffset, int yoffset, bool portion, int _x, int _y, int _w, int _h, bool inverted, int dothreshold, unsigned __int8 threshold, int thinverse, int minalpha);
+
+private:
+
+ inline void init();
+ void optimize();
+ void deoptimize();
+
+ OSREGIONHANDLE hrgn;
+ OSREGIONHANDLE alphaToRegionRect(SkinBitmap *bitmap, int xoffset, int yoffset, bool portion, int _x, int _y, int _w, int _h, bool inverted=false, int dothreshold=0, unsigned __int8 threshold=0, int thinverse=0, int minalpha=1/* 1..255*/);
+ RECT overlay;
+ int clonecount;
+ RegionI *lastdebug;
+ RegionServer *srv;
+ RECT optrect;
+ int optimized;
+
+protected:
+
+ RECVS_DISPATCH;
+};
+
+class RegionServer : public Dispatchable {
+
+ protected:
+ RegionServer() {}
+ virtual ~RegionServer() {}
+
+ public:
+
+ void addRef(void *client);
+ void delRef(void *client);
+ api_region *getRegion();
+
+ enum {
+ REGIONSERVER_ADDREF = 500,
+ REGIONSERVER_DELREF = 550,
+ REGIONSERVER_GETREGION = 600,
+ };
+};
+
+inline void RegionServer::addRef(void *client) {
+ _voidcall(REGIONSERVER_ADDREF, (api_region *)NULL, client);
+}
+
+inline void RegionServer::delRef(void *client) {
+ _voidcall(REGIONSERVER_DELREF, client);
+}
+
+inline api_region * RegionServer::getRegion() {
+ return _call(REGIONSERVER_GETREGION, (api_region *)NULL);
+}
+
+class TATAKIAPI RegionServerI : public RegionServer
+{
+ public :
+
+ RegionServerI() { numrefs = 0; }
+ virtual ~RegionServerI() {}
+
+ virtual void addRef(void *client) { numrefs++; }
+ virtual void delRef(void *client) { numrefs--; }
+ virtual api_region *getRegion()=0;
+
+ virtual int getNumRefs() { return numrefs; }
+
+ protected:
+
+ RECVS_DISPATCH;
+
+ private:
+
+ int numrefs;
+};
+
+#endif
+
+
diff --git a/Src/tataki/region/win/win32_region.cpp b/Src/tataki/region/win/win32_region.cpp
new file mode 100644
index 00000000..5fb3c3c5
--- /dev/null
+++ b/Src/tataki/region/win/win32_region.cpp
@@ -0,0 +1,813 @@
+#if defined _WIN64 || defined _WIN32
+#include <tataki/api__tataki.h>
+#include "region.h"
+#include <api/imgldr/api_imgldr.h>
+#include <tataki/region/api_region.h>
+#include <tataki/canvas/ifc_canvas.h>
+#include <api/wnd/basewnd.h>
+
+
+#define GETOSHANDLE(x) (const_cast<api_region *>(x)->getOSHandle())
+
+#define CBCLASS RegionI
+START_DISPATCH;
+CB(REGION_GETOSHANDLE, getOSHandle);
+CB(REGION_CLONE, clone);
+VCB(REGION_DISPOSECLONE, disposeClone);
+CB(REGION_PTINREGION, ptInRegion);
+VCB(REGION_OFFSET, offset);
+VCB(REGION_GETBOX, getBox);
+VCB(REGION_SUBTRACTRGN, subtractRegion);
+VCB(REGION_SUBTRACTRECT, subtractRect);
+VCB(REGION_ADDRECT, addRect);
+VCB(REGION_ADD, addRegion);
+VCB(REGION_AND, andRegion);
+VCB(REGION_SETRECT, setRect);
+VCB(REGION_EMPTY, empty);
+CB(REGION_ISEMPTY, isEmpty);
+CB(REGION_EQUALS, equals);
+CB(REGION_ENCLOSED, enclosed);
+CB(REGION_INTERSECTRECT, intersectRect);
+CB(REGION_DOESINTERSECTRGN, doesIntersectRgn);
+CB(REGION_INTERSECTRGN, intersectRgn);
+CB(REGION_ISRECT, isRect);
+VCB(REGION_SCALE, scale);
+VCB(REGION_DEBUG, debug);
+CB(REGION_MAKEWNDREGION, makeWindowRegion);
+CB(REGION_GETNUMRECTS, getNumRects);
+CB(REGION_ENUMRECT, enumRect);
+END_DISPATCH;
+#undef CBCLASS
+
+#define CHECK_REGION \
+ if (hrgn == NULL) hrgn = CreateRectRgn(0,0,0,0);
+
+RegionI::RegionI()
+{
+ hrgn = CreateRectRgn(0, 0, 0, 0);
+ init();
+}
+
+RegionI::RegionI(const RECT *r)
+{
+ hrgn = 0;
+ init();
+ optrect = *r;
+ optimized = 1;
+ //hrgn = CreateRectRgn(r->left,r->top,r->right,r->bottom);
+ //if (!hrgn) hrgn = CreateRectRgn(0,0,0,0);
+ //init();
+ //optimize();
+}
+
+RegionI::RegionI(int l, int t, int r, int b)
+{
+ hrgn = 0;
+ init();
+ optrect.left = l;
+ optrect.top = t;
+ optrect.right = r;
+ optrect.bottom = b;
+ optimized = 1;
+
+ //hrgn = CreateRectRgn(l,t,r,b);
+ //if (!hrgn) hrgn = CreateRectRgn(0,0,0,0);
+ //init();
+ //optimize();
+}
+
+RegionI::RegionI(OSREGIONHANDLE r)
+{
+ OSREGIONHANDLE R = CreateRectRgn(0, 0, 0, 0);
+ CombineRgn(R, r, r, RGN_COPY);
+ hrgn = R;
+ init();
+ optimize();
+}
+
+RegionI::RegionI(const RegionI *copy)
+{
+ init();
+ if (copy->optimized)
+ {
+ optrect = copy->optrect;
+ optimized = copy->optimized;
+ hrgn = 0;
+ }
+ else
+ {
+ hrgn = CreateRectRgn(0, 0, 0, 0);
+ CombineRgn(hrgn, copy->hrgn, copy->hrgn, RGN_COPY);
+ }
+}
+
+RegionI::RegionI(Canvas *c, RECT *defbounds)
+{
+ hrgn = CreateRectRgn(0, 0, 0, 0);
+ if (!GetClipRgn(c->getHDC(), hrgn))
+ {
+ if (defbounds != NULL)
+ {
+ SetRectRgn(hrgn, defbounds->left, defbounds->top, defbounds->right, defbounds->bottom);
+ optrect=*defbounds;
+ optimized=1;
+ }
+ }
+ init();
+ optimize();
+}
+
+RegionI::~RegionI()
+{
+ delete lastdebug;
+ if (srv != NULL) srv->delRef(this);
+ ASSERT(clonecount == 0);
+ if (srv == NULL && hrgn != NULL) DeleteObject(hrgn);
+}
+
+void RegionI::init()
+{
+ srv = NULL;
+ clonecount = 0;
+ lastdebug = NULL;
+ optimized = 0;
+}
+
+api_region *RegionI::clone()
+{
+ api_region *newregion = new RegionI(this);
+ clonecount++;
+ return newregion;
+}
+
+void RegionI::disposeClone(api_region *r)
+{
+ RegionI *ri = static_cast<RegionI *>(r);
+ delete ri; // todo: validate pointer before deleting
+ clonecount--;
+}
+
+// returns a handle that SetWindowRgn understands (non portable). We should NOT delete this handle, windows will delete
+// it by itself upon setting a new region of destroying the window
+OSREGIONHANDLE RegionI::makeWindowRegion()
+{
+ deoptimize();
+ OSREGIONHANDLE R = CreateRectRgn(0, 0, 0, 0);
+ CombineRgn(R, hrgn, hrgn, RGN_COPY);
+ optimize();
+ return R;
+}
+
+RegionI::RegionI(SkinBitmap *bitmap, RECT *r, int xoffset, int yoffset, bool inverted, int dothreshold, char threshold, int thinverse, int minalpha)
+{
+ init();
+ const wchar_t *id = bitmap->getBitmapName();
+
+ if (xoffset == 0 && yoffset == 0 && r == NULL && !inverted && !dothreshold && minalpha == 1 && id != NULL && *id != 0)
+ {
+ srv = WASABI_API_IMGLDR->imgldr_requestSkinRegion(id);
+ if (srv != NULL)
+ {
+ srv->addRef(this);
+ hrgn = srv->getRegion()->getOSHandle();
+ }
+ }
+
+ if (srv == NULL)
+ {
+ if (r)
+ hrgn = alphaToRegionRect(bitmap, xoffset, yoffset, TRUE, r->left, r->top, r->right - r->left, r->bottom - r->top, inverted, dothreshold, threshold, thinverse, minalpha);
+ else
+ hrgn = alphaToRegionRect(bitmap, xoffset, yoffset, FALSE, 0, 0, 0, 0, inverted, dothreshold, threshold, thinverse, minalpha);
+
+ if (id != NULL && *id != 0)
+ {
+ if (xoffset == 0 && yoffset == 0 && r == NULL && !inverted && !dothreshold && minalpha == 1)
+ {
+ WASABI_API_IMGLDR->imgldr_cacheSkinRegion(id, this);
+ srv = WASABI_API_IMGLDR->imgldr_requestSkinRegion(id);
+ if (srv != NULL)
+ {
+ srv->addRef(this);
+ DeleteObject(hrgn);
+ hrgn = srv->getRegion()->getOSHandle();
+ }
+ }
+ }
+ }
+ optimize();
+
+}
+
+OSREGIONHANDLE RegionI::alphaToRegionRect(SkinBitmap *bitmap, int xoffset, int yoffset, bool portion, int _x, int _y, int _w, int _h, bool inverted, int dothreshold, unsigned char threshold, int thinverse, int minalpha)
+{
+ return alphaToRegionRect(bitmap->getBits(), bitmap->getX(), bitmap->getY(), bitmap->getWidth(), bitmap->getHeight(), bitmap->getFullWidth(), bitmap->getFullHeight(), xoffset, yoffset, portion, _x, _y, _w, _h, inverted, dothreshold, threshold, thinverse, minalpha);
+}
+
+OSREGIONHANDLE RegionI::alphaToRegionRect(void *pbits32, int bmX, int bmY, int bmWidth, int bmHeight, int fullw, int fullh, int xoffset, int yoffset, bool portion, int _x, int _y, int _w, int _h, bool inverted, int dothreshold, unsigned char threshold, int thinverse, int minalpha)
+{
+ OSREGIONHANDLE hRgn = NULL;
+ if (!pbits32) return NULL;
+
+ RGNDATA *pData;
+ int y, x;
+
+ // For better performances, we will use the ExtCreateRegion() function to create the
+ // region. This function take a RGNDATA structure on entry. We will add rectangles by
+ // amount of ALLOC_UNIT number in this structure.
+ // JF> rects are 8 bytes, so this allocates just under 16kb of memory, no need to REALLOC
+#define MAXRECTS 2000
+ __int8 regionMemory[sizeof(RGNDATAHEADER) + (sizeof(RECT) * MAXRECTS)] = {0};
+ //pData = (RGNDATA *)MALLOC(sizeof(RGNDATAHEADER) + (sizeof(RECT) * MAXRECTS));
+ pData = (RGNDATA *)regionMemory;
+ //if (!pData) return NULL;
+
+ pData->rdh.dwSize = sizeof(RGNDATAHEADER);
+ pData->rdh.iType = RDH_RECTANGLES;
+ pData->rdh.nCount = pData->rdh.nRgnSize = 0;
+
+ SetRect(&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0);
+
+ int x_end = (portion ? _w + _x : bmWidth);
+ int y_end = (portion ? _h + _y : bmHeight);
+ int x_start = (portion ? _x : 0);
+ int y_start = (portion ? _y : 0);
+
+ x_start += bmX;
+ x_end += bmX;
+ y_start += bmY;
+ y_end += bmY;
+
+ unsigned int iv = minalpha << 24; //inverted?0xff000000:0;
+
+ int shiftx = xoffset - bmX;
+ int shifty = yoffset - bmY;
+
+ for (y = y_start; y < y_end; y++)
+ {
+ // Scan each bitmap pixel from left to right
+ unsigned int *lineptr = ((unsigned int *)pbits32) + fullw * y;
+ for (x = x_start; x < x_end; x++)
+ {
+ // Search for a continuous range of "non transparent pixels"
+ int x0 = x;
+ unsigned int *p = lineptr;
+ if (dothreshold)
+ {
+ if (inverted)
+ {
+ if (thinverse)
+ {
+ while (x < x_end)
+ {
+ unsigned int a = p[x];
+ if ((a&0xff000000) >= iv ||
+ (((((a & 0xFF) > threshold || ((a & 0xFF00) >> 8) > threshold || ((a & 0xFF0000) >> 16) > threshold)))))
+ break;
+ x++;
+ }
+ }
+ else
+ {
+ while (x < x_end)
+ {
+ unsigned int a = p[x];
+ if ((a&0xff000000) >= iv ||
+ (((((a & 0xFF) < threshold || ((a & 0xFF00) >> 8) < threshold || ((a & 0xFF0000) >> 16) < threshold)))))
+ break;
+ x++;
+ }
+ }
+ }
+ else
+ {
+ if (thinverse)
+ {
+ while (x < x_end)
+ {
+ unsigned int a = p[x];
+ if ((a&0xff000000) < iv ||
+ (((((a & 0xFF) > threshold || ((a & 0xFF00) >> 8) > threshold || ((a & 0xFF0000) >> 16) > threshold)))))
+ break;
+ x++;
+ }
+ }
+ else
+ {
+ while (x < x_end)
+ {
+ unsigned int a = p[x];
+ if ((a&0xff000000) < iv ||
+ (((((a & 0xFF) < threshold || ((a & 0xFF00) >> 8) < threshold || ((a & 0xFF0000) >> 16) < threshold)))))
+ break;
+ x++;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (inverted)
+ {
+ while (x < x_end)
+ {
+ if ((p[x] & 0xFF000000) >= iv) break;
+ x++;
+ }
+ }
+ else
+ {
+ while (x < x_end)
+ {
+ if ((p[x] & 0xFF000000) < iv) break;
+ x++;
+ }
+ }
+ }
+
+ if (x > x0)
+ {
+ SetRect(((RECT *)&pData->Buffer) + pData->rdh.nCount, x0 + shiftx, y + shifty, x + shiftx, y + 1 + shifty);
+
+ pData->rdh.nCount++;
+
+ if (x0 + shiftx < pData->rdh.rcBound.left) pData->rdh.rcBound.left = x0 + shiftx;
+ if (y + shifty < pData->rdh.rcBound.top) pData->rdh.rcBound.top = y + shifty;
+ if (x + shiftx > pData->rdh.rcBound.right) pData->rdh.rcBound.right = x + shiftx;
+ if (y + 1 + shifty > pData->rdh.rcBound.bottom) pData->rdh.rcBound.bottom = y + 1 + shifty;
+
+ // On Windows98, ExtCreateRegion() may fail if the number of rectangles is too
+ // large (ie: > 4000). Therefore, we have to create the region by multiple steps.
+ if (pData->rdh.nCount == MAXRECTS)
+ {
+ OSREGIONHANDLE h = ExtCreateRegion(NULL, sizeof(RGNDATAHEADER) + (sizeof(RECT) * pData->rdh.nCount), pData);
+ if (hRgn)
+ {
+ CombineRgn(hRgn, hRgn, h, RGN_OR);
+ DeleteObject(h);
+ }
+ else hRgn = h;
+ pData->rdh.nCount = 0;
+ SetRect(&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0);
+ }
+ }
+ }
+ }
+
+ // Create or extend the region with the remaining rectangles
+ OSREGIONHANDLE h = ExtCreateRegion(NULL, sizeof(RGNDATAHEADER) + (sizeof(RECT) * pData->rdh.nCount), pData);
+ if (hRgn)
+ {
+ CombineRgn(hRgn, hRgn, h, RGN_OR);
+ DeleteObject(h);
+ }
+ else
+ hRgn = h;
+
+ // Clean up
+ //FREE(pData);
+
+ return hRgn;
+}
+
+bool RegionI::ptInRegion(const POINT *pt)
+{
+ if (optimized) return !!PtInRect(&optrect, *pt);
+ CHECK_REGION
+ return !!PtInRegion(hrgn, pt->x, pt->y);
+}
+
+void RegionI::offset(int x, int y)
+{
+ if (optimized)
+ {
+ optrect.left += x;
+ optrect.top += y;
+ optrect.right += x;
+ optrect.bottom += y;
+ return ;
+ }
+ CHECK_REGION
+ if (srv)
+ {
+ hrgn = CreateRectRgn(0, 0, 0, 0);
+ RegionServer *s = srv;
+ srv = NULL;
+ addRegion(s->getRegion());
+ s->delRef(this);
+ }
+ if (x == 0 && y == 0) return ;
+ deoptimize(); // because addregion may have optimized it
+ OffsetRgn(hrgn, x, y);
+ optimize();
+}
+
+void RegionI::getBox(RECT *r)
+{
+ if (optimized)
+ {
+ *r = optrect;
+ return ;
+ }
+ CHECK_REGION
+ GetRgnBox(hrgn, r);
+}
+
+OSREGIONHANDLE RegionI::getOSHandle()
+{
+ deoptimize();
+ CHECK_REGION
+ return hrgn;
+}
+
+void RegionI::subtractRect(const RECT *r)
+{
+ RegionI s(r);
+ subtractRegion(&s);
+}
+
+void RegionI::subtractRegion(const api_region *reg)
+{
+ if (srv)
+ {
+ hrgn = CreateRectRgn(0, 0, 0, 0);
+ RegionServer *s = srv;
+ srv = NULL;
+ addRegion(s->getRegion());
+ s->delRef(this);
+ }
+ deoptimize();
+ CombineRgn(hrgn, hrgn, GETOSHANDLE(reg), RGN_DIFF);
+ optimize();
+}
+
+void RegionI::andRegion(const api_region *reg)
+{
+ if (srv)
+ {
+ hrgn = CreateRectRgn(0, 0, 0, 0);
+ RegionServer *s = srv;
+ srv = NULL;
+ addRegion(s->getRegion());
+ s->delRef(this);
+ }
+
+ deoptimize();
+ CombineRgn(hrgn, hrgn, GETOSHANDLE(reg), RGN_AND);
+ optimize();
+}
+
+void RegionI::addRect(const RECT *r)
+{
+ RegionI a(r);
+ addRegion(&a);
+}
+
+void RegionI::addRegion(const api_region *reg)
+{
+ if (srv)
+ {
+ hrgn = CreateRectRgn(0, 0, 0, 0);
+ RegionServer *s = srv;
+ srv = NULL;
+ addRegion(s->getRegion());
+ s->delRef(this);
+ }
+ deoptimize();
+ ASSERT(reg != NULL);
+ CombineRgn(hrgn, hrgn, GETOSHANDLE(reg), RGN_OR);
+ optimize();
+}
+
+int RegionI::isEmpty()
+{
+ RECT r;
+ getBox(&r);
+ if (r.left == r.right || r.bottom == r.top) return 1;
+ return 0;
+}
+
+int RegionI::enclosed(const api_region *r, api_region *outside)
+{
+ deoptimize();
+ OSREGIONHANDLE del = NULL;
+ if (!outside)
+ del = CreateRectRgn(0, 0, 0, 0);
+ int rs = CombineRgn(outside ? outside->getOSHandle() : del, hrgn, GETOSHANDLE(r), RGN_DIFF);
+ if (del != NULL) DeleteObject(del);
+ optimize();
+ return rs == NULLREGION;
+}
+
+#define IntersectRgn(hrgnResult, hrgnA, hrgnB) CombineRgn(hrgnResult, hrgnA, hrgnB, RGN_AND)
+
+int RegionI::intersectRgn(const api_region *r, api_region *intersection)
+{
+ ASSERT(intersection != NULL);
+ ASSERT(intersection != this);
+ int rs;
+ if (optimized)
+ {
+ deoptimize();
+ rs = IntersectRgn(intersection->getOSHandle(), hrgn, GETOSHANDLE(r));
+ DeleteObject(hrgn);
+ hrgn=NULL;
+ optimized=1;
+ }
+ else
+ {
+ rs = IntersectRgn(intersection->getOSHandle(), hrgn, GETOSHANDLE(r));
+ }
+
+ return (rs != NULLREGION && rs != ERROR);
+}
+
+int RegionI::doesIntersectRgn(const api_region *r)
+{
+ if (optimized)
+ {
+ return RectInRegion(GETOSHANDLE(r), &optrect);
+ }
+ else
+ {
+ CHECK_REGION
+ HRGN del = CreateRectRgn(0, 0, 0, 0);
+ int rs = IntersectRgn(del, hrgn, GETOSHANDLE(r));
+ DeleteObject(del);
+ return (rs != NULLREGION && rs != ERROR);
+ }
+
+}
+
+int RegionI::intersectRect(const RECT *r, api_region *intersection)
+{
+ int rs;
+ ASSERT(intersection != NULL);
+ ASSERT(intersection != this);
+ if (optimized)
+ {
+ RECT temp = optrect;
+ rs = IntersectRect(&temp, &optrect, r);
+ intersection->setRect(&temp);
+ return rs;
+ }
+ else
+ {
+ CHECK_REGION
+
+ OSREGIONHANDLE iRgn = intersection->getOSHandle();
+ SetRectRgn(iRgn, r->left, r->top, r->right, r->bottom);
+ rs = IntersectRgn(iRgn, hrgn, iRgn);
+ }
+ return (rs != NULLREGION && rs != ERROR);
+}
+
+int RegionI::doesIntersectRect(const RECT *r)
+{
+ return RectInRegion(hrgn, r);
+}
+
+void RegionI::empty()
+{
+ if (srv)
+ {
+ hrgn = CreateRectRgn(0, 0, 0, 0);
+ ASSERT(hrgn != NULL);
+ srv->delRef(this);
+ srv = NULL;
+ optimize();
+ return ;
+ }
+ //deoptimize();
+ if (hrgn != NULL)
+ DeleteObject(hrgn);
+ hrgn=NULL;
+ //hrgn = CreateRectRgn(0, 0, 0, 0);
+ optrect.left=0;
+ optrect.top=0;
+ optrect.right=0;
+ optrect.bottom=0;
+ optimized=1;
+ //ASSERT(hrgn != NULL);
+ //optimize();
+}
+
+void RegionI::setRect(const RECT *r)
+{
+ if (srv)
+ {
+ hrgn = CreateRectRgnIndirect(r);
+ srv->delRef(this);
+ srv = NULL;
+ optimize();
+ return ;
+ }
+ //deoptimize();
+ //CHECK_REGION
+ if (hrgn)
+ DeleteObject(hrgn);
+ hrgn=NULL;
+ //SetRectRgn(hrgn, r->left, r->top, r->right, r->bottom);
+ optrect = *r;
+ optimized = 1;
+ //optimize();
+}
+
+int RegionI::equals(const api_region *r)
+{
+ ASSERT(r);
+ api_region *cl = const_cast<api_region*>(r)->clone();
+ cl->subtractRegion(this);
+ int ret = cl->isEmpty();
+ const_cast<api_region*>(r)->disposeClone(cl);
+ cl = clone();
+ cl->subtractRegion(r);
+ ret &= cl->isEmpty();
+ disposeClone(cl);
+ return ret;
+}
+
+int RegionI::isRect()
+{
+ if (optimized) return 1;
+ RECT r;
+ getBox(&r);
+ RegionI n(&r);
+ return equals(&n);
+}
+
+void RegionI::scale(double sx, double sy, bool round)
+{
+ if (srv)
+ {
+ hrgn = CreateRectRgn(0, 0, 0, 0);
+ RegionServer *s = srv;
+ srv = NULL;
+ addRegion(s->getRegion());
+ s->delRef(this);
+ }
+ deoptimize();
+ CHECK_REGION
+ DWORD size = 0;
+ RECT box;
+ getBox(&box);
+ size = GetRegionData(hrgn, size, NULL);
+ if (!size) return ;
+ RGNDATA *data = (RGNDATA *)MALLOC(size);
+ RECT *r = (RECT *)data->Buffer;
+
+ GetRegionData(hrgn, size, (RGNDATA *)data);
+ double adj = round ? 0.99999 : 0.0;
+ int iadj = round ? 1 : 0;
+
+ if (data->rdh.nCount == 1)
+ {
+ RECT nr = box;
+ nr.left = (int)((double)nr.left * sx - iadj);
+ nr.top = (int)((double)nr.top * sy - iadj);
+ nr.right = (int)((double)nr.right * sx + adj);
+ nr.bottom = (int)((double)nr.bottom * sy + adj);
+ setRect(&nr);
+ FREE(data);
+ return ;
+ }
+
+ for (int i = 0;i < (int)data->rdh.nCount;i++)
+ {
+ r[i].left = (int)((double)r[i].left * sx - iadj);
+ r[i].top = (int)((double)r[i].top * sy - iadj);
+ r[i].right = (int)((double)r[i].right * sx + adj);
+ r[i].bottom = (int)((double)r[i].bottom * sy + adj);
+ }
+
+ OSREGIONHANDLE nhrgn = ExtCreateRegion(NULL, size, data);
+ if (!nhrgn)
+ {
+ nhrgn = CreateRectRgn(0, 0, 0, 0);
+ }
+ FREE(data);
+ DeleteObject(hrgn);
+ hrgn = nhrgn;
+ optimize();
+}
+
+void RegionI::debug(int async)
+{
+ if (!async)
+ {
+ SysCanvas c;
+ RECT r;
+ getBox(&r);
+ // c.fillRect(&r, 0);
+ InvertRgn(c.getHDC(), getOSHandle());
+ Sleep(200);
+ InvertRgn(c.getHDC(), getOSHandle());
+ }
+ else
+ {
+ SysCanvas c;
+ RECT r;
+ getBox(&r);
+ // c.fillRect(&r, 0);
+ if (lastdebug)
+ InvertRgn(c.getHDC(), lastdebug->getOSHandle());
+ delete lastdebug;
+ lastdebug = new RegionI();
+ lastdebug->addRegion(this);
+ InvertRgn(c.getHDC(), getOSHandle());
+ }
+}
+
+// later we can cache this data or something if needed
+int RegionI::getNumRects()
+{
+ if (optimized) return 1;
+ int bytes_needed = GetRegionData(hrgn, 0, NULL) + sizeof(RGNDATA);
+ MemBlock<unsigned char> data(bytes_needed);
+ GetRegionData(hrgn, bytes_needed, (LPRGNDATA)data.getMemory());
+ RGNDATA *rgndata = reinterpret_cast<RGNDATA *>(data.getMemory());
+ return rgndata->rdh.nCount;
+}
+
+int RegionI::enumRect(int n, RECT *r)
+{
+ if (optimized)
+ {
+ if (n == 0)
+ {
+ if (r != NULL) *r = optrect;
+ return 1;
+ }
+ return 0;
+ }
+ if (n < 0) return 0;
+ int bytes_needed = GetRegionData(hrgn, 0, NULL) + sizeof(RGNDATA);
+ MemBlock<unsigned char> data(bytes_needed);
+ GetRegionData(hrgn, bytes_needed, (LPRGNDATA)data.getMemory());
+ RGNDATA *rgndata = reinterpret_cast<RGNDATA *>(data.getMemory());
+ int nrects = rgndata->rdh.nCount;
+ if (n >= nrects) return 0;
+ RECT *rectlist = reinterpret_cast<RECT*>(rgndata->Buffer);
+ *r = rectlist[n];
+ return 1;
+}
+
+void RegionI::optimize()
+{
+ if (optimized) return ;
+ if (srv != NULL) return ; // region is cached and shared, do not optimize
+ CHECK_REGION
+ getBox(&optrect);
+
+ if (IsRectEmpty(&optrect))
+ return;
+
+ RECT br;
+ OSREGIONHANDLE gr = CreateRectRgnIndirect(&optrect);
+ OSREGIONHANDLE res = CreateRectRgn(0, 0, 0, 0);
+
+/*
+ // if they don't intersect, we may be offset
+ IntersectRgn(res, gr, hrgn);
+ GetRgnBox(res, &br);
+ if (br.left == br.right || br.bottom == br.top)
+ {
+ DeleteObject(gr);
+ DeleteObject(res);
+ return ;
+ }
+ */
+
+ // if they intersect, but when subtracting the region from the rect, we get nothing, they're the same, let's optimize
+ CombineRgn(res, gr, hrgn, RGN_DIFF);
+ DeleteObject(gr);
+ GetRgnBox(res, &br);
+ DeleteObject(res);
+ if (br.left == br.right || br.bottom == br.top)
+ {
+ optimized = 1;
+ DeleteObject(hrgn);
+ hrgn = NULL;
+ }
+}
+
+void RegionI::deoptimize()
+{
+ if (!optimized) return ;
+ CHECK_REGION
+ SetRectRgn(hrgn, optrect.left, optrect.top, optrect.right, optrect.bottom);
+ //if (hrgn != NULL) { DeleteObject(hrgn); hrgn = NULL; }
+ //hrgn = CreateRectRgnIndirect(&optrect);
+ //CHECK_REGION
+ optimized = 0;
+}
+
+
+#define CBCLASS RegionServerI
+START_DISPATCH;
+VCB(REGIONSERVER_ADDREF, addRef);
+VCB(REGIONSERVER_DELREF, delRef);
+CB(REGIONSERVER_GETREGION, getRegion);
+END_DISPATCH;
+
+#endif//WIN32
diff --git a/Src/tataki/resource.h b/Src/tataki/resource.h
new file mode 100644
index 00000000..b6ce275a
--- /dev/null
+++ b/Src/tataki/resource.h
@@ -0,0 +1,14 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by tataki.rc
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 101
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1001
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/Src/tataki/tataki.rc b/Src/tataki/tataki.rc
new file mode 100644
index 00000000..fcff7711
--- /dev/null
+++ b/Src/tataki/tataki.rc
@@ -0,0 +1,76 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.K.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "#include ""version.rc2""\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+#endif // English (U.K.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+#include "version.rc2"
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/Src/tataki/tataki.sln b/Src/tataki/tataki.sln
new file mode 100644
index 00000000..62e79c42
--- /dev/null
+++ b/Src/tataki/tataki.sln
@@ -0,0 +1,54 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.29424.173
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tataki", "tataki.vcxproj", "{255B68B5-7EF8-45EF-A675-2D6B88147909}"
+ ProjectSection(ProjectDependencies) = postProject
+ {DABE6307-F8DD-416D-9DAC-673E2DECB73F} = {DABE6307-F8DD-416D-9DAC-673E2DECB73F}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bfc", "..\Wasabi\bfc\bfc.vcxproj", "{D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nsutil", "..\nsutil\nsutil.vcxproj", "{DABE6307-F8DD-416D-9DAC-673E2DECB73F}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Debug|x64 = Debug|x64
+ Release|Win32 = Release|Win32
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {255B68B5-7EF8-45EF-A675-2D6B88147909}.Debug|Win32.ActiveCfg = Debug|Win32
+ {255B68B5-7EF8-45EF-A675-2D6B88147909}.Debug|Win32.Build.0 = Debug|Win32
+ {255B68B5-7EF8-45EF-A675-2D6B88147909}.Debug|x64.ActiveCfg = Debug|x64
+ {255B68B5-7EF8-45EF-A675-2D6B88147909}.Debug|x64.Build.0 = Debug|x64
+ {255B68B5-7EF8-45EF-A675-2D6B88147909}.Release|Win32.ActiveCfg = Release|Win32
+ {255B68B5-7EF8-45EF-A675-2D6B88147909}.Release|Win32.Build.0 = Release|Win32
+ {255B68B5-7EF8-45EF-A675-2D6B88147909}.Release|x64.ActiveCfg = Release|x64
+ {255B68B5-7EF8-45EF-A675-2D6B88147909}.Release|x64.Build.0 = Release|x64
+ {D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Debug|Win32.ActiveCfg = Debug|Win32
+ {D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Debug|Win32.Build.0 = Debug|Win32
+ {D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Debug|x64.ActiveCfg = Debug|x64
+ {D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Debug|x64.Build.0 = Debug|x64
+ {D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Release|Win32.ActiveCfg = Release|Win32
+ {D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Release|Win32.Build.0 = Release|Win32
+ {D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Release|x64.ActiveCfg = Release|x64
+ {D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Release|x64.Build.0 = Release|x64
+ {DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Debug|Win32.ActiveCfg = Debug|Win32
+ {DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Debug|Win32.Build.0 = Debug|Win32
+ {DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Debug|x64.ActiveCfg = Debug|x64
+ {DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Debug|x64.Build.0 = Debug|x64
+ {DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Release|Win32.ActiveCfg = Release|Win32
+ {DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Release|Win32.Build.0 = Release|Win32
+ {DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Release|x64.ActiveCfg = Release|x64
+ {DABE6307-F8DD-416D-9DAC-673E2DECB73F}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {FC646532-2050-40A5-A2AB-F699F1C071C4}
+ EndGlobalSection
+EndGlobal
diff --git a/Src/tataki/tataki.vcxproj b/Src/tataki/tataki.vcxproj
new file mode 100644
index 00000000..64cacbb4
--- /dev/null
+++ b/Src/tataki/tataki.vcxproj
@@ -0,0 +1,311 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{255B68B5-7EF8-45EF-A675-2D6B88147909}</ProjectGuid>
+ <RootNamespace>tataki</RootNamespace>
+ <WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <PlatformToolset>v142</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <PlatformToolset>v142</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <PlatformToolset>v142</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <PlatformToolset>v142</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
+ <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
+ <IncludePath>$(IncludePath)</IncludePath>
+ <LibraryPath>$(LibraryPath)</LibraryPath>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
+ <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
+ <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
+ <IncludePath>$(IncludePath)</IncludePath>
+ <LibraryPath>$(LibraryPath)</LibraryPath>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
+ <IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
+ </PropertyGroup>
+ <PropertyGroup Label="Vcpkg">
+ <VcpkgEnableManifest>false</VcpkgEnableManifest>
+ </PropertyGroup>
+ <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <VcpkgInstalledDir>
+ </VcpkgInstalledDir>
+ <VcpkgUseStatic>false</VcpkgUseStatic>
+ <VcpkgConfiguration>Debug</VcpkgConfiguration>
+ <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
+ </PropertyGroup>
+ <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <VcpkgInstalledDir>
+ </VcpkgInstalledDir>
+ <VcpkgUseStatic>false</VcpkgUseStatic>
+ <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
+ </PropertyGroup>
+ <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <VcpkgInstalledDir>
+ </VcpkgInstalledDir>
+ <VcpkgUseStatic>false</VcpkgUseStatic>
+ <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
+ <VcpkgConfiguration>Debug</VcpkgConfiguration>
+ </PropertyGroup>
+ <PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <VcpkgInstalledDir>
+ </VcpkgInstalledDir>
+ <VcpkgUseStatic>false</VcpkgUseStatic>
+ <VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>../Wasabi;..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;TATAKI_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>false</MinimalRebuild>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <BufferSecurityCheck>true</BufferSecurityCheck>
+ <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+ <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <DelayLoadDLLs>nsutil.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
+ <SubSystem>Windows</SubSystem>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <ImportLibrary>$(ProjectDir)x86_Debug\$(ProjectName).lib</ImportLibrary>
+ <TargetMachine>MachineX86</TargetMachine>
+ <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ </Link>
+ <PostBuildEvent>
+ <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Shared\
+xcopy /Y /D $(IntDir)$(TargetName).pdb ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Shared\ </Command>
+ <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Shared\'</Message>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <Optimization>Disabled</Optimization>
+ <AdditionalIncludeDirectories>../Wasabi;..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN64;_DEBUG;_WINDOWS;_USRDLL;TATAKI_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <MinimalRebuild>false</MinimalRebuild>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
+ <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
+ <BufferSecurityCheck>true</BufferSecurityCheck>
+ <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
+ <ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
+ <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <DelayLoadDLLs>nsutil.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
+ <SubSystem>Windows</SubSystem>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <ImportLibrary>$(ProjectDir)x64_Debug\$(ProjectName).lib</ImportLibrary>
+ <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ </Link>
+ <PostBuildEvent>
+ <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Shared\
+xcopy /Y /D $(IntDir)$(TargetName).pdb ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Shared\ </Command>
+ <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Shared\'</Message>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <Optimization>Full</Optimization>
+ <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
+ <AdditionalIncludeDirectories>../Wasabi;..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;TATAKI_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>true</StringPooling>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+ <BufferSecurityCheck>false</BufferSecurityCheck>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>None</DebugInformationFormat>
+ <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <DelayLoadDLLs>nsutil.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
+ <GenerateDebugInformation>false</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
+ <SubSystem>Windows</SubSystem>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <ImportLibrary>$(ProjectDir)x86_Release\$(ProjectName).lib</ImportLibrary>
+ <TargetMachine>MachineX86</TargetMachine>
+ <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ </Link>
+ <PostBuildEvent>
+ <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Shared\ </Command>
+ <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Shared\'</Message>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <Optimization>Full</Optimization>
+ <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed>
+ <AdditionalIncludeDirectories>../Wasabi;..;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <PreprocessorDefinitions>WIN64;NDEBUG;_WINDOWS;_USRDLL;TATAKI_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <StringPooling>true</StringPooling>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
+ <BufferSecurityCheck>false</BufferSecurityCheck>
+ <WarningLevel>Level3</WarningLevel>
+ <DebugInformationFormat>None</DebugInformationFormat>
+ <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
+ <DelayLoadDLLs>nsutil.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
+ <GenerateDebugInformation>false</GenerateDebugInformation>
+ <ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
+ <SubSystem>Windows</SubSystem>
+ <OptimizeReferences>true</OptimizeReferences>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <RandomizedBaseAddress>false</RandomizedBaseAddress>
+ <ImportLibrary>$(ProjectDir)x64_Release\$(ProjectName).lib</ImportLibrary>
+ <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
+ <AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+ </Link>
+ <PostBuildEvent>
+ <Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Shared\ </Command>
+ <Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Shared\'</Message>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\nsutil\nsutil.vcxproj">
+ <Project>{dabe6307-f8dd-416d-9dac-673e2decb73f}</Project>
+ </ProjectReference>
+ <ProjectReference Include="..\Wasabi\bfc\bfc.vcxproj">
+ <Project>{d0ec862e-dddd-4f4f-934f-b75dc9062dc1}</Project>
+ <CopyLocalSatelliteAssemblies>true</CopyLocalSatelliteAssemblies>
+ <ReferenceOutputAssembly>true</ReferenceOutputAssembly>
+ </ProjectReference>
+ <ProjectReference Include="..\Wasabi\Wasabi.vcxproj">
+ <Project>{3e0bfa8a-b86a-42e9-a33f-ec294f823f7f}</Project>
+ </ProjectReference>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\nu\ServiceWatcher.h" />
+ <ClInclude Include="api__tataki.h" />
+ <ClInclude Include="bitmap\autobitmap.h" />
+ <ClInclude Include="bitmap\bitmap.h" />
+ <ClInclude Include="bitmap\ifc_bitmap.h" />
+ <ClInclude Include="bitmap\win\bitmap.h" />
+ <ClInclude Include="blending\blending.h" />
+ <ClInclude Include="canvas\bltcanvas.h" />
+ <ClInclude Include="canvas\canvas.h" />
+ <ClInclude Include="canvas\ifc_canvas.h" />
+ <ClInclude Include="canvas\PaintCanvas.h" />
+ <ClInclude Include="canvas\win\bltcanvas.h" />
+ <ClInclude Include="canvas\win\canvas.h" />
+ <ClInclude Include="color\filteredcolor.h" />
+ <ClInclude Include="color\skinclr.h" />
+ <ClInclude Include="export.h" />
+ <ClInclude Include="region\api_region.h" />
+ <ClInclude Include="region\region.h" />
+ <ClInclude Include="region\win\region.h" />
+ <ClInclude Include="resource.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="..\nu\ServiceWatcher.cpp" />
+ <ClCompile Include="bitmap\autobitmap.cpp" />
+ <ClCompile Include="bitmap\win\bitmap.cpp" />
+ <ClCompile Include="blending\blending.cpp" />
+ <ClCompile Include="canvas\ifc_canvas.cpp" />
+ <ClCompile Include="canvas\win\BltCanvas.cpp" />
+ <ClCompile Include="canvas\win\win32_canvas.cpp" />
+ <ClCompile Include="color\filteredcolor.cpp" />
+ <ClCompile Include="color\skinclr.cpp" />
+ <ClCompile Include="main.cpp" />
+ <ClCompile Include="region\api_region.cpp" />
+ <ClCompile Include="region\win\win32_region.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="tataki.rc" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/Src/tataki/tataki.vcxproj.filters b/Src/tataki/tataki.vcxproj.filters
new file mode 100644
index 00000000..48d67814
--- /dev/null
+++ b/Src/tataki/tataki.vcxproj.filters
@@ -0,0 +1,119 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <ClCompile Include="region\win\win32_region.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="canvas\win\win32_canvas.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="color\skinclr.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\nu\ServiceWatcher.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="main.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="canvas\ifc_canvas.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="color\filteredcolor.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="canvas\win\BltCanvas.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="blending\blending.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="bitmap\win\bitmap.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="bitmap\autobitmap.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="region\api_region.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="api__tataki.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="region\api_region.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="bitmap\autobitmap.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="bitmap\win\bitmap.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="bitmap\bitmap.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="blending\blending.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="canvas\win\bltcanvas.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="canvas\bltcanvas.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="canvas\win\canvas.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="canvas\canvas.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="export.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="color\filteredcolor.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="bitmap\ifc_bitmap.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="canvas\ifc_canvas.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="canvas\PaintCanvas.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="region\win\region.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="region\region.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="resource.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\nu\ServiceWatcher.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="color\skinclr.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{f568eac1-1c90-440e-a7e4-961418304927}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Ressource Files">
+ <UniqueIdentifier>{63948b0b-d98d-4579-bec2-570c5f1ac16d}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{e20af976-f354-4573-aa81-c23800d14d51}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="tataki.rc">
+ <Filter>Ressource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/Src/tataki/tataki.xcodeproj/project.pbxproj b/Src/tataki/tataki.xcodeproj/project.pbxproj
new file mode 100644
index 00000000..4cd13955
--- /dev/null
+++ b/Src/tataki/tataki.xcodeproj/project.pbxproj
@@ -0,0 +1,418 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 42;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 0C2D18FA0C0BDD0B00ED9158 /* main.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C2D18F50C0BDD0B00ED9158 /* main.cpp */; };
+ 0C2D18FB0C0BDD0B00ED9158 /* export.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C2D18F60C0BDD0B00ED9158 /* export.h */; };
+ 0C2D18FC0C0BDD0B00ED9158 /* api.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C2D18F70C0BDD0B00ED9158 /* api.h */; };
+ 0C2D192C0C0BDE7400ED9158 /* canvas.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C2D19220C0BDE7400ED9158 /* canvas.h */; };
+ 0C2D192D0C0BDE7400ED9158 /* PaintCanvas.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C2D19230C0BDE7400ED9158 /* PaintCanvas.h */; };
+ 0C2D19300C0BDE7400ED9158 /* osx_canvas_layer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C2D19260C0BDE7400ED9158 /* osx_canvas_layer.cpp */; };
+ 0C2D19310C0BDE7400ED9158 /* PaintCanvas.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C2D19270C0BDE7400ED9158 /* PaintCanvas.cpp */; };
+ 0C2D19320C0BDE7400ED9158 /* osx_canvas_quartz.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C2D19280C0BDE7400ED9158 /* osx_canvas_quartz.cpp */; };
+ 0C2D19340C0BDE7400ED9158 /* bltcanvas.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C2D192A0C0BDE7400ED9158 /* bltcanvas.h */; };
+ 0C2D193C0C0BDEB400ED9158 /* api_canvas.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C2D19370C0BDEB400ED9158 /* api_canvas.cpp */; };
+ 0C2D193D0C0BDEB400ED9158 /* canvas.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C2D19380C0BDEB400ED9158 /* canvas.h */; };
+ 0C2D193E0C0BDEB400ED9158 /* PaintCanvas.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C2D19390C0BDEB400ED9158 /* PaintCanvas.h */; };
+ 0C2D193F0C0BDEB400ED9158 /* api_canvas.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C2D193A0C0BDEB400ED9158 /* api_canvas.h */; };
+ 0C2D19400C0BDEB400ED9158 /* bltcanvas.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C2D193B0C0BDEB400ED9158 /* bltcanvas.h */; };
+ 0C2D194B0C0BDEFD00ED9158 /* ifc_bitmap.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C2D19490C0BDEFD00ED9158 /* ifc_bitmap.h */; };
+ 0C2D194C0C0BDEFD00ED9158 /* bitmap.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C2D194A0C0BDEFD00ED9158 /* bitmap.h */; };
+ 0C2D19500C0BDFFF00ED9158 /* osx_bitmap_cgimage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C2D194E0C0BDFFF00ED9158 /* osx_bitmap_cgimage.cpp */; };
+ 0C2D19510C0BDFFF00ED9158 /* osx_bitmap_cgimage.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C2D194F0C0BDFFF00ED9158 /* osx_bitmap_cgimage.h */; };
+ 0C2D19580C0BE06A00ED9158 /* region.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C2D19550C0BE06A00ED9158 /* region.h */; };
+ 0C2D19590C0BE06A00ED9158 /* api_region.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C2D19560C0BE06A00ED9158 /* api_region.h */; };
+ 0C2D195A0C0BE06A00ED9158 /* api_region.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C2D19570C0BE06A00ED9158 /* api_region.cpp */; };
+ 0C2D195F0C0BE08400ED9158 /* osx_region_hishape.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C2D195D0C0BE08400ED9158 /* osx_region_hishape.cpp */; };
+ 0C2D19600C0BE08400ED9158 /* region.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C2D195E0C0BE08400ED9158 /* region.h */; };
+ 0CF66DD30CD5070800FF5DAF /* ServiceWatcher.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0CF66DD10CD5070800FF5DAF /* ServiceWatcher.cpp */; };
+ 0CF66DD40CD5070800FF5DAF /* ServiceWatcher.h in Headers */ = {isa = PBXBuildFile; fileRef = 0CF66DD20CD5070800FF5DAF /* ServiceWatcher.h */; };
+ 0CF66DE20CD507D000FF5DAF /* Vector.h in Headers */ = {isa = PBXBuildFile; fileRef = 0CF66DE10CD507D000FF5DAF /* Vector.h */; };
+ 0CF66E990CD50E6C00FF5DAF /* libbfc.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 0CF66E980CD50E6C00FF5DAF /* libbfc.a */; };
+ 0CF66F5B0CD50E9800FF5DAF /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0CF66F5A0CD50E9800FF5DAF /* Carbon.framework */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+ 0C2D19740C0BE0EA00ED9158 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 0C2D19670C0BE0EA00ED9158 /* bfc.xcodeproj */;
+ proxyType = 2;
+ remoteGlobalIDString = D2AAC06F0554671400DB518D;
+ remoteInfo = bfc;
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXFileReference section */
+ 0C2D18F50C0BDD0B00ED9158 /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = "<group>"; };
+ 0C2D18F60C0BDD0B00ED9158 /* export.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = export.h; sourceTree = "<group>"; };
+ 0C2D18F70C0BDD0B00ED9158 /* api.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = api.h; sourceTree = "<group>"; };
+ 0C2D19220C0BDE7400ED9158 /* canvas.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = canvas.h; path = canvas/mac/canvas.h; sourceTree = "<group>"; };
+ 0C2D19230C0BDE7400ED9158 /* PaintCanvas.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = PaintCanvas.h; path = canvas/mac/PaintCanvas.h; sourceTree = "<group>"; };
+ 0C2D19260C0BDE7400ED9158 /* osx_canvas_layer.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = osx_canvas_layer.cpp; path = canvas/mac/osx_canvas_layer.cpp; sourceTree = "<group>"; };
+ 0C2D19270C0BDE7400ED9158 /* PaintCanvas.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = PaintCanvas.cpp; path = canvas/mac/PaintCanvas.cpp; sourceTree = "<group>"; };
+ 0C2D19280C0BDE7400ED9158 /* osx_canvas_quartz.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = osx_canvas_quartz.cpp; path = canvas/mac/osx_canvas_quartz.cpp; sourceTree = "<group>"; };
+ 0C2D192A0C0BDE7400ED9158 /* bltcanvas.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = bltcanvas.h; path = canvas/mac/bltcanvas.h; sourceTree = "<group>"; };
+ 0C2D19370C0BDEB400ED9158 /* api_canvas.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = api_canvas.cpp; path = canvas/api_canvas.cpp; sourceTree = "<group>"; };
+ 0C2D19380C0BDEB400ED9158 /* canvas.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = canvas.h; path = canvas/canvas.h; sourceTree = "<group>"; };
+ 0C2D19390C0BDEB400ED9158 /* PaintCanvas.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = PaintCanvas.h; path = canvas/PaintCanvas.h; sourceTree = "<group>"; };
+ 0C2D193A0C0BDEB400ED9158 /* api_canvas.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = api_canvas.h; path = canvas/api_canvas.h; sourceTree = "<group>"; };
+ 0C2D193B0C0BDEB400ED9158 /* bltcanvas.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = bltcanvas.h; path = canvas/bltcanvas.h; sourceTree = "<group>"; };
+ 0C2D19490C0BDEFD00ED9158 /* ifc_bitmap.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = ifc_bitmap.h; path = bitmap/ifc_bitmap.h; sourceTree = "<group>"; };
+ 0C2D194A0C0BDEFD00ED9158 /* bitmap.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = bitmap.h; path = bitmap/bitmap.h; sourceTree = "<group>"; };
+ 0C2D194E0C0BDFFF00ED9158 /* osx_bitmap_cgimage.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = osx_bitmap_cgimage.cpp; path = bitmap/mac/osx_bitmap_cgimage.cpp; sourceTree = "<group>"; };
+ 0C2D194F0C0BDFFF00ED9158 /* osx_bitmap_cgimage.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = osx_bitmap_cgimage.h; path = bitmap/mac/osx_bitmap_cgimage.h; sourceTree = "<group>"; };
+ 0C2D19550C0BE06A00ED9158 /* region.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = region.h; path = region/region.h; sourceTree = "<group>"; };
+ 0C2D19560C0BE06A00ED9158 /* api_region.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = api_region.h; path = region/api_region.h; sourceTree = "<group>"; };
+ 0C2D19570C0BE06A00ED9158 /* api_region.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = api_region.cpp; path = region/api_region.cpp; sourceTree = "<group>"; };
+ 0C2D195D0C0BE08400ED9158 /* osx_region_hishape.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = osx_region_hishape.cpp; path = region/mac/osx_region_hishape.cpp; sourceTree = "<group>"; };
+ 0C2D195E0C0BE08400ED9158 /* region.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = region.h; path = region/mac/region.h; sourceTree = "<group>"; };
+ 0C2D19670C0BE0EA00ED9158 /* bfc.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = bfc.xcodeproj; path = ../Wasabi/bfc/bfc.xcodeproj; sourceTree = SOURCE_ROOT; };
+ 0CF66DD10CD5070800FF5DAF /* ServiceWatcher.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ServiceWatcher.cpp; path = ../nu/ServiceWatcher.cpp; sourceTree = SOURCE_ROOT; };
+ 0CF66DD20CD5070800FF5DAF /* ServiceWatcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ServiceWatcher.h; path = ../nu/ServiceWatcher.h; sourceTree = SOURCE_ROOT; };
+ 0CF66DE10CD507D000FF5DAF /* Vector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Vector.h; path = ../nu/Vector.h; sourceTree = SOURCE_ROOT; };
+ 0CF66E980CD50E6C00FF5DAF /* libbfc.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libbfc.a; path = ../Wasabi/bfc/build/Release/libbfc.a; sourceTree = SOURCE_ROOT; };
+ 0CF66F5A0CD50E9800FF5DAF /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = /System/Library/Frameworks/Carbon.framework; sourceTree = "<absolute>"; };
+ D2AAC0630554660B00DB518D /* libtataki.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libtataki.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ D289988505E68E00004EDB86 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 0CF66E990CD50E6C00FF5DAF /* libbfc.a in Frameworks */,
+ 0CF66F5B0CD50E9800FF5DAF /* Carbon.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 08FB7794FE84155DC02AAC07 /* tataki */ = {
+ isa = PBXGroup;
+ children = (
+ 0CF66F5A0CD50E9800FF5DAF /* Carbon.framework */,
+ 08FB7795FE84155DC02AAC07 /* Source */,
+ 1AB674ADFE9D54B511CA2CBB /* Products */,
+ );
+ name = tataki;
+ sourceTree = "<group>";
+ };
+ 08FB7795FE84155DC02AAC07 /* Source */ = {
+ isa = PBXGroup;
+ children = (
+ 0CF66E980CD50E6C00FF5DAF /* libbfc.a */,
+ 0CF66DE00CD5079C00FF5DAF /* nu */,
+ 0C2D19670C0BE0EA00ED9158 /* bfc.xcodeproj */,
+ 0C2D19540C0BE05D00ED9158 /* Region */,
+ 0C2D19480C0BDEEC00ED9158 /* Bitmap */,
+ 0C2D191E0C0BDE3300ED9158 /* Canvas */,
+ 0C2D18F50C0BDD0B00ED9158 /* main.cpp */,
+ 0C2D18F60C0BDD0B00ED9158 /* export.h */,
+ 0C2D18F70C0BDD0B00ED9158 /* api.h */,
+ );
+ name = Source;
+ sourceTree = "<group>";
+ };
+ 0C2D191E0C0BDE3300ED9158 /* Canvas */ = {
+ isa = PBXGroup;
+ children = (
+ 0C2D19370C0BDEB400ED9158 /* api_canvas.cpp */,
+ 0C2D19380C0BDEB400ED9158 /* canvas.h */,
+ 0C2D19390C0BDEB400ED9158 /* PaintCanvas.h */,
+ 0C2D193A0C0BDEB400ED9158 /* api_canvas.h */,
+ 0C2D193B0C0BDEB400ED9158 /* bltcanvas.h */,
+ 0C2D19360C0BDE7700ED9158 /* Mac */,
+ );
+ name = Canvas;
+ sourceTree = "<group>";
+ };
+ 0C2D19360C0BDE7700ED9158 /* Mac */ = {
+ isa = PBXGroup;
+ children = (
+ 0C2D19220C0BDE7400ED9158 /* canvas.h */,
+ 0C2D19230C0BDE7400ED9158 /* PaintCanvas.h */,
+ 0C2D19260C0BDE7400ED9158 /* osx_canvas_layer.cpp */,
+ 0C2D19270C0BDE7400ED9158 /* PaintCanvas.cpp */,
+ 0C2D19280C0BDE7400ED9158 /* osx_canvas_quartz.cpp */,
+ 0C2D192A0C0BDE7400ED9158 /* bltcanvas.h */,
+ );
+ name = Mac;
+ sourceTree = "<group>";
+ };
+ 0C2D19480C0BDEEC00ED9158 /* Bitmap */ = {
+ isa = PBXGroup;
+ children = (
+ 0C2D194D0C0BDFC200ED9158 /* Mac */,
+ 0C2D19490C0BDEFD00ED9158 /* ifc_bitmap.h */,
+ 0C2D194A0C0BDEFD00ED9158 /* bitmap.h */,
+ );
+ name = Bitmap;
+ sourceTree = "<group>";
+ };
+ 0C2D194D0C0BDFC200ED9158 /* Mac */ = {
+ isa = PBXGroup;
+ children = (
+ 0C2D194E0C0BDFFF00ED9158 /* osx_bitmap_cgimage.cpp */,
+ 0C2D194F0C0BDFFF00ED9158 /* osx_bitmap_cgimage.h */,
+ );
+ name = Mac;
+ sourceTree = "<group>";
+ };
+ 0C2D19540C0BE05D00ED9158 /* Region */ = {
+ isa = PBXGroup;
+ children = (
+ 0C2D195C0C0BE07400ED9158 /* Mac */,
+ 0C2D19550C0BE06A00ED9158 /* region.h */,
+ 0C2D19560C0BE06A00ED9158 /* api_region.h */,
+ 0C2D19570C0BE06A00ED9158 /* api_region.cpp */,
+ );
+ name = Region;
+ sourceTree = "<group>";
+ };
+ 0C2D195C0C0BE07400ED9158 /* Mac */ = {
+ isa = PBXGroup;
+ children = (
+ 0C2D195D0C0BE08400ED9158 /* osx_region_hishape.cpp */,
+ 0C2D195E0C0BE08400ED9158 /* region.h */,
+ );
+ name = Mac;
+ sourceTree = "<group>";
+ };
+ 0C2D19680C0BE0EA00ED9158 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 0C2D19750C0BE0EA00ED9158 /* libbfc.a */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 0CF66DE00CD5079C00FF5DAF /* nu */ = {
+ isa = PBXGroup;
+ children = (
+ 0CF66DE10CD507D000FF5DAF /* Vector.h */,
+ 0CF66DD10CD5070800FF5DAF /* ServiceWatcher.cpp */,
+ 0CF66DD20CD5070800FF5DAF /* ServiceWatcher.h */,
+ );
+ name = nu;
+ sourceTree = "<group>";
+ };
+ 1AB674ADFE9D54B511CA2CBB /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ D2AAC0630554660B00DB518D /* libtataki.dylib */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXHeadersBuildPhase section */
+ D2AAC0600554660B00DB518D /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 0C2D18FB0C0BDD0B00ED9158 /* export.h in Headers */,
+ 0C2D18FC0C0BDD0B00ED9158 /* api.h in Headers */,
+ 0C2D192C0C0BDE7400ED9158 /* canvas.h in Headers */,
+ 0C2D192D0C0BDE7400ED9158 /* PaintCanvas.h in Headers */,
+ 0C2D19340C0BDE7400ED9158 /* bltcanvas.h in Headers */,
+ 0C2D193D0C0BDEB400ED9158 /* canvas.h in Headers */,
+ 0C2D193E0C0BDEB400ED9158 /* PaintCanvas.h in Headers */,
+ 0C2D193F0C0BDEB400ED9158 /* api_canvas.h in Headers */,
+ 0C2D19400C0BDEB400ED9158 /* bltcanvas.h in Headers */,
+ 0C2D194B0C0BDEFD00ED9158 /* ifc_bitmap.h in Headers */,
+ 0C2D194C0C0BDEFD00ED9158 /* bitmap.h in Headers */,
+ 0C2D19510C0BDFFF00ED9158 /* osx_bitmap_cgimage.h in Headers */,
+ 0C2D19580C0BE06A00ED9158 /* region.h in Headers */,
+ 0C2D19590C0BE06A00ED9158 /* api_region.h in Headers */,
+ 0C2D19600C0BE08400ED9158 /* region.h in Headers */,
+ 0CF66DD40CD5070800FF5DAF /* ServiceWatcher.h in Headers */,
+ 0CF66DE20CD507D000FF5DAF /* Vector.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXHeadersBuildPhase section */
+
+/* Begin PBXNativeTarget section */
+ D2AAC0620554660B00DB518D /* tataki */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 1DEB914A08733D8E0010E9CD /* Build configuration list for PBXNativeTarget "tataki" */;
+ buildPhases = (
+ D2AAC0600554660B00DB518D /* Headers */,
+ D2AAC0610554660B00DB518D /* Sources */,
+ D289988505E68E00004EDB86 /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = tataki;
+ productName = tataki;
+ productReference = D2AAC0630554660B00DB518D /* libtataki.dylib */;
+ productType = "com.apple.product-type.library.dynamic";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 08FB7793FE84155DC02AAC07 /* Project object */ = {
+ isa = PBXProject;
+ buildConfigurationList = 1DEB914E08733D8E0010E9CD /* Build configuration list for PBXProject "tataki" */;
+ compatibilityVersion = "Xcode 2.4";
+ hasScannedForEncodings = 1;
+ mainGroup = 08FB7794FE84155DC02AAC07 /* tataki */;
+ projectDirPath = "";
+ projectReferences = (
+ {
+ ProductGroup = 0C2D19680C0BE0EA00ED9158 /* Products */;
+ ProjectRef = 0C2D19670C0BE0EA00ED9158 /* bfc.xcodeproj */;
+ },
+ );
+ projectRoot = "";
+ targets = (
+ D2AAC0620554660B00DB518D /* tataki */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXReferenceProxy section */
+ 0C2D19750C0BE0EA00ED9158 /* libbfc.a */ = {
+ isa = PBXReferenceProxy;
+ fileType = archive.ar;
+ path = libbfc.a;
+ remoteRef = 0C2D19740C0BE0EA00ED9158 /* PBXContainerItemProxy */;
+ sourceTree = BUILT_PRODUCTS_DIR;
+ };
+/* End PBXReferenceProxy section */
+
+/* Begin PBXSourcesBuildPhase section */
+ D2AAC0610554660B00DB518D /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 0C2D18FA0C0BDD0B00ED9158 /* main.cpp in Sources */,
+ 0C2D19300C0BDE7400ED9158 /* osx_canvas_layer.cpp in Sources */,
+ 0C2D19310C0BDE7400ED9158 /* PaintCanvas.cpp in Sources */,
+ 0C2D19320C0BDE7400ED9158 /* osx_canvas_quartz.cpp in Sources */,
+ 0C2D193C0C0BDEB400ED9158 /* api_canvas.cpp in Sources */,
+ 0C2D19500C0BDFFF00ED9158 /* osx_bitmap_cgimage.cpp in Sources */,
+ 0C2D195A0C0BE06A00ED9158 /* api_region.cpp in Sources */,
+ 0C2D195F0C0BE08400ED9158 /* osx_region_hishape.cpp in Sources */,
+ 0CF66DD30CD5070800FF5DAF /* ServiceWatcher.cpp in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+ 1DEB914B08733D8E0010E9CD /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = NO;
+ EXECUTABLE_PREFIX = lib;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_ENABLE_FIX_AND_CONTINUE = YES;
+ GCC_MODEL_TUNING = G5;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ INSTALL_PATH = /usr/local/lib;
+ LIBRARY_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(LIBRARY_SEARCH_PATHS_QUOTED_1)",
+ "$(LIBRARY_SEARCH_PATHS_QUOTED_2)",
+ );
+ LIBRARY_SEARCH_PATHS_QUOTED_1 = "\"$(SRCROOT)/../Wasabi/bfc/build/Debug\"";
+ LIBRARY_SEARCH_PATHS_QUOTED_2 = "\"$(SRCROOT)/../Wasabi/bfc/build/Release\"";
+ PRODUCT_NAME = tataki;
+ ZERO_LINK = YES;
+ };
+ name = Debug;
+ };
+ 1DEB914C08733D8E0010E9CD /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = (
+ ppc,
+ i386,
+ );
+ EXECUTABLE_PREFIX = lib;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+ GCC_MODEL_TUNING = G5;
+ GCC_PREPROCESSOR_DEFINITIONS = TATAKI_EXPORTS;
+ INSTALL_PATH = /usr/local/lib;
+ LIBRARY_SEARCH_PATHS = (
+ "$(inherited)",
+ "$(LIBRARY_SEARCH_PATHS_QUOTED_1)",
+ "$(LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_1)",
+ );
+ LIBRARY_SEARCH_PATHS_QUOTED_1 = "\"$(SRCROOT)/../Wasabi/bfc/build/Debug\"";
+ LIBRARY_SEARCH_PATHS_QUOTED_FOR_TARGET_1 = "\"$(SRCROOT)/../Wasabi/bfc/build/Release\"";
+ PRODUCT_NAME = tataki;
+ };
+ name = Release;
+ };
+ 1DEB914F08733D8E0010E9CD /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ GCC_PREPROCESSOR_DEFINITIONS = TATAKI_EXPORTS;
+ GCC_SYMBOLS_PRIVATE_EXTERN = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = (
+ ..,
+ ../Wasabi,
+ );
+ PREBINDING = NO;
+ SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk;
+ };
+ name = Debug;
+ };
+ 1DEB915008733D8E0010E9CD /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ GCC_MODEL_TUNING = "";
+ GCC_PREPROCESSOR_DEFINITIONS = TATAKI_EXPORTS;
+ GCC_SYMBOLS_PRIVATE_EXTERN = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ HEADER_SEARCH_PATHS = (
+ ..,
+ ../Wasabi,
+ );
+ PREBINDING = NO;
+ SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk;
+ STANDARD_C_PLUS_PLUS_LIBRARY_TYPE = dynamic;
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 1DEB914A08733D8E0010E9CD /* Build configuration list for PBXNativeTarget "tataki" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 1DEB914B08733D8E0010E9CD /* Debug */,
+ 1DEB914C08733D8E0010E9CD /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 1DEB914E08733D8E0010E9CD /* Build configuration list for PBXProject "tataki" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 1DEB914F08733D8E0010E9CD /* Debug */,
+ 1DEB915008733D8E0010E9CD /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 08FB7793FE84155DC02AAC07 /* Project object */;
+}
diff --git a/Src/tataki/version.rc2 b/Src/tataki/version.rc2
new file mode 100644
index 00000000..8719eb33
--- /dev/null
+++ b/Src/tataki/version.rc2
@@ -0,0 +1,39 @@
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+#include "../Winamp/buildType.h"
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION WINAMP_PRODUCTVER
+ PRODUCTVERSION WINAMP_PRODUCTVER
+ FILEFLAGSMASK 0x17L
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "CompanyName", "Winamp SA"
+ VALUE "FileDescription", "Winamp Support Library"
+ VALUE "FileVersion", STR_WINAMP_PRODUCTVER
+ VALUE "InternalName", "tataki.dll"
+ VALUE "LegalCopyright", "Copyright © 2005-2023 Winamp SA"
+ VALUE "LegalTrademarks", "Nullsoft and Winamp are trademarks of Winamp SA"
+ VALUE "OriginalFilename", "tataki.dll"
+ VALUE "ProductName", "Winamp Shared Code Library"
+ VALUE "ProductVersion", STR_WINAMP_PRODUCTVER
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END