aboutsummaryrefslogtreecommitdiff
path: root/Src/Wasabi/api/imgldr/imggen
diff options
context:
space:
mode:
Diffstat (limited to 'Src/Wasabi/api/imgldr/imggen')
-rw-r--r--Src/Wasabi/api/imgldr/imggen/grad.cpp60
-rw-r--r--Src/Wasabi/api/imgldr/imggen/grad.h15
-rw-r--r--Src/Wasabi/api/imgldr/imggen/imggen.cpp29
-rw-r--r--Src/Wasabi/api/imgldr/imggen/imggen.h14
-rw-r--r--Src/Wasabi/api/imgldr/imggen/osedge.cpp95
-rw-r--r--Src/Wasabi/api/imgldr/imggen/osedge.h13
-rw-r--r--Src/Wasabi/api/imgldr/imggen/poly.cpp59
-rw-r--r--Src/Wasabi/api/imgldr/imggen/poly.h13
-rw-r--r--Src/Wasabi/api/imgldr/imggen/shadowwnd.cpp152
-rw-r--r--Src/Wasabi/api/imgldr/imggen/shadowwnd.h40
-rw-r--r--Src/Wasabi/api/imgldr/imggen/solid.cpp67
-rw-r--r--Src/Wasabi/api/imgldr/imggen/solid.h14
12 files changed, 571 insertions, 0 deletions
diff --git a/Src/Wasabi/api/imgldr/imggen/grad.cpp b/Src/Wasabi/api/imgldr/imggen/grad.cpp
new file mode 100644
index 00000000..acec2eab
--- /dev/null
+++ b/Src/Wasabi/api/imgldr/imggen/grad.cpp
@@ -0,0 +1,60 @@
+#include "precomp.h"
+
+#include "grad.h"
+
+#include <api/xml/xmlparams.h>
+#include <api/memmgr/api_memmgr.h>
+#ifndef _WASABIRUNTIME
+
+BEGIN_SERVICES(GradientGen_Svc);
+DECLARE_SERVICETSINGLE(svc_imageGenerator, GradientImage);
+END_SERVICES(GradientGen_Svc, _GradientGen_Svc);
+
+#ifdef _X86_
+extern "C" { int _link_GradientGen_Svc; }
+#else
+extern "C" { int __link_GradientGen_Svc; }
+#endif
+
+#endif
+
+
+int GradientImage::testDesc(const wchar_t *desc) {
+ return !_wcsicmp(desc, L"$gradient");
+}
+
+ARGB32 *GradientImage::genImage(const wchar_t *desc, int *has_alpha, int *w, int *h, ifc_xmlreaderparams *params)
+{
+ int _w = params->getItemValueInt(L"w",1);
+ if (_w == 0) _w = 1;
+ int _h = params->getItemValueInt(L"h",1);
+ if (_h == 0) _h = 1;
+ if (_w <= 0 || _h <= 0) return NULL;
+
+#ifdef WASABI_COMPILE_MEMMGR
+ ARGB32 *ret = (ARGB32*)WASABI_API_MEMMGR->sysMalloc(_w * _h * sizeof(ARGB32));
+#else
+ ARGB32 *ret = (ARGB32*)MALLOC(_w * _h * sizeof(ARGB32));
+#endif
+
+ setX1((float)WTOF(params->getItemValue(L"gradient_x1")));
+ setY1((float)WTOF(params->getItemValue(L"gradient_y1")));
+ setX2((float)WTOF(params->getItemValue(L"gradient_x2")));
+ setY2((float)WTOF(params->getItemValue(L"gradient_y2")));
+
+ setPoints(params->getItemValue(L"points"));
+
+ setMode(params->getItemValue(L"mode"));
+
+ setReverseColors(TRUE); // cuz we're imggen
+
+ setAntialias(params->getItemValueInt(L"antialias"));
+
+ renderGradient(ret, _w, _h);
+
+ *w = _w;
+ *h = _h;
+ *has_alpha = 1; // will be optimized anyway
+
+ return ret;
+}
diff --git a/Src/Wasabi/api/imgldr/imggen/grad.h b/Src/Wasabi/api/imgldr/imggen/grad.h
new file mode 100644
index 00000000..8ee4c886
--- /dev/null
+++ b/Src/Wasabi/api/imgldr/imggen/grad.h
@@ -0,0 +1,15 @@
+#ifndef _GRAD_H
+#define _GRAD_H
+
+#include <api/service/svcs/svc_imggen.h>
+#include <bfc/draw/gradient.h>
+
+class GradientImage : public svc_imageGeneratorI, public Gradient
+{
+public:
+ static const char *getServiceName() { return "Gradient image generator"; }
+ virtual int testDesc(const wchar_t *desc);
+ virtual ARGB32 *genImage(const wchar_t *desc, int *has_alpha, int *w, int *h, ifc_xmlreaderparams *params=NULL);
+};
+
+#endif
diff --git a/Src/Wasabi/api/imgldr/imggen/imggen.cpp b/Src/Wasabi/api/imgldr/imggen/imggen.cpp
new file mode 100644
index 00000000..bcf0b6d4
--- /dev/null
+++ b/Src/Wasabi/api/imgldr/imggen/imggen.cpp
@@ -0,0 +1,29 @@
+#include "precomp.h"
+#include "imggen.h"
+
+#include "solid.h"
+#include "grad.h"
+#include "osedge.h"
+#include "poly.h"
+#include "shadowwnd.h"
+
+#include "../studio/services/servicei.h"
+
+static WACNAME wac;
+WAComponentClient *the = &wac;
+
+// {9C9CB15E-2904-4df2-B8CE-FFBC6CD230DC}
+static const GUID guid =
+{ 0x9c9cb15e, 0x2904, 0x4df2, { 0xb8, 0xce, 0xff, 0xbc, 0x6c, 0xd2, 0x30, 0xdc } };
+
+WACNAME::WACNAME() {
+ registerService(new waServiceFactoryTSingle<svc_imageGenerator, SolidImage>);
+ registerService(new waServiceFactoryTSingle<svc_imageGenerator, GradientImage>);
+ registerService(new waServiceFactoryTSingle<svc_imageGenerator, OsEdgeImage>);
+ registerService(new waServiceFactoryTSingle<svc_imageGenerator, PolyImage>);
+ registerService(new XuiObjectCreator<XuiShadowWndSvc>);
+}
+
+GUID WACNAME::getGUID() {
+ return guid;
+}
diff --git a/Src/Wasabi/api/imgldr/imggen/imggen.h b/Src/Wasabi/api/imgldr/imggen/imggen.h
new file mode 100644
index 00000000..9af473d5
--- /dev/null
+++ b/Src/Wasabi/api/imgldr/imggen/imggen.h
@@ -0,0 +1,14 @@
+#ifndef _IMGGEN_H
+#define _IMGGEN_H
+
+#include "../studio/wac.h"
+
+#define WACNAME WACimggen
+class WACNAME : public WAComponentClient {
+public:
+ WACNAME();
+
+ virtual const char *getName() { return "Standard Image Generators"; };
+ virtual GUID getGUID();
+};
+#endif
diff --git a/Src/Wasabi/api/imgldr/imggen/osedge.cpp b/Src/Wasabi/api/imgldr/imggen/osedge.cpp
new file mode 100644
index 00000000..c699a860
--- /dev/null
+++ b/Src/Wasabi/api/imgldr/imggen/osedge.cpp
@@ -0,0 +1,95 @@
+#include "precomp.h"
+
+#include "osedge.h"
+#include <api/xml/xmlparams.h>
+#include <bfc/parse/pathparse.h>
+#include <api/memmgr/api_memmgr.h>
+#ifndef _WASABIRUNTIME
+
+BEGIN_SERVICES(OsEdgeGen_Svc);
+DECLARE_SERVICETSINGLE(svc_imageGenerator, OsEdgeImage);
+END_SERVICES(OsEdgeGen_Svc, _OsEdgeGen_Svc);
+
+#ifdef _X86_
+extern "C" { int _link_OsEdgeGen_Svc; }
+#else
+extern "C" { int __link_OsEdgeGen_Svc; }
+#endif
+
+#endif
+
+
+int OsEdgeImage::testDesc(const wchar_t *desc) {
+ return !_wcsicmp(desc, L"$osedge");
+}
+
+ARGB32 *OsEdgeImage::genImage(const wchar_t *desc, int *has_alpha, int *w, int *h, ifc_xmlreaderparams *params)
+{
+ int _w = params->getItemValueInt(L"w", 1);
+ if (_w == 0) _w = 1;
+ int _h = params->getItemValueInt(L"h", 1);
+ if (_h == 0) _h = 1;
+ if (_w <= 0 || _h <= 0) return NULL;
+
+#ifdef WASABI_COMPILE_MEMMGR
+ ARGB32 *ret = (ARGB32*)WASABI_API_MEMMGR->sysMalloc(_w * _h * sizeof(ARGB32));
+#else
+ ARGB32 *ret = (ARGB32*)MALLOC(_w * _h * sizeof(ARGB32));
+#endif
+
+ RECT r = Wasabi::Std::makeRect(0, 0, _w, _h);
+
+ BITMAPINFO bmi;
+ ZERO(bmi);
+ bmi.bmiHeader.biSize = sizeof(bmi);
+ bmi.bmiHeader.biWidth = _w;
+ bmi.bmiHeader.biHeight = -_h;
+ bmi.bmiHeader.biPlanes = 1;
+ bmi.bmiHeader.biBitCount = 32;
+ bmi.bmiHeader.biCompression = BI_RGB;
+ // the rest are 0
+ ARGB32 *bits;
+ HBITMAP hbmp = CreateDIBSection(NULL, &bmi, DIB_RGB_COLORS, (void**)&bits, NULL, 0);
+ HDC hdc = CreateCompatibleDC(NULL);
+ HBITMAP prevbmp = (HBITMAP)SelectObject(hdc, hbmp);
+
+ unsigned long edgev = 0;
+ if (!_wcsicmp(params->getItemValue(L"edge"), L"bump")) edgev = EDGE_BUMP;
+ else if (!_wcsicmp(params->getItemValue(L"edge"), L"etched")) edgev = EDGE_ETCHED;
+ else if (!_wcsicmp(params->getItemValue(L"edge"), L"raised")) edgev = EDGE_RAISED;
+ else if (!_wcsicmp(params->getItemValue(L"edge"), L"sunken")) edgev = EDGE_SUNKEN;
+ if (edgev == 0) edgev = EDGE_RAISED;
+
+ unsigned long sides = 0;
+ PathParserW pp(params->getItemValue(L"sides"), L",");
+ for (int i = 0; i < pp.getNumStrings(); i++) {
+ const wchar_t *p = pp.enumString(i);
+ if (!_wcsicmp(p, L"left")) sides |= BF_LEFT;
+ if (!_wcsicmp(p, L"top")) sides |= BF_TOP;
+ if (!_wcsicmp(p, L"right")) sides |= BF_RIGHT;
+ if (!_wcsicmp(p, L"bottom")) sides |= BF_BOTTOM;
+ if (!_wcsicmp(p, L"all")) sides |= BF_RECT;
+ if (!_wcsicmp(p, L"middle")) sides |= BF_MIDDLE;
+ if (!_wcsicmp(p, L"flat")) sides |= BF_FLAT;
+ if (!_wcsicmp(p, L"soft")) sides |= BF_SOFT;
+ if (!_wcsicmp(p, L"mono")) sides |= BF_MONO;
+ }
+
+// DO EET
+ DrawEdge(hdc, &r, edgev, sides);
+
+ MEMCPY(ret, bits, sizeof(ARGB32) * _w * _h);
+ for (int i = 0; i < _w * _h; i++) { // force alpha
+ ret[i] |= 0xff000000;
+ }
+
+ SelectObject(hdc, prevbmp);
+ DeleteDC(hdc);
+ DeleteObject(hbmp);
+
+ *w = _w;
+ *h = _h;
+ *has_alpha = 1; // will be optimized anyway
+
+ return ret;
+}
diff --git a/Src/Wasabi/api/imgldr/imggen/osedge.h b/Src/Wasabi/api/imgldr/imggen/osedge.h
new file mode 100644
index 00000000..f00771a1
--- /dev/null
+++ b/Src/Wasabi/api/imgldr/imggen/osedge.h
@@ -0,0 +1,13 @@
+#ifndef _OSEDGE_H
+#define _OSEDGE_H
+
+#include <api/service/svcs/svc_imggen.h>
+
+class OsEdgeImage : public svc_imageGeneratorI {
+public:
+ static const char *getServiceName() { return "OS Edge image generator"; }
+ virtual int testDesc(const wchar_t *desc);
+ virtual ARGB32 *genImage(const wchar_t *desc, int *has_alpha, int *w, int *h, ifc_xmlreaderparams *params=NULL);
+};
+
+#endif
diff --git a/Src/Wasabi/api/imgldr/imggen/poly.cpp b/Src/Wasabi/api/imgldr/imggen/poly.cpp
new file mode 100644
index 00000000..086664e8
--- /dev/null
+++ b/Src/Wasabi/api/imgldr/imggen/poly.cpp
@@ -0,0 +1,59 @@
+#include "precomp.h"
+
+#include "poly.h"
+
+#include <api/xml/xmlparams.h>
+#include <api/memmgr/api_memmgr.h>
+#ifndef _WASABIRUNTIME
+
+BEGIN_SERVICES(PolyGen_Svc);
+DECLARE_SERVICETSINGLE(svc_imageGenerator, PolyImage);
+END_SERVICES(PolyGen_Svc, _PolyGen_Svc);
+
+#ifdef _X86_
+extern "C" { int _link_PolyGen_Svc; }
+#else
+extern "C" { int __link_PolyGen_Svc; }
+#endif
+
+#endif
+
+int PolyImage::testDesc(const wchar_t *desc) {
+ return !_wcsicmp(desc, L"$polygon");
+}
+
+void premultiply(ARGB32 *m_pBits, int nwords);
+
+#include <bfc/draw/drawpoly.h>
+
+ARGB32 *PolyImage::genImage(const wchar_t *desc, int *has_alpha, int *w, int *h, ifc_xmlreaderparams *params)
+{
+ int _w = (params->getItemValueInt(L"w", 1));
+ if (_w == 0) _w = 1;
+ int _h = (params->getItemValueInt(L"h", 1));
+ if (_h == 0) _h = 1;
+ if (_w <= 0 || _h <= 0) return NULL;
+
+ const wchar_t *bgcolorstr = params->getItemValue(L"bgcolor");
+ ARGB32 bgcolor = (bgcolorstr == NULL || *bgcolorstr=='\0') ? 0 : _byteswap_ulong(WASABI_API_SKIN->parse(params->getItemValue(L"bgcolor"), L"color")<<8);
+
+ unsigned int bgalpha = params->getItemValueInt(L"bgalpha", 0);
+ bgcolor |= ((bgalpha & 0xff) << 24);
+
+ premultiply(&bgcolor, 1);
+
+#ifdef WASABI_COMPILE_MEMMGR
+ ARGB32 *ret = (ARGB32*)WASABI_API_MEMMGR->sysMalloc(_w * _h * sizeof(ARGB32));
+#else
+ ARGB32 *ret = (ARGB32*)MALLOC(_w * _h * sizeof(ARGB32));
+#endif
+
+ MEMFILL<ARGB32>(ret, bgcolor, _w * _h);
+
+ Draw::drawPointList(ret, _w, _h, params->getItemValue(L"points"));
+
+ *w = _w;
+ *h = _h;
+ *has_alpha = 1;
+ return ret;
+}
diff --git a/Src/Wasabi/api/imgldr/imggen/poly.h b/Src/Wasabi/api/imgldr/imggen/poly.h
new file mode 100644
index 00000000..07095056
--- /dev/null
+++ b/Src/Wasabi/api/imgldr/imggen/poly.h
@@ -0,0 +1,13 @@
+#ifndef _POLY_H
+#define _POLY_H
+
+#include <api/service/svcs/svc_imggen.h>
+
+class PolyImage : public svc_imageGeneratorI {
+public:
+ static const char *getServiceName() { return "Polygon image generator"; }
+ virtual int testDesc(const wchar_t *desc);
+ virtual ARGB32 *genImage(const wchar_t *desc, int *has_alpha, int *w, int *h, ifc_xmlreaderparams *params=NULL);
+};
+
+#endif
diff --git a/Src/Wasabi/api/imgldr/imggen/shadowwnd.cpp b/Src/Wasabi/api/imgldr/imggen/shadowwnd.cpp
new file mode 100644
index 00000000..fb61c95c
--- /dev/null
+++ b/Src/Wasabi/api/imgldr/imggen/shadowwnd.cpp
@@ -0,0 +1,152 @@
+#include "precomp.h"
+
+#include "shadowwnd.h"
+
+#include "../bfc/canvas.h"
+#include "../bfc/region.h"
+
+enum { TARGET };
+
+char XuiShadowWndParams[][]=
+{
+ "TARGET",
+};
+XuiShadowWnd::XuiShadowWnd() {
+ myxuihandle = newXuiHandle();
+ addParam(myxuihandle, XuiShadowWndParams[0], TARGET, XUI_ATTRIBUTE_REQUIRED);
+ group = NULL;
+ bltcanvas = NULL;
+ c_w = c_h = 0;
+ in_paint = 0;
+}
+
+XuiShadowWnd::~XuiShadowWnd() {
+ delete bltcanvas;
+}
+
+int XuiShadowWnd::onInit() {
+ XUISHADOWWND_PARENT::onInit();
+
+DebugString("on iniiit");
+
+ attachToGroup();
+setTimer(10, 50);
+
+ return 1;
+}
+
+void XuiShadowWnd::timerclient_timerCallback(int id) {
+ if (id == 10) {
+ if (group == NULL) attachToGroup();
+ delete bltcanvas;
+ RECT r; group->getClientRect(&r);
+ bltcanvas = new BltCanvas(r.right - r.left, r.bottom - r.top);
+ in_paint++;
+ group->paint(bltcanvas);
+MEMFILL<ARGB32>((unsigned long *)bltcanvas->getBits(), 0xffffffff, (r.right - r.left) * 20);
+ in_paint--;
+ invalidate();
+ } else
+ XUISHADOWWND_PARENT::timerclient_timerCallback(id);
+}
+
+int XuiShadowWnd::onPaint(Canvas *canvas) {
+#if 0
+if (group == NULL) attachToGroup();
+if (group == NULL) { DebugString("groupNull"); }
+if (group == NULL) return 0;
+
+#endif
+DebugString("begin painting");
+
+if (in_paint++) {
+// RECT cr = clientRect();
+// canvas->fillRect(&cr, RGB(255,0,255));
+//MEMFILL<ARGB32>((unsigned long *)canvas->getBits(), 0xffffffff, (cr.right - cr.left) * 20);
+DebugString("filla!");
+} else {
+#if 0
+ RECT cr;
+ group->getClientRect(&cr);
+ SkinBitmap *bm
+bltcanvas->blit(0, 0,
+BltCanvas c(cr.right - cr.left, cr.bottom - cr.top);
+group->paint(&c);
+#if 0
+c.pushPen(0,255,0);
+c.lineDraw(0, 0, cr.right, cr.bottom);
+/c.popPen();
+#endif
+MEMFILL<ARGB32>((unsigned long *)c.getBits(), 0xffffffff, (cr.right - cr.left) * 20);
+c.blit(0, 0, canvas, 0, 0, cr.right - cr.left, cr.bottom - cr.top);
+
+DebugString("get from group!");
+#endif
+ if (bltcanvas != NULL) {
+ SkinBitmap *bm = bltcanvas->getSkinBitmap();
+ bm->stretchToRectAlpha(canvas, &clientRect(), getPaintingAlpha());
+DebugString("bleet!");
+ }
+}
+in_paint--;
+ return 1;
+}
+
+int XuiShadowWnd::setXuiParam(int xuihandle, int xmlattributeid, const wchar_t *xmlattributename, const wchar_t *value) {
+ if (xuihandle != myxuihandle)
+ return XUISHADOWWND_PARENT::setXuiParam(xuihandle, xmlattributeid, xmlattributename, value);
+ switch (xmlattributeid) {
+ case TARGET:
+ targetname = value;
+DebugString("set target %s", value);
+ if (isPostOnInit()) attachToGroup();
+ break;
+ default: return 0;
+ }
+ return 1;
+}
+
+void XuiShadowWnd::attachToGroup() {
+ if (targetname.isempty()) return;
+ group = findWindow(targetname);
+ if (group == NULL) return;
+ monitorWindow(group);
+DebugString("attached to group rw %d", group);
+
+ delete bltcanvas; bltcanvas = NULL;
+}
+
+void XuiShadowWnd::onAfterPaint(PaintCallbackInfo *info) {
+DebugString("after paint");
+#if 0
+ RECT ncr;
+ group->getNonClientRect(&ncr);
+ c_w = ncr.right - ncr.left;
+ c_h = ncr.bottom - ncr.top;
+
+DebugString("w %d h %d", c_w, c_h);
+
+ delete bltcanvas; bltcanvas = NULL;
+ if (c_w != 0 && c_h != 0) bltcanvas = new BltCanvas(c_w, c_h);
+
+ Canvas *c = info->getCanvas();
+ api_region *r = info->getRegion();
+ // blit what changed
+ RegionI saved;
+ c->getClipRgn(&saved);
+ bltcanvas->selectClipRgn(r);
+ c->blit(0, 0, bltcanvas, 0, 0, c_w, c_h);
+ c->selectClipRgn(&saved);
+
+ invalidate();
+#endif
+}
+
+void XuiShadowWnd::onInvalidation(PaintCallbackInfo *info) {
+// invalidate();
+DebugString("got invalidate");
+}
+
+void XuiShadowWnd::onWindowDeleted(api_window *w) {
+ if (w == group) group = NULL;
+}
diff --git a/Src/Wasabi/api/imgldr/imggen/shadowwnd.h b/Src/Wasabi/api/imgldr/imggen/shadowwnd.h
new file mode 100644
index 00000000..8082dba5
--- /dev/null
+++ b/Src/Wasabi/api/imgldr/imggen/shadowwnd.h
@@ -0,0 +1,40 @@
+#ifndef _SHADOW_H
+#define _SHADOW_H
+
+#include "../common/guiobjwnd.h"
+#include "../bfc/paintcb.h"
+
+#define XUISHADOWWND_PARENT GuiObjectWnd
+class XuiShadowWnd : public XUISHADOWWND_PARENT, public PaintCallback {
+public:
+ static const wchar_t *xuiobject_getXmlTag() { return "Shadow"; }
+ static const char *xuiobject_getServiceName() { return "Shadow XuiObject"; }
+
+ XuiShadowWnd();
+ virtual ~XuiShadowWnd();
+
+ virtual int onInit();
+
+ virtual int onPaint(Canvas *canvas);
+
+ virtual int setXuiParam(int xuihandle, int xmlattributeid, const wchar_t *xmlattributename, const wchar_t *value);
+
+ virtual void onAfterPaint(PaintCallbackInfo *info);
+ virtual void onInvalidation(PaintCallbackInfo *info);
+protected:
+ virtual void onWindowDeleted(BaseWnd *w);
+ void attachToGroup();
+ virtual void timerclient_timerCallback(int id);
+
+private:
+ int myxuihandle;
+ StringW targetname;
+ api_window *group;
+ BltCanvas *bltcanvas;
+ int c_w, c_h;
+ int in_paint;
+};
+
+class XuiShadowWndSvc : public XuiObjectSvc2<XuiShadowWnd> {};
+
+#endif
diff --git a/Src/Wasabi/api/imgldr/imggen/solid.cpp b/Src/Wasabi/api/imgldr/imggen/solid.cpp
new file mode 100644
index 00000000..7f461eaa
--- /dev/null
+++ b/Src/Wasabi/api/imgldr/imggen/solid.cpp
@@ -0,0 +1,67 @@
+#include "precomp.h"
+
+#include "solid.h"
+#include <api/xml/xmlparams.h>
+#include <api/memmgr/api_memmgr.h>
+
+#ifndef _WASABIRUNTIME
+
+BEGIN_SERVICES(SolidGen_Svc);
+DECLARE_SERVICETSINGLE(svc_imageGenerator, SolidImage);
+END_SERVICES(SolidGen_Svc, _SolidGen_Svc);
+
+#ifdef _X86_
+extern "C" { int _link_SolidGen_Svc; }
+#else
+extern "C" { int __link_SolidGen_Svc; }
+#endif
+
+#endif
+
+int SolidImage::testDesc(const wchar_t *desc)
+{
+ return !WCSICMP(desc, L"$solid");
+}
+
+void premultiply(ARGB32 *m_pBits, int nwords)
+{
+ for (; nwords > 0; nwords--, m_pBits++)
+ {
+ unsigned __int8 *pixel = (unsigned __int8 *)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
+ }
+}
+
+ARGB32 *SolidImage::genImage(const wchar_t *desc, int *has_alpha, int *w, int *h, ifc_xmlreaderparams *params)
+{
+ int _w = params->getItemValueInt(L"w", 1);
+ if (_w == 0) _w = 1;
+ int _h = params->getItemValueInt(L"h", 1);
+ if (_h == 0) _h = 1;
+ if (_w <= 0 || _h <= 0) return NULL;
+ ARGB32 color = _byteswap_ulong(WASABI_API_SKIN->parse(params->getItemValue(L"color"), L"color") << 8);
+
+ unsigned int alpha = params->getItemValueInt(L"alpha", 255);
+ color |= ((alpha & 0xff) << 24);
+
+ premultiply(&color, 1);
+
+#ifdef WASABI_COMPILE_MEMMGR
+ ARGB32 *ret = (ARGB32*)WASABI_API_MEMMGR->sysMalloc(_w * _h * sizeof(ARGB32));
+#else
+ ARGB32 *ret = (ARGB32*)MALLOC(_w * _h * sizeof(ARGB32));
+#endif
+
+ MEMFILL<ARGB32>(ret, color, _w * _h);
+
+ *w = _w;
+ *h = _h;
+
+ *has_alpha = (alpha == 255) ? 0 : 1;
+
+ return ret;
+}
diff --git a/Src/Wasabi/api/imgldr/imggen/solid.h b/Src/Wasabi/api/imgldr/imggen/solid.h
new file mode 100644
index 00000000..d810bc1c
--- /dev/null
+++ b/Src/Wasabi/api/imgldr/imggen/solid.h
@@ -0,0 +1,14 @@
+#ifndef _SOLID_H
+#define _SOLID_H
+
+#include <api/service/svcs/svc_imggen.h>
+
+class SolidImage : public svc_imageGeneratorI
+{
+public:
+ static const char *getServiceName() { return "Solid Color image generator"; }
+ virtual int testDesc(const wchar_t *desc);
+ virtual ARGB32 *genImage(const wchar_t *desc, int *has_alpha, int *w, int *h, ifc_xmlreaderparams *params = NULL);
+};
+
+#endif