summaryrefslogtreecommitdiffstats
path: root/chalk/colorspaces/wetsticky
diff options
context:
space:
mode:
authortpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2011-06-26 00:41:16 +0000
committertpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2011-06-26 00:41:16 +0000
commit698569f8428ca088f764d704034a1330517b98c0 (patch)
treebf45be6946ebbbee9cce5a5bcf838f4c952d87e6 /chalk/colorspaces/wetsticky
parent2785103a6bd4de55bd26d79e34d0fdd4b329a73a (diff)
downloadkoffice-698569f8428ca088f764d704034a1330517b98c0.tar.gz
koffice-698569f8428ca088f764d704034a1330517b98c0.zip
Finish rebranding of Krita as Chalk
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/koffice@1238363 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'chalk/colorspaces/wetsticky')
-rw-r--r--chalk/colorspaces/wetsticky/Makefile.am25
-rw-r--r--chalk/colorspaces/wetsticky/README42
-rw-r--r--chalk/colorspaces/wetsticky/TODO7
-rw-r--r--chalk/colorspaces/wetsticky/brushop/Makefile.am28
-rw-r--r--chalk/colorspaces/wetsticky/brushop/README2
-rw-r--r--chalk/colorspaces/wetsticky/brushop/chalkwsbrushpaintop.desktop73
-rw-r--r--chalk/colorspaces/wetsticky/brushop/kis_wsbrushop.cc117
-rw-r--r--chalk/colorspaces/wetsticky/brushop/kis_wsbrushop.h56
-rw-r--r--chalk/colorspaces/wetsticky/brushop/wetpaintbrush.pngbin0 -> 1329 bytes
-rw-r--r--chalk/colorspaces/wetsticky/brushop/wsbrushpaintop_plugin.cc56
-rw-r--r--chalk/colorspaces/wetsticky/brushop/wsbrushpaintop_plugin.h44
-rw-r--r--chalk/colorspaces/wetsticky/chalkwsplugin.desktop46
-rw-r--r--chalk/colorspaces/wetsticky/kis_wet_sticky_colorspace.cc605
-rw-r--r--chalk/colorspaces/wetsticky/kis_wet_sticky_colorspace.h148
-rw-r--r--chalk/colorspaces/wetsticky/kis_ws_engine_filter.cc180
-rw-r--r--chalk/colorspaces/wetsticky/kis_ws_engine_filter.h77
-rw-r--r--chalk/colorspaces/wetsticky/wet_sticky_plugin.cc60
-rw-r--r--chalk/colorspaces/wetsticky/wet_sticky_plugin.h42
-rw-r--r--chalk/colorspaces/wetsticky/ws/GNU0
-rw-r--r--chalk/colorspaces/wetsticky/ws/GNU Public Licence.txt341
-rw-r--r--chalk/colorspaces/wetsticky/ws/README4
-rw-r--r--chalk/colorspaces/wetsticky/ws/TODO24
-rw-r--r--chalk/colorspaces/wetsticky/ws/after.jpgbin0 -> 29607 bytes
-rw-r--r--chalk/colorspaces/wetsticky/ws/anim.c154
-rw-r--r--chalk/colorspaces/wetsticky/ws/before.jpgbin0 -> 15496 bytes
-rw-r--r--chalk/colorspaces/wetsticky/ws/canvas.c514
-rw-r--r--chalk/colorspaces/wetsticky/ws/canvas.h70
-rw-r--r--chalk/colorspaces/wetsticky/ws/cmap.c681
-rw-r--r--chalk/colorspaces/wetsticky/ws/constants.h69
-rw-r--r--chalk/colorspaces/wetsticky/ws/engine.c802
-rw-r--r--chalk/colorspaces/wetsticky/ws/engine.h33
-rw-r--r--chalk/colorspaces/wetsticky/ws/engine3.c617
-rw-r--r--chalk/colorspaces/wetsticky/ws/load_ppm.c244
-rw-r--r--chalk/colorspaces/wetsticky/ws/main.c105
-rw-r--r--chalk/colorspaces/wetsticky/ws/makefile55
-rw-r--r--chalk/colorspaces/wetsticky/ws/mona.pgmbin0 -> 86269 bytes
-rw-r--r--chalk/colorspaces/wetsticky/ws/ogl_interface.c302
-rw-r--r--chalk/colorspaces/wetsticky/ws/test2.jpgbin0 -> 13051 bytes
-rw-r--r--chalk/colorspaces/wetsticky/ws/test3.jpgbin0 -> 21238 bytes
-rw-r--r--chalk/colorspaces/wetsticky/ws/types.h72
-rw-r--r--chalk/colorspaces/wetsticky/ws/win_interface.h28
-rw-r--r--chalk/colorspaces/wetsticky/ws/x_interface.c795
-rw-r--r--chalk/colorspaces/wetsticky/wstool.ui262
43 files changed, 6780 insertions, 0 deletions
diff --git a/chalk/colorspaces/wetsticky/Makefile.am b/chalk/colorspaces/wetsticky/Makefile.am
new file mode 100644
index 00000000..4ade368a
--- /dev/null
+++ b/chalk/colorspaces/wetsticky/Makefile.am
@@ -0,0 +1,25 @@
+kde_services_DATA = chalkwsplugin.desktop
+INCLUDES = -I$(srcdir)/../../sdk \
+ -I$(srcdir)/../../core \
+ -I$(srcdir)/../../core/color_strategy \
+ -I$(srcdir)/../../../chalkcolor/color_strategy/ \
+ -I$(srcdir)/../../../color_strategy/ \
+ -I$(srcdir)/../../ui \
+ $(KOFFICE_INCLUDES) \
+ -I$(interfacedir) \
+ $(KOPAINTER_INCLUDES) \
+ $(all_includes)
+
+kde_module_LTLIBRARIES = chalkwsplugin.la
+
+chalkwsplugin_la_SOURCES = wet_sticky_plugin.cc kis_wet_sticky_colorspace.cc kis_ws_engine_filter.cc
+noinst_HEADERS = wet_sticky_plugin.h kis_wet_sticky_colorspace.h kis_ws_engine_filter.h
+
+chalkwsplugin_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+chalkwsplugin_la_LIBADD = ../../chalkcolor/libchalkcolor.la
+
+chalkwsplugin_la_METASOURCES = AUTO
+
+SUBDIRS=brushop
+
+
diff --git a/chalk/colorspaces/wetsticky/README b/chalk/colorspaces/wetsticky/README
new file mode 100644
index 00000000..b1844466
--- /dev/null
+++ b/chalk/colorspaces/wetsticky/README
@@ -0,0 +1,42 @@
+Wet & Sticky
+
+The Chalk Wet & Sticky module is derived from the seminal dissertation
+"Wet & Stick: A Novel Model for Computer-Based Painting" by Malcom Tunde
+Cockshott, and the implementation of that model by Tunde Cockshott,
+David England and Kevin Waite. The complete source code to the first
+implementation is included in the module_ws/ws and is released under
+the terms of the GPL.
+
+The W&S model is implemented in the following components:
+
+* A color strategy
+* A paint op
+* A filter
+
+The color strategy implements the canvas; the paint op implements the
+application of paint and the filter implements the paint simulation
+engine.
+
+This system adds the following interesting capabilities to Chalk:
+
+* Extending the tool options dialog with a widget describing the
+ paint op.
+
+* Extending the paint op class with properties beyond opacity and
+ color to a more generic structure with can contain the many different
+ properties needed by more complex color models to calculate bitBlt's.
+
+ All the ordinary paint ops still work, but they act as if they are
+ applying dry, thin paint, conforming to Cockshott's analysis of the
+ Shoup model (which Chalk implemented in the first instance) as a subset
+ of the W&S model.
+
+* Adding continuously running filters (either in separate threads or
+ called by a timer) to a particular paint device.
+
+* Adding a new way to mix colour; the older colour selection widgets
+ still work, but only give completely dry, infinitely thin paint.
+
+* Creating a layer with a fill of 'substrate' cells -- i.e, filling not just
+ with colour, but also with certain calculated amounts of height,
+ gravity and absorbency.
diff --git a/chalk/colorspaces/wetsticky/TODO b/chalk/colorspaces/wetsticky/TODO
new file mode 100644
index 00000000..513df2ff
--- /dev/null
+++ b/chalk/colorspaces/wetsticky/TODO
@@ -0,0 +1,7 @@
+* Add paintopbox to toolbox
+* Make all paint tools use the paintop from the paintop box
+* Add paintop properties palette
+* Add continuously running filters
+* Add filler objects that can fill a given area computationally
+* Add extensible properties for paint devices (to control things like drying)
+* Add default fill hook dependent on colorspace
diff --git a/chalk/colorspaces/wetsticky/brushop/Makefile.am b/chalk/colorspaces/wetsticky/brushop/Makefile.am
new file mode 100644
index 00000000..8df4d61e
--- /dev/null
+++ b/chalk/colorspaces/wetsticky/brushop/Makefile.am
@@ -0,0 +1,28 @@
+kde_services_DATA = chalkwsbrushpaintop.desktop
+
+chalkimagesdir = $(prefix)/share/apps/chalk/images
+chalkimages_DATA = wetpaintbrush.png
+
+# all_includes must remain last!
+INCLUDES = -I$(srcdir)/../../../sdk \
+ -I$(srcdir)/../../../chalkcolor/color_strategy/ \
+ -I$(srcdir)/../../../color_strategy/ \
+ -I$(srcdir)/../../../core/ \
+ -I$(srcdir)/../../../ui \
+ $(KOFFICE_INCLUDES) $(KOPAINTER_INCLUDES) $(all_includes)
+
+
+chalkwsbrushpaintop_la_SOURCES = \
+ wsbrushpaintop_plugin.cc \
+ kis_wsbrushop.cc
+
+noinst_HEADERS= \
+ wsbrushpaintop_plugin.h \
+ kis_wsbrushop.h
+
+kde_module_LTLIBRARIES = chalkwsbrushpaintop.la
+
+chalkwsbrushpaintop_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+chalkwsbrushpaintop_la_LIBADD = ../../..//libchalkcommon.la $(LIB_KOPAINTER) $(LIB_KOFFICECORE)
+
+chalkwsbrushpaintop_la_METASOURCES = AUTO
diff --git a/chalk/colorspaces/wetsticky/brushop/README b/chalk/colorspaces/wetsticky/brushop/README
new file mode 100644
index 00000000..81156a89
--- /dev/null
+++ b/chalk/colorspaces/wetsticky/brushop/README
@@ -0,0 +1,2 @@
+Template for plugin paintops. Paint tools use the paintop to determine how
+to deposit their paint on the canvas, exactly.
diff --git a/chalk/colorspaces/wetsticky/brushop/chalkwsbrushpaintop.desktop b/chalk/colorspaces/wetsticky/brushop/chalkwsbrushpaintop.desktop
new file mode 100644
index 00000000..aa087bb9
--- /dev/null
+++ b/chalk/colorspaces/wetsticky/brushop/chalkwsbrushpaintop.desktop
@@ -0,0 +1,73 @@
+[Desktop Entry]
+Name=Wet & Sticky Paintbrush Paintop
+Name[bg]=Мокра и лепкава четка
+Name[ca]=Pinzell humit i viscós de Paintop
+Name[cy]=Brws paent gwlyb gludiog
+Name[da]=Maleoperation med våd og klæbrig malerpensel
+Name[de]=Maloperation mit feuchtem & klebrigem Farbpinsel
+Name[el]=Βούρτσα υγρής και κολλώδους μπογιάς
+Name[eo]=KDED-testmodulo
+Name[es]=Pincel mojado y pegajoso para pintar
+Name[et]=Märja lõuendi joonistamistoiming
+Name[fa]=Paintop قلم‌موی چسبناک و مرطوب
+Name[fr]=Pinceau paintop mouillé et gluant
+Name[fy]=Kwasten foar wiete en kliemske ferfhannelings
+Name[gl]=Pintado Mollado e Pegoñento
+Name[hu]=Nedves és ragadós ecset
+Name[is]=Blautur & klístraður pensill
+Name[it]=Operazione con pennello bagnato e appiccicoso
+Name[km]=ជក់​ទឹក & ស្អិត Paintop
+Name[nb]=Fargemodell for våt og klissete pensel
+Name[nds]=Malen mit en natten backigen Pinsel
+Name[ne]=ओसिलो र टाँसिने पेन्टब्रस पेन्टप
+Name[nl]=Kwasten voor natte en kleverige verfverrichtingen
+Name[pl]=Mokre i lepkie włosie pędzla
+Name[pt]=Modelo de Cores Molhado e Pegajoso
+Name[pt_BR]=Modelo de Cores Molhado e Pegajoso
+Name[ru]=Кисть с параметрами влажности и прилипания
+Name[sk]=Mokrý a lepkavý štetec Paintop
+Name[sl]=Slikanje z mokrim in lepljivim čopičem
+Name[sr]=Модел боја мокре и лепљиве четкице
+Name[sr@Latn]=Model boja mokre i lepljive četkice
+Name[sv]=Målningsoperation med våt och klibbig målarpensel
+Name[uk]=Пензель з параметрами вогкості і клейкості
+Name[zh_CN]=湿性和粘性画布
+Name[zh_TW]=濕 & 黏的筆刷頭
+Comment=Wet & Sticky paintbrush
+Comment[bg]=Мокра и лепкава четка
+Comment[ca]=Pinzell humit i viscós
+Comment[cy]=Brws paent gwlyb gludiog
+Comment[da]=Våd og klæbrig malerpensel
+Comment[de]=Feuchter & klebriger Farbpinsel
+Comment[el]=Βούρτσα υγρής και κολλώδους μπογιάς
+Comment[eo]=Malseka & Glueca peniko
+Comment[es]=Pincel mojado y pegajoso
+Comment[et]=Märja lõuendi pintsel
+Comment[fa]=قلم‌موی چسبناک و مرطوب
+Comment[fr]=Pinceau mouillé et gluant
+Comment[fy]=Kwast foar wiete en kliemske ferfhannelings
+Comment[gl]=Un pincel mollado e pegaxoso
+Comment[hu]=Nedves és ragadós ecset
+Comment[is]=Blautur og klístraður pensill
+Comment[it]=Pennello bagnato e appiccicoso
+Comment[ja]=Wet & Sticky ペイントブラシ
+Comment[km]=ជក់​ទឹក & ស្អិត
+Comment[nb]=Våt og klissete pensel
+Comment[nds]=Natt un backig Pinsel
+Comment[ne]=ओसिलो र टाँसिने पेन्टब्रस
+Comment[nl]=Kwast voor nat en kleverige verfverichtingen
+Comment[pl]=Mokry i lepki pędzel
+Comment[pt]=Um pincel molhado e pegajoso
+Comment[pt_BR]=Modelo de cores de tela Molhada & Pegajosa
+Comment[ru]=Кисть с параметрами влажности и прилипания
+Comment[sk]=Mokrý a lepkavý štetec
+Comment[sl]=Moker in lepljiv čopič
+Comment[sr]=Мокра и лепљива четкица
+Comment[sr@Latn]=Mokra i lepljiva četkica
+Comment[sv]=Våt och klibbig målarpensel
+Comment[uk]=Пензель з параметрами вогкості і клейкості
+Comment[zh_TW]=濕 & 黏的筆刷
+ServiceTypes=Chalk/ColorSpace
+Type=Service
+X-KDE-Library=chalkwsbrushpaintop
+X-Chalk-Version=2
diff --git a/chalk/colorspaces/wetsticky/brushop/kis_wsbrushop.cc b/chalk/colorspaces/wetsticky/brushop/kis_wsbrushop.cc
new file mode 100644
index 00000000..8b182e08
--- /dev/null
+++ b/chalk/colorspaces/wetsticky/brushop/kis_wsbrushop.cc
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2005 Boudewijn Rempt <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <tqrect.h>
+
+#include <kdebug.h>
+
+#include "kis_brush.h"
+#include "kis_global.h"
+#include "kis_paint_device.h"
+#include "kis_painter.h"
+#include "kis_types.h"
+#include "kis_paintop.h"
+
+#include "kis_wsbrushop.h"
+
+KisPaintOp * KisWSBrushOpFactory::createOp(const KisPaintOpSettings */*settings*/, KisPainter * painter)
+{
+ KisPaintOp * op = new KisWSBrushOp(painter);
+ Q_CHECK_PTR(op);
+ return op;
+}
+
+KisWSBrushOp::KisWSBrushOp(KisPainter * painter)
+ : super(painter)
+{
+}
+
+KisWSBrushOp::~KisWSBrushOp()
+{
+}
+
+void KisWSBrushOp::paintAt(const KisPoint &pos,
+ const double pressure,
+ const double /*xTilt*/,
+ const double /*yTilt*/)
+{
+ // Painting should be implemented according to the following algorithm:
+ // retrieve brush
+ // if brush == tqmask
+ // retrieve tqmask
+ // else if brush == image
+ // retrieve image
+ // subsample (tqmask | image) for position -- pos should be double!
+ // apply filters to tqmask (colour | gradient | pattern | etc.
+ // composite filtered tqmask into temporary layer
+ // composite temporary layer into target layer
+ // @see: doc/brush.txt
+
+ if (!m_painter -> device()) return;
+
+ KisBrush *brush = m_painter -> brush();
+
+ Q_ASSERT(brush);
+ if (!brush) return;
+
+ KisPaintDeviceSP device = m_painter -> device();
+
+ KisPoint hotSpot = brush -> hotSpot(pressure);
+ KisPoint pt = pos - hotSpot;
+
+ // Split the coordinates into integer plus fractional parts. The integer
+ // is where the dab will be positioned and the fractional part determines
+ // the sub-pixel positioning.
+ TQ_INT32 x;
+ double xFraction;
+ TQ_INT32 y;
+ double yFraction;
+
+ splitCoordinate(pt.x(), &x, &xFraction);
+ splitCoordinate(pt.y(), &y, &yFraction);
+
+ KisLayerSP dab = 0;
+
+ if (brush -> brushType() == IMAGE || brush -> brushType() == PIPE_IMAGE) {
+ dab = brush -> image(device -> colorSpace(), pressure, xFraction, yFraction);
+ }
+ else {
+ KisAlphaMaskSP tqmask = brush -> tqmask(pressure, xFraction, yFraction);
+ dab = computeDab(tqmask);
+ }
+ m_painter -> setPressure(pressure);
+
+ TQRect dabRect = TQRect(0, 0, brush -> tqmaskWidth(pressure), brush -> tqmaskHeight(pressure));
+ TQRect dstRect = TQRect(x, y, dabRect.width(), dabRect.height());
+
+ KisImage * image = device -> image();
+
+ if (image != 0) {
+ dstRect &= image -> bounds();
+ }
+
+ if (dstRect.isNull() || dstRect.isEmpty() || !dstRect.isValid()) return;
+
+ TQ_INT32 sx = dstRect.x() - x;
+ TQ_INT32 sy = dstRect.y() - y;
+ TQ_INT32 sw = dstRect.width();
+ TQ_INT32 sh = dstRect.height();
+
+ m_painter -> bltSelection(dstRect.x(), dstRect.y(), m_painter -> compositeOp(), dab.data(), m_painter -> opacity(), sx, sy, sw, sh);
+ m_painter -> addDirtyRect(dstRect);
+}
diff --git a/chalk/colorspaces/wetsticky/brushop/kis_wsbrushop.h b/chalk/colorspaces/wetsticky/brushop/kis_wsbrushop.h
new file mode 100644
index 00000000..65f5fb6c
--- /dev/null
+++ b/chalk/colorspaces/wetsticky/brushop/kis_wsbrushop.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2005 Boudewijn Rempt <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef KIS_WSBRUSHOP_H_
+#define KIS_WSBRUSHOP_H_
+
+#include "kis_paintop.h"
+#include "kis_types.h"
+
+class KisPoint;
+class KisPainter;
+
+
+class KisWSBrushOpFactory : public KisPaintOpFactory {
+
+public:
+ KisWSBrushOpFactory() {}
+ virtual ~KisWSBrushOpFactory() {}
+
+ virtual KisPaintOp * createOp(const KisPaintOpSettings *settings, KisPainter * painter);
+ virtual KisID id() { return KisID("wsbrush", i18n("Wet & Sticky Paintbrush")); }
+ virtual TQString pixmap() { return "wetpaintbrush.png"; }
+};
+
+class KisWSBrushOp : public KisPaintOp {
+
+ typedef KisPaintOp super;
+
+public:
+
+ KisWSBrushOp(KisPainter * painter);
+ virtual ~KisWSBrushOp();
+
+ void paintAt(const KisPoint &pos,
+ const double pressure,
+ const double /*xTilt*/,
+ const double /*yTilt*/);
+
+};
+
+#endif // KIS_WSBRUSHOP_H_
diff --git a/chalk/colorspaces/wetsticky/brushop/wetpaintbrush.png b/chalk/colorspaces/wetsticky/brushop/wetpaintbrush.png
new file mode 100644
index 00000000..8b681ec1
--- /dev/null
+++ b/chalk/colorspaces/wetsticky/brushop/wetpaintbrush.png
Binary files differ
diff --git a/chalk/colorspaces/wetsticky/brushop/wsbrushpaintop_plugin.cc b/chalk/colorspaces/wetsticky/brushop/wsbrushpaintop_plugin.cc
new file mode 100644
index 00000000..383bd9c5
--- /dev/null
+++ b/chalk/colorspaces/wetsticky/brushop/wsbrushpaintop_plugin.cc
@@ -0,0 +1,56 @@
+/*
+ * wsbrushpaintop_plugin.cc -- Part of Chalk
+ *
+ * Copyright (c) 2005 Boudewijn Rempt ([email protected])
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#include <klocale.h>
+#include <kiconloader.h>
+#include <kinstance.h>
+#include <kmessagebox.h>
+#include <kstandarddirs.h>
+#include <ktempfile.h>
+#include <kdebug.h>
+#include <kgenericfactory.h>
+
+#include <kis_paintop_registry.h>
+#include <kis_debug_areas.h>
+#include "kis_wsbrushop.h"
+
+#include "wsbrushpaintop_plugin.h"
+
+typedef KGenericFactory<WSBrushPaintOpPlugin> WSBrushPaintOpPluginFactory;
+K_EXPORT_COMPONENT_FACTORY( chalkwsbrushpaintop, WSBrushPaintOpPluginFactory( "chalkcore" ) )
+
+
+WSBrushPaintOpPlugin::WSBrushPaintOpPlugin(TQObject *tqparent, const char *name, const TQStringList &)
+ : KParts::Plugin(tqparent, name)
+{
+ setInstance(WSBrushPaintOpPluginFactory::instance());
+
+ // This is not a gui plugin; only load it when the doc is created.
+ if ( tqparent->inherits("KisFactory") )
+ {
+ KisPaintOpRegistry::instance() -> add ( new KisWSBrushOpFactory );
+ }
+
+}
+
+WSBrushPaintOpPlugin::~WSBrushPaintOpPlugin()
+{
+}
+
+#include "wsbrushpaintop_plugin.moc"
diff --git a/chalk/colorspaces/wetsticky/brushop/wsbrushpaintop_plugin.h b/chalk/colorspaces/wetsticky/brushop/wsbrushpaintop_plugin.h
new file mode 100644
index 00000000..7e77afec
--- /dev/null
+++ b/chalk/colorspaces/wetsticky/brushop/wsbrushpaintop_plugin.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2005 Boudewijn Rempt ([email protected])
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef WSBRUSH_PAINTOP_PLUGIN_H_
+#define WSBRUSH_PAINTOP_PLUGIN_H_
+
+#include <kparts/plugin.h>
+
+#include "kis_types.h"
+
+class KisView;
+
+/**
+ * A plugin wrapper that adds the paintop factories to the paintop registry.
+ */
+class WSBrushPaintOpPlugin : public KParts::Plugin
+{
+ Q_OBJECT
+ TQ_OBJECT
+public:
+ WSBrushPaintOpPlugin(TQObject *tqparent, const char *name, const TQStringList &);
+ virtual ~WSBrushPaintOpPlugin();
+
+private:
+
+ KisView* m_view;
+};
+
+#endif // WSBRUSH_PAINTOP_PLUGIN_H_
diff --git a/chalk/colorspaces/wetsticky/chalkwsplugin.desktop b/chalk/colorspaces/wetsticky/chalkwsplugin.desktop
new file mode 100644
index 00000000..12fdc286
--- /dev/null
+++ b/chalk/colorspaces/wetsticky/chalkwsplugin.desktop
@@ -0,0 +1,46 @@
+[Desktop Entry]
+Name=Wet & Sticky Canvas Color Model
+Name[bg]=Цветови модел за мокро и лепкаво платно
+Name[ca]=Model de color de llenç humit i viscós
+Name[cy]=Model Lliw Cynfas Gwlyb a Gludiog
+Name[da]=Våd & klæbrig kanvasfarve-model
+Name[de]=Farbmodell feuchte & klebrige Leinwand
+Name[el]=Μοντέλο καμβά υγρής και κολλώδους μπογιάς
+Name[en_GB]=Wet & Sticky Canvas Colour Model
+Name[eo]=Kolormodelo por Malseka & Glueca Kanvaso
+Name[es]=Modelo de color de lienzo mojado y pegajoso
+Name[et]=Märja lõuendi värvimudel
+Name[eu]=Oihal heze eta itsaskorraren kolore-eredua
+Name[fa]=مدل رنگ صفحه مجازی چسبناک و مرطوب
+Name[fi]=Märkä ja tahmea kangasvärimalli
+Name[fr]=Modèle de couleurs gluantes et mouillées
+Name[fy]=wiete en kliemske canvasmodel
+Name[gl]=Modelo de Cores de Tea Mollado e Pegoñento
+Name[hu]=Nedves és ragadós vászon színmodell
+Name[is]=Blaut & klístruð litategund
+Name[it]=Modello di colore per tela bagnata
+Name[ja]=Wet & Sticky キャンバスカラーモデル
+Name[km]=ម៉ូដែល​ពណ៌​ទឹក & ស្អិត
+Name[ms]=Model Warna Kanvas Basah & Lekit
+Name[nb]=Fargemodell for vått og klissete lerret
+Name[nds]=Klöörmodell natt un backig Lienwand
+Name[ne]=ओसिलो र टाँसिने चित्रपट रङ मोडेल
+Name[nl]=Nat en kleverig canvasmodel
+Name[nn]=Fargemodell for vått lerret
+Name[pl]=Przestrzeń barw mokrego i lepkiego płótna
+Name[pt]=Modelo de Cores de Tela Molhado e Pegajoso
+Name[pt_BR]=Modelo de cores de tela Molhada & Pegajosa
+Name[ru]=Цветовое пространство с параметрами влажности и прилипания
+Name[sk]=Model farieb pre mokré a lepkavé plátno
+Name[sl]=Barvni model z mokrim in lepljivim platnom
+Name[sr]=Модел боја мокрог и лепљивог платна
+Name[sr@Latn]=Model boja mokrog i lepljivog platna
+Name[sv]=Våt och klibbig dukfärgmodell
+Name[uk]=Канва моделі кольорів з параметрами вогкості і клейкості
+Name[zh_CN]=湿性/粘性画布色彩模型
+Name[zh_TW]=濕 & 黏的畫布色彩模型
+ServiceTypes=Chalk/ColorSpace
+Type=Service
+X-KDE-Library=chalkwsplugin
+X-Chalk-Version=2
+
diff --git a/chalk/colorspaces/wetsticky/kis_wet_sticky_colorspace.cc b/chalk/colorspaces/wetsticky/kis_wet_sticky_colorspace.cc
new file mode 100644
index 00000000..44426382
--- /dev/null
+++ b/chalk/colorspaces/wetsticky/kis_wet_sticky_colorspace.cc
@@ -0,0 +1,605 @@
+/*
+ * Copyright (c) 2005 Boudewijn Rempt <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <limits.h>
+#include <stdlib.h>
+
+#include <config.h>
+#include LCMS_HEADER
+
+#include <tqimage.h>
+
+#include <klocale.h>
+#include <kdebug.h>
+
+#include "kis_color_conversions.h"
+#include "kis_abstract_colorspace.h"
+#include "kis_colorspace_registry.h"
+#include "kis_image.h"
+#include "kis_wet_sticky_colorspace.h"
+#include "kis_integer_maths.h"
+#include "kis_types.h"
+#include "kis_channelinfo.h"
+
+#define NOWSDEBUG
+
+using namespace WetAndSticky;
+
+enum WetStickyChannelIndex {
+ BLUE_CHANNEL_INDEX,
+ GREEN_CHANNEL_INDEX,
+ RED_CHANNEL_INDEX,
+ ALPHA_CHANNEL_INDEX,
+ HUE_CHANNEL_INDEX,
+ SATURATION_CHANNEL_INDEX,
+ LIGHTNESS_CHANNEL_INDEX,
+ LITQUID_CONTENT_CHANNEL_INDEX,
+ DRYING_RATE_CHANNEL_INDEX,
+ MISCIBILITY_CHANNEL_INDEX,
+ GRAVITATIONAL_DIRECTION_INDEX,
+ GRAVITATIONAL_STRENGTH_CHANNEL_INDEX,
+ ABSORBANCY_CHANNEL_INDEX,
+ PAINT_VOLUME_CHANNEL_INDEX
+};
+
+KisWetStickyColorSpace::KisWetStickyColorSpace() :
+ KisAbstractColorSpace(KisID("W&S", i18n("Wet & Sticky")), 0, icMaxEnumData)
+{
+ TQ_INT32 pos = 0;
+
+ // Basic representational definition
+ m_channels.push_back(new KisChannelInfo(i18n("Blue"), "B", pos, COLOR, 1));
+ m_channels.push_back(new KisChannelInfo(i18n("Green"), "G", ++pos, COLOR, 1));
+ m_channels.push_back(new KisChannelInfo(i18n("Red"), "R", ++pos, COLOR, 1));
+ m_channels.push_back(new KisChannelInfo(i18n("Alpha"), "A", ++pos, ALPHA, 1));
+
+ // Paint definition
+ m_channels.push_back(new KisChannelInfo(i18n("Hue"), "H", ++pos, COLOR, sizeof(float)));
+ m_channels.push_back(new KisChannelInfo(i18n("Saturation"), "S", pos+=sizeof(float) , COLOR, sizeof(float)));
+ m_channels.push_back(new KisChannelInfo(i18n("Lightness"), "L", pos+=sizeof(float), COLOR, sizeof(float)));
+
+ m_channels.push_back(new KisChannelInfo(i18n("Liquid Content"), "Q", pos+=sizeof(float), SUBSTANCE, 1));
+ m_channels.push_back(new KisChannelInfo(i18n("Drying Rate"), "D", ++pos, SUBSTANCE, 1));
+ m_channels.push_back(new KisChannelInfo(i18n("Miscibility"), "M", ++pos, SUBSTANCE, 1));
+
+ // Substrate definition
+ m_channels.push_back(new KisChannelInfo(i18n("Gravitational Direction"), "Gd", ++pos, SUBSTRATE, sizeof(enumDirection)));
+ m_channels.push_back(new KisChannelInfo(i18n("Gravitational Strength"), "Gs", pos+=sizeof(enumDirection), SUBSTRATE, 1));
+
+ m_channels.push_back(new KisChannelInfo(i18n("Absorbency"), "Ad", ++pos, SUBSTRATE, 1));
+ m_channels.push_back(new KisChannelInfo(i18n("Paint Volume"), "V", ++pos, SUBSTANCE, 1));
+
+ m_alphaPos = 3;
+ m_alphaSize = 1;
+ setDefaultProfile( 0 );
+
+#ifdef WSDEBUG
+ TQValueVector<KisChannelInfo *>_it it;
+ int i = 0;
+ for (it = m_channels.begin(); it != m_channels.end(); ++it)
+ {
+ KisChannelInfo * ch = (*it);
+ kdDebug(DBG_AREA_CMS) << "Channel: " << ch->name() << ", " << ch->pos() << ", " << i << "\n";
+ ++i;
+ }
+
+ kdDebug(DBG_AREA_CMS) << "Size of cell: " << sizeof(CELL) << "\n";
+#endif
+}
+
+
+KisWetStickyColorSpace::~KisWetStickyColorSpace()
+{
+}
+
+void KisWetStickyColorSpace::fromTQColor(const TQColor& c, TQ_UINT8 *dst, KisProfile * profile)
+{
+ CELL_PTR p = (CELL_PTR) dst;
+ TQ_UINT8 r, g, b;
+
+ r = c.red();
+ g = c.green();
+ b = c.blue();
+
+ p -> red = r;
+ p -> green = g;
+ p -> blue = b;
+ p -> alpha = OPACITY_OPAQUE;
+
+ rgb_to_hls(r, g, b, &p->hue, &p->lightness, &p->saturation);
+
+ p -> liquid_content = 0;
+ p -> drying_rate = 0;
+ p -> miscibility = 0;
+
+ p -> direction = DOWN;
+ p -> strength = 10;
+
+ p -> absorbancy = 10;
+ p -> volume = 0;
+
+#ifdef WSDEBUG
+ kdDebug(DBG_AREA_CMS) << "qcolor: "
+ << " r: " << c.red() << " b: " << c.blue() << " g: " << c.red()
+ << " native color: (" << TQString().setNum(p->red) << ", "
+ << TQString().setNum(p->green) << ", "
+ << TQString().setNum(p->blue) << ", "
+ << TQString().setNum(p->alpha) << ") "
+ << ", hls: (" << p->hue << ", "
+ << p->lightness << ", "
+ << p->saturation << ")\n";
+#endif
+}
+
+void KisWetStickyColorSpace::fromTQColor(const TQColor& c, TQ_UINT8 opacity, TQ_UINT8 *dst, KisProfile * profile)
+{
+ CELL_PTR p = (CELL_PTR) dst;
+ TQ_UINT8 r, g, b;
+
+ r = c.red();
+ g = c.green();
+ b = c.blue();
+
+ p -> red = r;
+ p -> green = g;
+ p -> blue = b;
+ p -> alpha = opacity;
+ rgb_to_hls(r, g, b, &p -> hue, &p -> lightness, &p -> saturation);
+
+ p ->liquid_content = 0;
+ p ->drying_rate = 0;
+ p ->miscibility = 0;
+
+ p -> direction = DOWN;
+ p -> strength = 10;
+
+ p -> absorbancy = 10;
+ p -> volume = 0;
+
+#ifdef WSDEBUG
+ kdDebug(DBG_AREA_CMS) << "qcolor: "
+ << " r: " << c.red() << " b: " << c.blue() << " g: " << c.red() << " opacity: " << opacity
+ << " native color: (" << TQString().setNum(p->red) << ", "
+ << TQString().setNum(p->green) << ", "
+ << TQString().setNum(p->blue) << ", "
+ << TQString().setNum(p->alpha) << ") "
+ << ", hls: (" << p->hue << ", "
+ << p->lightness << ", "
+ << p->saturation << ")\n";
+#endif
+}
+
+void KisWetStickyColorSpace::toTQColor(const TQ_UINT8 *src, TQColor *c, KisProfile * profile)
+{
+ CELL_PTR p = (CELL_PTR) src;
+
+ c -> setRgb(p -> red,
+ p -> green,
+ p -> blue);
+#ifdef WSDEBUG
+ kdDebug(DBG_AREA_CMS) << "Created qcolor from wet & sticky: " << " r: " << c->red() << " b: " << c->blue() << " g: " << c->red() << "\n";
+#endif
+}
+
+void KisWetStickyColorSpace::toTQColor(const TQ_UINT8 *src, TQColor *c, TQ_UINT8 *opacity, KisProfile * profile)
+{
+
+ CELL_PTR p = (CELL_PTR) src;
+
+ c -> setRgb(p -> red,
+ p -> green,
+ p -> blue);
+
+ *opacity = p -> alpha;
+#ifdef WSDEBUG
+ kdDebug(DBG_AREA_CMS) << "Created qcolor from wet & sticky: " << " r: " << c->red() << " b: " << c->blue() << " g: " << c->red() << "\n";
+#endif
+}
+
+
+
+KisPixelRO KisWetStickyColorSpace::toKisPixelRO(const TQ_UINT8 *src, KisProfile * profile)
+{
+ return KisPixelRO (src, src, this, profile);
+}
+
+KisPixel KisWetStickyColorSpace::toKisPixel(TQ_UINT8 *src, KisProfile * profile)
+{
+ return KisPixel (src, src, this, profile);
+}
+
+void KisWetStickyColorSpace::mixColors(const TQ_UINT8 **colors, const TQ_UINT8 *weights, TQ_UINT32 nColors, TQ_UINT8 *dst) const
+{
+}
+
+TQ_UINT8 KisWetStickyColorSpace::getAlpha(const TQ_UINT8 *pixel) const
+{
+ return ((CELL_PTR)pixel)->alpha;
+}
+
+void KisWetStickyColorSpace::setAlpha(TQ_UINT8 * pixels, TQ_UINT8 alpha, TQ_INT32 nPixels) const
+{
+ while (nPixels > 0) {
+ ((CELL_PTR)pixels)->alpha = alpha;
+ --nPixels;
+ pixels+=pixelSize();
+ }
+}
+
+void KisWetStickyColorSpace::applyAlphaU8Mask(TQ_UINT8 * pixels, TQ_UINT8 * alpha, TQ_INT32 nPixels)
+{
+}
+
+void KisWetStickyColorSpace::applyInverseAlphaU8Mask(TQ_UINT8 * pixels, TQ_UINT8 * alpha, TQ_INT32 nPixels)
+{
+}
+
+TQ_UINT8 KisWetStickyColorSpace::scaleToU8(const TQ_UINT8 * srcPixel, TQ_INT32 channelPos)
+{
+ return 0;
+}
+
+TQ_UINT16 KisWetStickyColorSpace::scaleToU16(const TQ_UINT8 * srcPixel, TQ_INT32 channelPos)
+{
+ return 0;
+}
+
+
+TQValueVector<KisChannelInfo *> KisWetStickyColorSpace::channels() const
+{
+ return m_channels;
+}
+
+bool KisWetStickyColorSpace::hasAlpha() const
+{
+ return true;
+}
+
+TQ_INT32 KisWetStickyColorSpace::nChannels() const
+{
+ return 14;
+}
+
+TQ_INT32 KisWetStickyColorSpace::nColorChannels() const
+{
+ return 3;
+}
+
+TQ_INT32 KisWetStickyColorSpace::nSubstanceChannels() const
+{
+ return 4;
+
+}
+
+TQ_INT32 KisWetStickyColorSpace::pixelSize() const
+{
+ return sizeof(CELL);
+}
+
+
+TQImage KisWetStickyColorSpace::convertToTQImage(const TQ_UINT8 *data, TQ_INT32 width, TQ_INT32 height,
+ KisProfile * /*srcProfile*/, KisProfile * /*dstProfile*/,
+ TQ_INT32 /*renderingIntent*/, float /*exposure*/)
+{
+
+ TQImage img(width, height, 32, 0, TQImage::LittleEndian);
+
+ TQ_INT32 i = 0;
+ uchar *j = img.bits();
+
+ CELL_PTR p = (CELL_PTR) data;
+
+ while ( i < width * height) {
+
+ const TQ_UINT8 PIXEL_BLUE = 0;
+ const TQ_UINT8 PIXEL_GREEN = 1;
+ const TQ_UINT8 PIXEL_RED = 2;
+ const TQ_UINT8 PIXEL_ALPHA = 3;
+
+ *( j + PIXEL_ALPHA ) = p -> alpha;
+ *( j + PIXEL_RED ) = p -> red;
+ *( j + PIXEL_GREEN ) = p -> green;
+ *( j + PIXEL_BLUE ) = p -> blue;
+
+ p++;
+ i++;
+ j += 4; // Because we're hard-coded 32 bits deep, 4 bytes
+ }
+ return img;
+}
+
+bool KisWetStickyColorSpace::convertPixelsTo(const TQ_UINT8 * src, KisProfile * /*srcProfile*/,
+ TQ_UINT8 * dst, KisAbstractColorSpace * dstColorSpace, KisProfile * dstProfile,
+ TQ_UINT32 numPixels,
+ TQ_INT32 /*renderingIntent*/)
+{
+ TQ_INT32 dSize = dstColorSpace -> pixelSize();
+ TQ_INT32 sSize = pixelSize();
+
+ TQ_UINT32 j = 0;
+ TQ_UINT32 i = 0;
+ TQColor c;
+ CELL_PTR cp;
+ while ( i < numPixels ) {
+ cp = (CELL_PTR) (src + i);
+
+ c.setRgb(cp -> red,
+ cp -> green,
+ cp -> blue);
+
+ dstColorSpace -> fromTQColor(c, cp -> alpha, (dst + j), dstProfile);
+
+ i += sSize;
+ j += dSize;
+
+ }
+ return true;
+
+}
+
+void KisWetStickyColorSpace::bitBlt(TQ_UINT8 *dst,
+ TQ_INT32 dstRowStride,
+ const TQ_UINT8 *src,
+ TQ_INT32 srcRowStride,
+ const TQ_UINT8 *tqmask,
+ TQ_INT32 tqmaskRowStride,
+ TQ_UINT8 opacity,
+ TQ_INT32 rows,
+ TQ_INT32 cols,
+ const KisCompositeOp& op)
+{
+ switch (op.op()) {
+ case COMPOSITE_UNDEF:
+ // Undefined == no composition
+ break;
+ case COMPOSITE_OVER:
+ compositeOver(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_COPY:
+ default:
+ compositeCopy(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity);
+ break;
+ }
+
+}
+
+
+void KisWetStickyColorSpace::compositeOver(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT8 opacity)
+{
+ // XXX: This is basically the same as with rgb and used to composite layers for Composition for
+ // painting works differently
+
+
+ while (rows > 0) {
+
+ const TQ_UINT8 *src = srcRowStart;
+ TQ_UINT8 *dst = dstRowStart;
+ const TQ_UINT8 *tqmask = tqmaskRowStart;
+
+ TQ_INT32 columns = numColumns;
+
+ while (columns > 0) {
+
+ CELL_PTR dstCell = (CELL_PTR) dst;
+ CELL_PTR srcCell = (CELL_PTR) src;
+
+#ifdef WSDEBUG
+ kdDebug(DBG_AREA_CMS) << "Source: " << rows << ", " << columns << " color: " <<
+ srcCell->red << ", " << srcCell->blue << ", " << srcCell->green << ", " << srcCell->alpha << ", " << srcCell->volume << "\n";
+
+
+ kdDebug(DBG_AREA_CMS) << "Destination: " << rows << ", " << columns << " color: " <<
+ dstCell->red << ", " << dstCell->blue << ", " << dstCell->green << ", " << dstCell->alpha << ", " << dstCell->volume << "\n";
+
+#endif
+
+ TQ_UINT8 srcAlpha = srcCell->alpha;
+
+ // apply the alphatqmask
+ if(tqmask != 0)
+ {
+ if(*tqmask != OPACITY_OPAQUE)
+ srcAlpha = UINT8_MULT(srcAlpha, *tqmask);
+ tqmask++;
+ }
+
+ if (srcAlpha != OPACITY_TRANSPARENT) {
+
+ if (opacity != OPACITY_OPAQUE) {
+ srcAlpha = UINT8_MULT(srcCell->alpha, opacity);
+ }
+
+ if (srcAlpha == OPACITY_OPAQUE) {
+ memcpy(dst, src, 3); // XXX: First three bytes for rgb?
+ } else {
+ TQ_UINT8 dstAlpha = dstCell->alpha;
+
+ TQ_UINT8 srcBlend;
+
+ if (dstAlpha == OPACITY_OPAQUE) {
+ srcBlend = srcAlpha;
+ } else {
+ TQ_UINT8 newAlpha = dstAlpha + UINT8_MULT(OPACITY_OPAQUE - dstAlpha, srcAlpha);
+ dstCell->alpha = newAlpha;
+
+ if (newAlpha != 0) {
+ srcBlend = UINT8_DIVIDE(srcAlpha, newAlpha);
+ } else {
+ srcBlend = srcAlpha;
+ }
+ }
+
+ if (srcBlend == OPACITY_OPAQUE) {
+ memcpy(dst, src, 3); //XXX: First three bytes for rgb?
+ } else {
+ dstCell->red = UINT8_BLEND(srcCell->red, dstCell->red, srcBlend);
+ dstCell->green = UINT8_BLEND(srcCell->green, dstCell->green, srcBlend);
+ dstCell->blue = UINT8_BLEND(srcCell->blue, dstCell->blue, srcBlend);
+ }
+ }
+ }
+ columns--;
+ src += sizeof(CELL);
+ dst += sizeof(CELL);
+ }
+ rows--;
+ srcRowStart += srcRowStride;
+ dstRowStart += dstRowStride;
+
+ if(tqmaskRowStart)
+ tqmaskRowStart += tqmaskRowStride;
+ }
+
+}
+
+void KisWetStickyColorSpace::compositeCopy(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT8 opacity)
+{
+ TQ_INT32 linesize = sizeof(CELL) * columns;
+ TQ_UINT8 *d;
+ const TQ_UINT8 *s;
+ d = dst;
+ s = src;
+
+ while (rows-- > 0) {
+ memcpy(d, s, linesize);
+ d += dstRowStride;
+ s += srcRowStride;
+ }
+
+}
+
+
+KisCompositeOpList KisWetStickyColorSpace::userVisiblecompositeOps() const
+{
+ KisCompositeOpList list;
+
+ list.append(KisCompositeOp(COMPOSITE_OVER));
+
+ return list;
+}
+
+TQString KisWetStickyColorSpace::channelValueText(const TQ_UINT8 *U8_pixel, TQ_UINT32 channelIndex) const
+{
+ Q_ASSERT(channelIndex < nChannels());
+ const CELL *pixel = reinterpret_cast<const CELL *>(U8_pixel);
+
+ switch (channelIndex) {
+ case BLUE_CHANNEL_INDEX:
+ return TQString().setNum(pixel -> blue);
+ case GREEN_CHANNEL_INDEX:
+ return TQString().setNum(pixel -> green);
+ case RED_CHANNEL_INDEX:
+ return TQString().setNum(pixel -> red);
+ case ALPHA_CHANNEL_INDEX:
+ return TQString().setNum(pixel -> alpha);
+ case HUE_CHANNEL_INDEX:
+ return TQString().setNum(pixel -> hue);
+ case SATURATION_CHANNEL_INDEX:
+ return TQString().setNum(pixel -> saturation);
+ case LIGHTNESS_CHANNEL_INDEX:
+ return TQString().setNum(pixel -> lightness);
+ case LITQUID_CONTENT_CHANNEL_INDEX:
+ return TQString().setNum(pixel -> liquid_content);
+ case DRYING_RATE_CHANNEL_INDEX:
+ return TQString().setNum(pixel -> drying_rate);
+ case MISCIBILITY_CHANNEL_INDEX:
+ return TQString().setNum(pixel -> miscibility);
+ case GRAVITATIONAL_DIRECTION_INDEX:
+ {
+ switch (pixel -> direction) {
+ case UP:
+ return i18n("Up");
+ case DOWN:
+ return i18n("Down");
+ case LEFT:
+ return i18n("Left");
+ case RIGHT:
+ return i18n("Right");
+ default:
+ Q_ASSERT(false);
+ return TQString();
+ }
+ }
+ case GRAVITATIONAL_STRENGTH_CHANNEL_INDEX:
+ return TQString().setNum(pixel -> strength);
+ case ABSORBANCY_CHANNEL_INDEX:
+ return TQString().setNum(pixel -> absorbancy);
+ case PAINT_VOLUME_CHANNEL_INDEX:
+ return TQString().setNum(pixel -> volume);
+ default:
+ Q_ASSERT(false);
+ return TQString();
+ }
+}
+
+TQString KisWetStickyColorSpace::normalisedChannelValueText(const TQ_UINT8 *U8_pixel, TQ_UINT32 channelIndex) const
+{
+ Q_ASSERT(channelIndex < nChannels());
+ const CELL *pixel = reinterpret_cast<const CELL *>(U8_pixel);
+
+ //XXX: Are these right?
+
+ switch (channelIndex) {
+ case BLUE_CHANNEL_INDEX:
+ return TQString().setNum(static_cast<float>(pixel -> blue) / UINT8_MAX);
+ case GREEN_CHANNEL_INDEX:
+ return TQString().setNum(static_cast<float>(pixel -> green) / UINT8_MAX);
+ case RED_CHANNEL_INDEX:
+ return TQString().setNum(static_cast<float>(pixel -> red) / UINT8_MAX);
+ case ALPHA_CHANNEL_INDEX:
+ return TQString().setNum(static_cast<float>(pixel -> alpha) / UINT8_MAX);
+ case HUE_CHANNEL_INDEX:
+ return TQString().setNum(pixel -> hue);
+ case SATURATION_CHANNEL_INDEX:
+ return TQString().setNum(pixel -> saturation);
+ case LIGHTNESS_CHANNEL_INDEX:
+ return TQString().setNum(pixel -> lightness);
+ case LITQUID_CONTENT_CHANNEL_INDEX:
+ return TQString().setNum(static_cast<float>(pixel -> liquid_content) / UINT8_MAX);
+ case DRYING_RATE_CHANNEL_INDEX:
+ return TQString().setNum(static_cast<float>(pixel -> drying_rate) / UINT8_MAX);
+ case MISCIBILITY_CHANNEL_INDEX:
+ return TQString().setNum(static_cast<float>(pixel -> miscibility) / UINT8_MAX);
+ case GRAVITATIONAL_DIRECTION_INDEX:
+ {
+ switch (pixel -> direction) {
+ case UP:
+ return i18n("Up");
+ case DOWN:
+ return i18n("Down");
+ case LEFT:
+ return i18n("Left");
+ case RIGHT:
+ return i18n("Right");
+ default:
+ Q_ASSERT(false);
+ return TQString();
+ }
+ }
+ case GRAVITATIONAL_STRENGTH_CHANNEL_INDEX:
+ return TQString().setNum(static_cast<float>(pixel -> strength) / UINT8_MAX);
+ case ABSORBANCY_CHANNEL_INDEX:
+ return TQString().setNum(static_cast<float>(pixel -> absorbancy) / UINT8_MAX);
+ case PAINT_VOLUME_CHANNEL_INDEX:
+ return TQString().setNum(static_cast<float>(pixel -> volume) / UINT8_MAX);
+ default:
+ Q_ASSERT(false);
+ return TQString();
+ }
+}
+
diff --git a/chalk/colorspaces/wetsticky/kis_wet_sticky_colorspace.h b/chalk/colorspaces/wetsticky/kis_wet_sticky_colorspace.h
new file mode 100644
index 00000000..57f3ac70
--- /dev/null
+++ b/chalk/colorspaces/wetsticky/kis_wet_sticky_colorspace.h
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2005 Boudewijn Rempt <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#ifndef KIS_COLORSPACE_WET_STICKY_H_
+#define KIS_COLORSPACE_WET_STICKY_H_
+
+#include <tqcolor.h>
+
+#include "kis_global.h"
+#include "kis_abstract_colorspace.h"
+
+namespace WetAndSticky {
+
+ /**
+ * A color is specified as a vector in HLS space. Hue is a value
+ * in the range 0..360 degrees with 0 degrees being red. Saturation
+ * and Lightness are both in the range [0,1]. A lightness of 0 means
+ * black, with 1 being white. A totally saturated color has saturation
+ * of 1.
+ */
+
+ enum enumDirection {
+ UP,
+ DOWN,
+ LEFT,
+ RIGHT
+ };
+
+ /**
+ * Defines the contents and attributes of a cell on the canvas.
+ */
+ typedef struct cell {
+ TQ_UINT8 blue;
+ TQ_UINT8 green;
+ TQ_UINT8 red;
+ TQ_UINT8 alpha;
+
+ float hue;
+ float saturation;
+ float lightness;
+
+ TQ_UINT8 liquid_content;
+ TQ_UINT8 drying_rate;
+ TQ_UINT8 miscibility;
+
+ enumDirection direction;
+ TQ_UINT8 strength;
+
+ TQ_UINT8 absorbancy; /* How much paint can this cell hold? */
+ TQ_UINT8 volume; /* The volume of paint. */
+
+ } CELL, *CELL_PTR;
+
+
+}
+
+
+
+class KisWetStickyColorSpace : public KisAbstractColorSpace {
+public:
+ KisWetStickyColorSpace();
+ virtual ~KisWetStickyColorSpace();
+
+public:
+
+
+
+ virtual void fromTQColor(const TQColor& c, TQ_UINT8 *dst, KisProfile * profile = 0);
+ virtual void fromTQColor(const TQColor& c, TQ_UINT8 opacity, TQ_UINT8 *dst, KisProfile * profile = 0);
+
+ virtual void toTQColor(const TQ_UINT8 *src, TQColor *c, KisProfile * profile = 0);
+ virtual void toTQColor(const TQ_UINT8 *src, TQColor *c, TQ_UINT8 *opacity, KisProfile * profile = 0);
+
+ virtual TQ_UINT8 getAlpha(const TQ_UINT8 *pixel) const;
+ virtual void setAlpha(TQ_UINT8 * pixels, TQ_UINT8 alpha, TQ_INT32 nPixels) const;
+
+ virtual void applyAlphaU8Mask(TQ_UINT8 * pixels, TQ_UINT8 * alpha, TQ_INT32 nPixels);
+ virtual void applyInverseAlphaU8Mask(TQ_UINT8 * pixels, TQ_UINT8 * alpha, TQ_INT32 nPixels);
+
+ virtual TQ_UINT8 scaleToU8(const TQ_UINT8 * srcPixel, TQ_INT32 channelPos);
+ virtual TQ_UINT16 scaleToU16(const TQ_UINT8 * srcPixel, TQ_INT32 channelPos);
+
+ virtual TQValueVector<KisChannelInfo *> channels() const;
+ virtual bool hasAlpha() const;
+ virtual TQ_INT32 nChannels() const;
+ virtual TQ_INT32 nColorChannels() const;
+ virtual TQ_INT32 nSubstanceChannels() const;
+ virtual TQ_INT32 pixelSize() const;
+
+ virtual TQString channelValueText(const TQ_UINT8 *pixel, TQ_UINT32 channelIndex) const;
+ virtual TQString normalisedChannelValueText(const TQ_UINT8 *pixel, TQ_UINT32 channelIndex) const;
+
+ virtual TQImage convertToTQImage(const TQ_UINT8 *data, TQ_INT32 width, TQ_INT32 height,
+ KisProfile * srcProfile, KisProfile * dstProfile,
+ TQ_INT32 renderingIntent = INTENT_PERCEPTUAL,
+ float exposure = 0.0f);
+
+
+ virtual void mixColors(const TQ_UINT8 **colors, const TQ_UINT8 *weights, TQ_UINT32 nColors, TQ_UINT8 *dst) const;
+ virtual void convolveColors(TQ_UINT8** colors, TQ_INT32* kernelValues, KisChannelInfo::enumChannelFlags channelFlags, TQ_UINT8 *dst, TQ_INT32 factor, TQ_INT32 offset, TQ_INT32 nColors) const;
+ virtual void invertColor(TQ_UINT8 * src, TQ_INT32 nPixels);
+ virtual void darken(const TQ_UINT8 * src, TQ_UINT8 * dst, TQ_INT32 shade, bool compensate, double compensation, TQ_INT32 nPixels) const;
+
+ virtual KisCompositeOpList userVisiblecompositeOps() const;
+
+protected:
+
+ virtual void bitBlt(TQ_UINT8 *dst,
+ TQ_INT32 dstRowSize,
+ const TQ_UINT8 *src,
+ TQ_INT32 srcRowStride,
+ const TQ_UINT8 *srcAlphaMask,
+ TQ_INT32 tqmaskRowStride,
+ TQ_UINT8 opacity,
+ TQ_INT32 rows,
+ TQ_INT32 cols,
+ const KisCompositeOp& op);
+
+
+ virtual bool convertPixelsTo(const TQ_UINT8 * src, KisProfile * srcProfile,
+ TQ_UINT8 * dst, KisAbstractColorSpace * dstColorSpace, KisProfile * dstProfile,
+ TQ_UINT32 numPixels,
+ TQ_INT32 renderingIntent = INTENT_PERCEPTUAL);
+
+
+private:
+
+ void compositeOver(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT8 opacity);
+ void compositeClear(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT8 opacity);
+ void compositeCopy(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT8 opacity);
+
+};
+
+#endif // KIS_COLORSPACE_WET_STICKY_H_
diff --git a/chalk/colorspaces/wetsticky/kis_ws_engine_filter.cc b/chalk/colorspaces/wetsticky/kis_ws_engine_filter.cc
new file mode 100644
index 00000000..040d3002
--- /dev/null
+++ b/chalk/colorspaces/wetsticky/kis_ws_engine_filter.cc
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2005 Boudewijn Rempt ([email protected])
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#include <stdlib.h>
+#include <vector>
+#include <math.h>
+
+#include <tqpoint.h>
+#include <tqspinbox.h>
+#include <tqrect.h>
+#include <tqcolor.h>
+
+#include <klocale.h>
+#include <kiconloader.h>
+#include <kinstance.h>
+#include <kmessagebox.h>
+#include <kstandarddirs.h>
+#include <ktempfile.h>
+#include <kdebug.h>
+#include <kgenericfactory.h>
+#include <knuminput.h>
+
+#include <kis_debug_areas.h>
+#include <kis_image.h>
+#include <kis_iterators_pixel.h>
+#include <kis_layer.h>
+#include <kis_filter_registry.h>
+#include <kis_debug_areas.h>
+#include <kis_types.h>
+#include <kis_paint_device.h>
+#include <kis_colorspace_registry.h>
+
+#include "kis_ws_engine_filter.h"
+#include "kis_wet_sticky_colorspace.h"
+
+/**
+ * The Wet & Sticky Engine filter is based on the wet & sticky model
+ * for computer painting designed by Tunde Cockshott and implemented
+ * by David England and Kevin Waite.
+ *
+ * The filter implements the engine that moves the paint according to
+ * gravity, viscosity and absorbency.
+ *
+ */
+KisWSEngineFilter::KisWSEngineFilter() : KisFilter(id(), "", i18n("&Wet & Sticky paint engine..."))
+{
+}
+
+
+/**
+ * Sets the POINT giving the coordinate location of the next
+ * cell on the canvas to be visited. There is an even probability
+ * of each cell being visited.
+ */
+TQPoint next_cell(TQ_UINT32 width, TQ_UINT32 height)
+{
+ return TQPoint(random() * width, random() * height);
+}
+
+void single_step(KisColorSpace * cs, KisPaintDeviceSP src, KisPaintDeviceSP dst, const TQRect & rect, bool native)
+{
+ using namespace WetAndSticky;
+
+
+ TQPoint p = next_cell( rect.width(), rect.height() );
+
+ // XXX: We could optimize by randomly doing lines of 64 pixels
+ // -- maybe that would be enough to avoid the windscreen wiper
+ // effect.
+ KisHLineIterator iter = src -> createHLineIterator(p.x(), p.y(), 1, false);
+
+ TQ_UINT8 *orig = iter.rawData();
+ TQ_UINT8 *pix = orig;
+
+ if (!orig) return;
+
+ if (!native ) {
+ TQColor c;
+ TQ_UINT8 opacity;
+
+ src -> colorSpace() -> toTQColor(pix, &c, &opacity);
+ TQ_UINT8 *pix = new TQ_UINT8[sizeof( cell )];
+ Q_CHECK_PTR(pix);
+
+ cs -> fromTQColor(c, opacity, pix);
+ }
+
+ // Process
+
+ CELL_PTR c = ( CELL_PTR )pix;
+
+
+ if ( !native ) {
+ // Set RGBA back
+ }
+
+}
+
+void KisWSEngineFilter::process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration* configuration, const TQRect& rect)
+{
+
+ m_src = src;
+ m_dst = dst;
+ m_cfg = ( KisWSEngineFilterConfiguration * )configuration;
+ m_rect = rect;
+
+
+ kdDebug(DBG_AREA_FILTERS) << "WSEnginefilter called!\n";
+ TQTime t;
+ t.restart();
+
+ // Two possibilities: we have our own, cool w&s pixel, and
+ // then we have real data to mess with, or we're filtering a
+ // boring shoup-model paint device and we can only work by
+ // synthesizing w&s pixels.
+ bool native = false;
+ // XXX: We need a better way to ID color strategies
+ if ( src -> colorSpace() -> id() == KisID("W&S","") ) native = true;
+
+ // XXX: We need a better way to ID color strategies
+ KisColorSpace * cs = KisColorSpaceRegistry::instance()->get("W&S");
+
+ TQ_UINT32 pixels = 400; //m_cfg -> pixels();
+
+ kdDebug(DBG_AREA_FILTERS) << "Going to singlestep " << pixels << " pixels.\n";
+
+ // Determine whether we want an infinite loop
+ if ( pixels == 0 ) {
+ while ( true )
+ single_step (cs, src, dst, rect, native);
+ }
+ // Or not.
+ else {
+ for ( TQ_UINT32 i = 0; i < pixels; ++i ) {
+ single_step (cs, src, dst, rect, native);
+ }
+ }
+ kdDebug(DBG_AREA_FILTERS) << "Done in " << t.elapsed() << " ms\n";
+
+}
+
+KisFilterConfigWidget * KisWSEngineFilter::createConfigurationWidget(TQWidget* tqparent, KisPaintDeviceSP dev)
+{
+// KisWSEngineFilterConfigurationWidget* kefcw = new KisWSEngineFilterConfigurationWidget(this,tqparent, "");
+// kdDebug(DBG_AREA_FILTERS) << kefcw << endl;
+// return kefcw ;
+ return 0;
+}
+
+KisFilterConfiguration* KisWSEngineFilter::configuration(TQWidget* nwidget, KisPaintDeviceSP dev)
+{
+// KisWSEngineFilterConfigurationWidget* widget = (KisWSEngineFilterConfigurationWidget*) nwidget;
+
+// if( widget == 0 )
+// {
+// return new KisWSEngineFilterConfiguration(30);
+// } else {
+// TQ_UINT32 depth = widget -> baseWidget() -> depthSpinBox -> value();
+
+// return new KisWSEngineFilterConfiguration(depth);
+// }
+
+
+ return new KisWSEngineFilterConfiguration( m_rect.height() * m_rect.width() );
+}
+
diff --git a/chalk/colorspaces/wetsticky/kis_ws_engine_filter.h b/chalk/colorspaces/wetsticky/kis_ws_engine_filter.h
new file mode 100644
index 00000000..d1c23810
--- /dev/null
+++ b/chalk/colorspaces/wetsticky/kis_ws_engine_filter.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2005 Boudewijn Rempt ([email protected])
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#ifndef _KIS_WS_ENGINE_FILTER_H_
+#define _KIS_WS_ENGINE_FILTER_H_
+
+#include <kdebug.h>
+
+#include <kis_view.h>
+#include <kis_filter.h>
+#include <kis_id.h>
+
+class KisWSEngineFilterConfiguration : public KisFilterConfiguration
+{
+
+public:
+
+ KisWSEngineFilterConfiguration() { m_pixels = 10000; }
+
+ KisWSEngineFilterConfiguration(TQ_UINT32 pixels = 0) { m_pixels = pixels; }
+
+ TQ_UINT32 pixels() { return m_pixels; }
+
+private:
+
+ TQ_UINT32 m_pixels; // The number of pixels the filter should
+ // move. 0 means keep running indefinitely
+
+
+
+};
+
+class KisWSEngineFilter : public KisFilter
+{
+
+public:
+
+ KisWSEngineFilter();
+
+ virtual void process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration* cfg, const TQRect& rc);
+
+ static inline KisID id() { return KisID("Wet & Sticky Engine", i18n("Wet & Sticky")); };
+ virtual bool supportsPainting() { return false; }
+ virtual bool supportsPreview() { return false; }
+ virtual bool supportsIncrementalPainting() { return false; }
+
+public:
+ virtual KisFilterConfigWidget * createConfigurationWidget(TQWidget* tqparent, KisPaintDeviceSP dev);
+ virtual KisFilterConfiguration* configuration(TQWidget*, KisPaintDeviceSP dev);
+
+
+private:
+
+private:
+
+ KisWSEngineFilterConfiguration * m_cfg;
+ KisPaintDeviceSP m_src;
+ KisPaintDeviceSP m_dst;
+ TQRect m_rect;
+
+};
+
+#endif // _KIS_WS_ENGINE_FILTER_H_
diff --git a/chalk/colorspaces/wetsticky/wet_sticky_plugin.cc b/chalk/colorspaces/wetsticky/wet_sticky_plugin.cc
new file mode 100644
index 00000000..525b18bb
--- /dev/null
+++ b/chalk/colorspaces/wetsticky/wet_sticky_plugin.cc
@@ -0,0 +1,60 @@
+/*
+ * wet_sticky_plugin.cc -- Part of Chalk
+ *
+ * Copyright (c) 2005 Boudewijn Rempt ([email protected])
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#include <klocale.h>
+#include <kiconloader.h>
+#include <kinstance.h>
+#include <kmessagebox.h>
+#include <kstandarddirs.h>
+#include <ktempfile.h>
+#include <kdebug.h>
+#include <kgenericfactory.h>
+
+#include <kis_colorspace_registry.h>
+#include <kis_debug_areas.h>
+#include "wet_sticky_plugin.h"
+
+#include "kis_wet_sticky_colorspace.h"
+#include "kis_ws_engine_filter.h"
+
+typedef KGenericFactory<WetStickyPlugin> WetStickyPluginFactory;
+K_EXPORT_COMPONENT_FACTORY( chalkwsplugin, WetStickyPluginFactory( "chalkcore" ) )
+
+
+WetStickyPlugin::WetStickyPlugin(TQObject *tqparent, const char *name, const TQStringList &)
+ : KParts::Plugin(tqparent, name)
+{
+ setInstance(WetStickyPluginFactory::instance());
+
+ // This is not a gui plugin; only load it when the doc is created.
+ if ( tqparent->inherits("KisFactory") )
+ {
+ KisColorSpace * colorSpaceWS = new KisWetStickyColorSpace();
+ Q_CHECK_PTR(colorSpaceWS);
+ KisColorSpaceRegistry::instance() -> add(colorSpaceWS);
+ KisFilterRegistry::instance()->add(new KisWSEngineFilter());
+ }
+
+}
+
+WetStickyPlugin::~WetStickyPlugin()
+{
+}
+
+#include "wet_sticky_plugin.moc"
diff --git a/chalk/colorspaces/wetsticky/wet_sticky_plugin.h b/chalk/colorspaces/wetsticky/wet_sticky_plugin.h
new file mode 100644
index 00000000..fe981a59
--- /dev/null
+++ b/chalk/colorspaces/wetsticky/wet_sticky_plugin.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2005 Boudewijn Rempt ([email protected])
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef WET_STICKY_PLUGIN_H_
+#define WET_STICKY_PLUGIN_H_
+
+#include <kparts/plugin.h>
+
+/**
+ * A plugin wrapper around the Wet & Sticky colour space strategy.
+ *
+ * The Wet & Sticky paint system was first designed in 1991 by Tunde Cockshott
+ * and was further developed by David England and Kevin Waite. It was released
+ * under the GPL in 2005.
+ *
+ */
+class WetStickyPlugin : public KParts::Plugin
+{
+ Q_OBJECT
+ TQ_OBJECT
+public:
+ WetStickyPlugin(TQObject *tqparent, const char *name, const TQStringList &);
+ virtual ~WetStickyPlugin();
+
+};
+
+#endif // WET_STICKY_PLUGIN_H_
diff --git a/chalk/colorspaces/wetsticky/ws/GNU b/chalk/colorspaces/wetsticky/ws/GNU
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/chalk/colorspaces/wetsticky/ws/GNU
diff --git a/chalk/colorspaces/wetsticky/ws/GNU Public Licence.txt b/chalk/colorspaces/wetsticky/ws/GNU Public Licence.txt
new file mode 100644
index 00000000..5e79907b
--- /dev/null
+++ b/chalk/colorspaces/wetsticky/ws/GNU Public Licence.txt
@@ -0,0 +1,341 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which tqcontains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it tqcontains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
+
diff --git a/chalk/colorspaces/wetsticky/ws/README b/chalk/colorspaces/wetsticky/ws/README
new file mode 100644
index 00000000..15f55e77
--- /dev/null
+++ b/chalk/colorspaces/wetsticky/ws/README
@@ -0,0 +1,4 @@
+
+The gear example
+
+This example program demonstrates how to use OpenGL display lists.
diff --git a/chalk/colorspaces/wetsticky/ws/TODO b/chalk/colorspaces/wetsticky/ws/TODO
new file mode 100644
index 00000000..91c48a03
--- /dev/null
+++ b/chalk/colorspaces/wetsticky/ws/TODO
@@ -0,0 +1,24 @@
+1/ Load in portable pixmaps (PPM). Set an arbitrary paint attribute
+map for each different colour. Otherwise load in a paint attribute
+map definition file.
+2/ Input from "brush". Incremental development of brush input.
+First simple mixing then
+empty brush moving paint
+paint on top of paint
+attribute application.
+3/ Animation
+1000000 = 1 fps
+500000 = 2 fps
+250000 = 4 fps
+125000 = 8 fps
+62500 = 16 fps
+41660 = 24 fps
+
+4/ NK times 178.9 real 49.4 user 13.3 sys
+ Orig times 636.6 real 111.1 user 43.6 sys
+
+5/ Cross section through volume
+
+6/ Separate Colour scale window
+
+7/ Transparency
diff --git a/chalk/colorspaces/wetsticky/ws/after.jpg b/chalk/colorspaces/wetsticky/ws/after.jpg
new file mode 100644
index 00000000..5116efdb
--- /dev/null
+++ b/chalk/colorspaces/wetsticky/ws/after.jpg
Binary files differ
diff --git a/chalk/colorspaces/wetsticky/ws/anim.c b/chalk/colorspaces/wetsticky/ws/anim.c
new file mode 100644
index 00000000..995a3dff
--- /dev/null
+++ b/chalk/colorspaces/wetsticky/ws/anim.c
@@ -0,0 +1,154 @@
+/*
+ FILE: x_interface.c
+ PURPOSE: Creation and access to an X windows interface
+ to wet+sticky using Athena Widgets
+ AUTHOR: David England
+ VERSION: 1.00 (13-May-91)
+
+Copyright 1991, 1992, 2002, 2003 Tunde Cockshott, Kevin Waite, David England.
+
+Contact David England [email protected]
+School of Computing and Maths Sciences,
+Liverpool John Moores University
+Liverpool L3 3AF
+United Kingdom
+Phone +44 151 231 2271
+
+Wet and Sticky is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Wet and Sticky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Wet and Sticky; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+*/
+
+#define FRAME_LIMIT 36
+
+#include <X11/Xos.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Intrinsic.h>
+
+#include <X11/cursorfont.h>
+#include <X11/StringDefs.h>
+
+#include <X11/Shell.h>
+#include <X11/Xaw/Box.h>
+#include <X11/Xaw/Label.h>
+#include <stdio.h>
+
+#include "constants.h"
+#include "types.h"
+
+#include "engine.h"
+#include "canvas.h"
+
+/* Window Heirarchy -
+ Three shell widgets, one for colour output, two for attributes
+output
+ plus a back_up pixmap for redrawing
+*/
+
+static Widget top_level;
+static Widget colour_shell;
+static Widget colour_box;
+static Widget colour_canvas;
+static Pixmap colour_pm[FRAME_LIMIT];
+
+static GC gc;
+static GC tmp_gc;
+static long tqmask;
+static XGCValues values;
+
+Display *display;
+char pix_file[32];
+unsigned int delay;
+
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ static Arg args[]={
+ {XtNwidth, (XtArgVal) 0},
+ {XtNheight, (XtArgVal)0} };
+
+ XEvent event;
+ int i, width, height;
+ int ret;
+ int c;
+
+ extern char *optarg;
+ extern int optind;
+
+ width = 300;
+ height = 300;
+
+ args[0].value = (XtArgVal)width;
+
+ args[1].value = (XtArgVal)height;
+
+ top_level = XtInitialize("wet+sticky", "Wet+Sticky", NULL,
+ 0, &argc, argv);
+
+ delay = 100000; /*default delay in microseconds between frames */
+
+ while ((c = getopt(argc, argv, "D:")) != -1)
+ switch (c) {
+ case 'D':
+ delay = atoi(optarg);
+ delay = delay * 1000000;
+ break;
+ }
+
+
+ display = XtDisplay(top_level);
+
+ colour_shell = XtCreateApplicationShell("colour_frame",
+ topLevelShellWidgetClass, NULL, 0);
+
+ colour_box = XtCreateManagedWidget("colour_box", boxWidgetClass,
+ colour_shell, NULL, 0);
+
+
+ colour_canvas = XtCreateManagedWidget("", labelWidgetClass,
+ colour_box, args, XtNumber(args));
+
+
+ /*XtAddEventHandler(colour_canvas, ExposureMask, False,
+ expose_event, 0);*/
+
+ XtRealizeWidget(colour_shell);
+
+ XSynchronize(display, True);
+
+ tqmask = GCBackground| GCForeground| GCFunction;
+
+ values.function = GXcopy;
+ values.background = 0;
+ values.foreground = 1;
+
+
+ gc = XtGetGC(colour_canvas, tqmask, &values);
+
+
+
+ fprintf(stderr,"Read files ...");
+ for (i=0; i < FRAME_LIMIT; i++) {
+ sprintf(pix_file,"pixmap.%d",i);
+ if ((XReadBitmapFile(display, XtWindow(colour_shell), pix_file,
+ &width, &height, &colour_pm[i], &ret, &ret)) !=
+ BitmapSuccess)
+ perror("bad bitmap");
+ }
+ fprintf(stderr,"done.\nBegin Animation\n");
+
+
+ for (;;) {
+ for (i=0; i < FRAME_LIMIT; i++) {
+ XCopyPlane(display, colour_pm[i],
+ XtWindow(colour_canvas),gc,
+ 0, 0, 300, 300, 0, 0, 1);
+ fprintf(stderr,"pre sleep\n");
+ usleep(delay);
+ }
+
+
+ } /* End for loop */
+}xk
+
diff --git a/chalk/colorspaces/wetsticky/ws/before.jpg b/chalk/colorspaces/wetsticky/ws/before.jpg
new file mode 100644
index 00000000..fc26b989
--- /dev/null
+++ b/chalk/colorspaces/wetsticky/ws/before.jpg
Binary files differ
diff --git a/chalk/colorspaces/wetsticky/ws/canvas.c b/chalk/colorspaces/wetsticky/ws/canvas.c
new file mode 100644
index 00000000..77cfa17d
--- /dev/null
+++ b/chalk/colorspaces/wetsticky/ws/canvas.c
@@ -0,0 +1,514 @@
+/*
+ FILE: canvas.c
+ PURPOSE: Hides the canvas and provides its access and
+ manipuation routines.
+ AUTHOR: Kevin Waite
+ VERSION: 1.00 (10-May-91)
+
+Copyright 1991, 1992, 2002, 2003 Tunde Cockshott, Kevin Waite, David England.
+
+Contact David England [email protected]
+School of Computing and Maths Sciences,
+Liverpool John Moores University
+Liverpool L3 3AF
+United Kingdom
+Phone +44 151 231 2271
+
+Wet and Sticky is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Wet and Sticky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Wet and Sticky; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+*/
+
+#include "constants.h"
+#include "types.h"
+#include "canvas.h"
+#include <stdio.h>
+
+/* Declare the canvas data structure local to this module. It can
+ only be accessed via routines given in the header file for this module.
+ The (0,0) location for the canvas is at the top-left. */
+
+CELL canvas[CANVAS_WIDTH][CANVAS_HEIGHT];
+
+/* This module maintains a list of the addresses of cells that have
+ been modified since the last redraw and therefore need updating.
+ Points are added to this list by the need_to_tqrepaint() routine
+ and are removed by the next_cell_for_tqrepaint() function. The
+ pointer to the current tail of the list is updated by side-effect. */
+
+static POINT need_tqrepainting[REDRAW_LIMIT];
+static int next_free = 0;
+static int next_to_tqrepaint = 0;
+
+/* *********************************************************************** */
+
+int number_of_tqrepaints_needed()
+/* Returns the number of cells that need to be tqrepainted. */
+
+{
+ return (next_free);
+}
+
+/* *********************************************************************** */
+
+void need_to_tqrepaint(point)
+/* The cell at this location needs to be redrawn since it has
+ been altered. Scan the list to see if it is already
+ scheduled for a tqrepainting operation and only add it if
+ it is not there. */
+
+POINT point;
+
+{
+ int k;
+
+
+ /* If the list is already full then simply ignore the tqrepaint
+ request - it will get done eventually anyway. */
+
+ if (next_free == REDRAW_LIMIT) return;
+
+ /* Check whether this point is already on the list. */
+
+ for (k=0; k < next_free; k++) {
+ if ((need_tqrepainting[k].x == point.x) &&
+ (need_tqrepainting[k].y == point.y)) break;
+ }
+
+ if (k < next_free) return; /* Already in the list. */
+
+ /* Add this new cell address to the end of the list. */
+
+ need_tqrepainting[next_free].x = point.x;
+ need_tqrepainting[next_free].y = point.y;
+ next_free++;
+}
+
+/* *********************************************************************** */
+
+void next_cell_for_tqrepaint(cell, locus)
+/* This routine returns the next cell to be tqrepainted, together with its
+ location on the canvas. This is determined by taking the next point
+ from the need_tqrepainting list and accessing its cell. If the list is
+ empty then return NIL.
+ Note that the tqrepainting operation will clear out the list before
+ any other new positions are added. */
+
+ CELL_PTR *cell;
+ POINT_PTR locus;
+
+{
+ if (next_to_tqrepaint >= next_free) {
+ next_to_tqrepaint = next_free = 0;
+ *(cell) = NIL;
+ return;
+ }
+
+ *(cell) = get_cell(need_tqrepainting[next_to_tqrepaint]);
+ locus->x = need_tqrepainting[next_to_tqrepaint].x;
+ locus->y = need_tqrepainting[next_to_tqrepaint].y;
+ next_to_tqrepaint++;
+}
+
+/* *********************************************************************** */
+
+void next_cell_point (address)
+/* Sets the POINT giving the coordinate location of the next
+ cell on the canvas to be visited. There is an even probability
+ of each cell being visited. */
+
+POINT_PTR address;
+{
+ extern long random();
+
+ address->x = random() % CANVAS_WIDTH;
+ address->y = random() % CANVAS_HEIGHT;
+}
+
+
+/* *********************************************************************** */
+
+CELL_PTR get_cell (point)
+/* This function returns a pointer to the cell at the
+ given address on the canvas. */
+
+POINT point;
+
+{
+ return (&canvas[point.x][point.y]);
+}
+
+/* *********************************************************************** */
+
+DIRECTION anti_clockwise_from (arrow)
+/* Returns the direction found going anti-clockwise from the
+ given direction. */
+
+DIRECTION arrow;
+
+{
+ switch (arrow) {
+
+ case NORTH: return(WEST);
+ case EAST: return(NORTH);
+ case SOUTH: return(EAST);
+ case WEST: ;
+
+ }
+ return(SOUTH);
+}
+
+/* *********************************************************************** */
+
+DIRECTION clockwise_from (arrow)
+/* Returns the direction found going clockwise from the
+ given direction. */
+
+DIRECTION arrow;
+
+{
+ switch (arrow) {
+
+ case NORTH: return(EAST);
+ case EAST: return(SOUTH);
+ case SOUTH: return(WEST);
+ case WEST: ;
+
+ }
+ return(NORTH);
+}
+
+/* *********************************************************************** */
+
+BOOLEAN neighbour (aPoint, direction, bPoint)
+/* Set bPoint to the coordinate of the point that can
+ be found by going one place in the given direction
+ from aPoint. The direction can be NORTH, EAST, WEST
+ or SOUTH. If bPoint will be off the canvas then the
+ function returns FALSE otherwise TRUE. */
+
+POINT aPoint;
+POINT_PTR bPoint;
+DIRECTION direction;
+
+{
+ int x, y;
+
+ switch (direction) {
+
+ case NORTH: x = 0; y = -1; break;
+ case EAST: x = 1; y = 0; break;
+ case SOUTH: x = 0; y = 1; break;
+ case WEST: x = -1; y = 0; break;
+ }
+
+ bPoint->x = aPoint.x + x;
+ bPoint->y = aPoint.y + y;
+
+ if ((bPoint->x >= CANVAS_WIDTH) || (bPoint->x < 0) ||
+ (bPoint->y >= CANVAS_HEIGHT) || (bPoint->y < 0)) return(FALSE);
+
+ return(TRUE);
+}
+
+/* *********************************************************************** */
+
+void initialise_paint (paint)
+/* Set this paint to be a dry, unmixing white. */
+
+PAINT_PTR paint;
+
+{
+ paint->colour.hue = 255;
+ paint->colour.saturation = 0.0;
+ paint->colour.lightness = 1.0;
+ paint->liquid_content = 0;
+ paint->drying_rate = 0;
+ paint->miscibility = 0;
+}
+
+/* *********************************************************************** */
+
+void initialise_cell(cell)
+/* Reset the given cell to a default value. */
+
+CELL_PTR cell;
+
+{
+ initialise_paint (&cell->contents);
+
+ cell->volume = UNFILLED; /* Indicates that no paint has yet been applied.
+*/
+ cell->absorbancy = 10;
+ cell->gravity.direction = SOUTH;
+ cell->gravity.strength = DEFAULT_GRAVITY_STRENGTH;
+}
+
+
+/* *********************************************************************** */
+
+void split_gravity()
+/* This routine is for test purposes only. It causes the right
+ half of the canvas to have gravity going NORTH with the left
+ half having gravity going SOUTH. */
+
+{
+ POINT p;
+ CELL_PTR cell;
+
+ /*for (p.x=CANVAS_WIDTH/2; p.x < CANVAS_WIDTH; p.x++) {*/
+ for (p.x=165; p.x < CANVAS_WIDTH; p.x++) {
+ for (p.y=0; p.y < CANVAS_HEIGHT; p.y++) {
+ cell = get_cell (p);
+ cell->gravity.direction = NORTH;
+ }
+ }
+}
+
+/* *********************************************************************** */
+
+void initialise_canvas()
+/* Before it can be used the canvas needs to be initialised to
+ a default state. This involves setting each of the cells to
+ have no paint and for gravity to be uniformly down. Each cell
+ has the default absorbancy value. */
+
+{
+ POINT p;
+ CELL_PTR cell;
+
+ for (p.x=0; p.x < CANVAS_WIDTH; p.x++) {
+ for (p.y=0; p.y < CANVAS_HEIGHT; p.y++) {
+ cell = get_cell (p);
+ initialise_cell (cell);
+ }
+ }
+}
+
+/* *********************************************************************** */
+
+void print_cell_attributes(cell)
+CELL_PTR cell;
+{
+ printf("Volume = %d\n", cell->volume);
+
+ printf("Liquid content = %d%%\n", cell->contents.liquid_content);
+ printf("Drying rate = %d%%\n", cell->contents.drying_rate);
+ printf("Miscibility = %d%%\n\n", cell->contents.miscibility);
+
+ printf("Saturation = %2f\n", cell->contents.colour.saturation);
+ printf("Lightness = %2f\n", cell->contents.colour.lightness);
+ printf("Hue = %d\n", cell->contents.colour.hue);
+ printf ("------------------------------\n\n");
+}
+
+/* *********************************************************************** */
+
+void blob_cell_alpha (cell)
+CELL_PTR cell;
+
+{
+ cell->contents.liquid_content = 100;
+ cell->contents.drying_rate = 10;
+ cell->contents.miscibility = 80;
+
+ cell->contents.colour.hue = 20;
+ cell->contents.colour.saturation = 1.0;
+ cell->contents.colour.lightness = 0.0;
+
+ cell->volume = 50;
+
+}
+
+/* *********************************************************************** */
+
+void blob_cell_beta (cell)
+CELL_PTR cell;
+
+{
+ cell->contents.liquid_content = 80;
+ cell->contents.drying_rate = 20;
+ cell->contents.miscibility = 90;
+
+ cell->contents.colour.hue = 70;
+ cell->contents.colour.saturation = 1.0;
+ cell->contents.colour.lightness = 0.7;
+
+ cell->volume = 30;
+
+}
+/* *********************************************************************** */
+
+void blob_cell_gamma (cell)
+CELL_PTR cell;
+
+{
+ cell->contents.liquid_content = 80;
+ cell->contents.drying_rate = 40;
+ cell->contents.miscibility = 80;
+
+ cell->contents.colour.hue = 100;
+ cell->contents.colour.saturation = 0.5;
+ cell->contents.colour.lightness = 0.4;
+
+ cell->volume = 50;
+
+}
+
+/* *********************************************************************** */
+
+void old_blob(width)
+/* This routine puts a square blob of various paints
+ of the given side length centred on the canvas.
+ This is used for test purposes. */
+
+int width;
+
+{
+ int count, lump, startx, starty, x, y;
+
+ width = (width > CANVAS_WIDTH) ? CANVAS_WIDTH : width;
+ width = (width > CANVAS_HEIGHT) ? CANVAS_HEIGHT : width;
+
+ printf("This run used a square blob of side %d pixels\n", width);
+ printf ("centred on the canvas. The blob was split into three equal\n");
+ printf ("vertical strips with the following paint attributes:\n\n");
+
+ startx = (CANVAS_WIDTH - width) / 2;
+ starty = (CANVAS_HEIGHT - width) / 2;
+ lump = width / 3;
+
+ count=0;
+ for (x = startx; x < startx + width; x++) {
+ for (y = starty; y < starty + width; y++) {
+ switch (count / lump) {
+
+ case 0: blob_cell_alpha (&canvas[x][y]); break;
+ case 1: blob_cell_beta (&canvas[x][y]); break;
+ default: blob_cell_gamma (&canvas[x][y]); break;
+
+ }
+ }
+ count++;
+ }
+ split_gravity();
+
+ print_cell_attributes (&canvas[startx][starty]);
+ print_cell_attributes (&canvas[startx + lump][starty]);
+ print_cell_attributes (&canvas[startx + (2*lump)][starty]);
+}
+
+gravity_set(x,y,x1,y1,attr)
+int x;
+int y;
+int x1;
+int y1;
+int attr;
+{
+ /* set the canavs absorbancy and gravity to various test values
+ in the region (x,y),(x1,y1)
+ */
+
+ int i,j;
+
+ for (i=x; i < x1; i++ )
+ for (j=y; j < y1; j++) {
+ canvas[i][j].absorbancy = 10; /* default 10 */
+ canvas[i][j].gravity.direction = SOUTH;
+ canvas[i][j].gravity.strength = DEFAULT_GRAVITY_STRENGTH;
+ /*DEFAULT_GRAVITY_STRENGTH*/
+ }
+}
+
+blob_set(x, y, x1, y1, attr)
+int x;
+int y;
+int x1;
+int y1;
+int attr;
+{
+ /* Set a blob of paint in the rectangle (x,y),(x1,y1) with
+ the attribute, attr (can be volume, liquidity or dryness*/
+ int i,j;
+ float colour;
+
+ colour = (3.6 * 122);
+ colour = 64;
+ fprintf(stderr, "attribute value %d %d\n", attr, (int)colour);
+
+
+ for (i=x; i < x1; i++ )
+ for (j=y; j < y1; j++) {
+ canvas[i][j].contents.liquid_content = 80;
+ canvas[i][j].contents.drying_rate = 50;
+ canvas[i][j].contents.miscibility = 80;
+
+ canvas[i][j].contents.colour.hue = (int)colour;
+ canvas[i][j].contents.colour.saturation = 1.0;
+ canvas[i][j].contents.colour.lightness = 0.7;
+
+ canvas[i][j].volume = attr;
+ }
+
+
+}
+
+void blob(type)
+int type;
+{
+
+ /* paint nine test blobs on the canvas */
+
+ /* X Example 1 All attributes at 80% except vol 0 - 100%*/
+
+ /* X Example 2 All attributes at 80% except liq 0 - 100% */
+
+ /* X Example 3 All attributes at 80% except dry 0 - 100% */
+
+ /* X Example 4 All attributes at 80% except absorp 100 - 0% */
+
+ /* X Example 5 All attributes at 80% except gravity 0 - 100% */
+
+ /* X Example 6 All attributes at 80% except direction N,S,E & W */
+
+ blob_set(20, 20, 80, 80, 0);
+ gravity_set(0, 0, 100, 100, SOUTH);
+
+ blob_set(120,20, 180, 80, 22);
+ gravity_set(150, 0, 300, 150, EAST);
+
+ blob_set(220,20,280,80,33);
+ gravity_set(0, 150, 150, 300, NORTH);
+
+ blob_set(20,120,80,180,44);
+ gravity_set(150, 150, 300, 300, WEST);
+
+ blob_set(120,120,180,180,55);
+ gravity_set(100, 100, 200, 200, 55);
+
+ blob_set(220,120, 280,180, 66);
+ gravity_set(200, 100, 300, 200, 66);
+
+ blob_set(20,220,80,280,77);
+ gravity_set(0, 200, 100, 300, 77);
+
+ blob_set(120,220,180,280,88);
+ gravity_set(100, 200, 200, 300, 88);
+
+ blob_set(220,220,280,280, 100);
+ gravity_set(200, 200, 300, 300, 100);
+
+}
+
+void
+load_file(filename, width, height)
+char *filename;
+int *width;
+int *height;
+{
+
+ /* Load in a file using the load_ppm_format() function
+ This loads in a file in Portable Pixmap format
+ */
+
+ load_ppm_format(filename, canvas, width, height);
+}
diff --git a/chalk/colorspaces/wetsticky/ws/canvas.h b/chalk/colorspaces/wetsticky/ws/canvas.h
new file mode 100644
index 00000000..c2f2bcbf
--- /dev/null
+++ b/chalk/colorspaces/wetsticky/ws/canvas.h
@@ -0,0 +1,70 @@
+/*
+ FILE: canvas.h
+ PURPOSE: Defines the public routines for manipulating the canvas.
+ AUTHOR: Kevin Waite
+ VERSION: 1.00 (10-May-91)
+
+Copyright 1991, 1992, 2002, 2003 Tunde Cockshott, Kevin Waite, David England.
+
+Contact David England [email protected]
+School of Computing and Maths Sciences,
+Liverpool John Moores University
+Liverpool L3 3AF
+United Kingdom
+Phone +44 151 231 2271
+
+Wet and Sticky is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Wet and Sticky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Wet and Sticky; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA
+
+*/
+
+
+extern int number_of_tqrepaints_needed();
+/* Returns the number of cells needing to tqrepainted. */
+
+extern void need_to_tqrepaint (/* POINT */);
+/* Requests that the cell at the given point be tqrepainted
+ at the next update as it has been modified. */
+
+extern void next_cell_for_tqrepaint (/* *CELL_PTR, POINT_PTR */);
+/* Returns a pointer to a cell that needs to be updated as well
+ as the location of that cell on the canvas. If there are
+ no more cells to be redrawn then the pointer will be NIL. */
+
+extern void next_cell_point (/* POINT_PTR */);
+/* Sets the POINT giving the coordinate location of the next
+ cell on the canvas to be visited. There is an even probability
+ of each cell being visited. */
+
+extern CELL_PTR get_cell (/* POINT */);
+/* This function returns a pointer to the cell at the
+ given address on the canvas. */
+
+extern DIRECTION anti_clockwise_from (/* DIRECTION */);
+/* Returns the direction found going clockwise from the
+ given direction. */
+
+extern DIRECTION clockwise_from (/* DIRECTION */);
+/* Returns the direction found going clockwise from the
+ given direction. */
+
+extern BOOLEAN neighbour (/* POINT, DIRECTION, POINT_PTR */);
+/* Set bPoint to the coordinate of the point that can
+ be found by going one place in the given direction
+ from aPoint. The direction can be NORTH, EAST, WEST
+ or SOUTH. If bPoint will be off the canvas then the
+ function returns FALSE otherwise TRUE. */
+
+extern void initialise_canvas();
+/* Before it can be used the canvas needs to be initialised to
+ a default state. This involves setting each of the cells to
+ have no paint and for gravity to be uniformly down. Each cell
+ has the default absorbancy value. */
+
+extern void blob( /* int */);
+/* This routine puts a square blob of black paint
+ of the given side length centred on the canvas.
+ This is used for test purposes. */
+
+extern void load_file(/*char *, int *, int * */);
+/* Load a file from a portable pixmap into the canvas */
diff --git a/chalk/colorspaces/wetsticky/ws/cmap.c b/chalk/colorspaces/wetsticky/ws/cmap.c
new file mode 100644
index 00000000..0f11eaf7
--- /dev/null
+++ b/chalk/colorspaces/wetsticky/ws/cmap.c
@@ -0,0 +1,681 @@
+/*
+ FILE: x_interface.c
+ PURPOSE: Creation and access to an X windows interface
+ to wet+sticky using Athena Widgets
+ AUTHOR: David England
+ VERSION: 1.00 (13-May-91)
+
+Copyright 1991, 1992, 2002, 2003 Tunde Cockshott, Kevin Waite, David England.
+
+Contact David England [email protected]
+School of Computing and Maths Sciences,
+Liverpool John Moores University
+Liverpool L3 3AF
+United Kingdom
+Phone +44 151 231 2271
+
+Wet and Sticky is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Wet and Sticky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Wet and Sticky; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+*/
+
+#include <X11/Xos.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Intrinsic.h>
+
+#include <X11/cursorfont.h>
+#include <X11/StringDefs.h>
+
+#include <X11/Shell.h>
+#include <X11/Xaw/Box.h>
+#include <X11/Xaw/Label.h>
+#include <stdio.h>
+
+#include "constants.h"
+#include "types.h"
+#include "engine.h"
+#include "canvas.h"
+
+/* Window Heirarchy -
+ Three shell widgets, one for colour output, two for attributes output
+ plus a back_up pixmap for redrawing
+*/
+
+static Widget top_level;
+static Widget colour_shell;
+static Widget colour_box;
+static Widget colour_canvas;
+static Pixmap colour_pm;
+
+static Widget volume_shell;
+static Widget volume_box;
+static Widget volume_canvas;
+static Pixmap volume_pm;
+
+static Widget dryness_shell;
+static Widget dryness_box;
+static Widget dryness_canvas;
+static Pixmap dryness_pm;
+
+static GC gc;
+static GC tmp_gc;
+static long tqmask;
+static XGCValues values;
+
+static Colormap cmap;
+static XColor colours[256];
+void stroke();
+void stroke_motion();
+
+Display *display;
+int screen;
+Screen *screen_ptr;
+Window root;
+
+static int count=0;
+static int frame_count=0;
+char pix_file[64];
+
+void StartWindow();
+void StartUpWindows();
+
+static XtEventHandler
+expose_event(w, event)
+Widget w;
+XEvent *event;
+{
+/* Re-display the colour window if an exposure event is received */
+int width, height;
+
+ width = height = 300;
+
+ XCopyArea(XtDisplay(colour_canvas), colour_pm,
+ XtWindow(colour_canvas), gc, 0, 0, width, height, 0,0);
+
+}
+
+
+static void
+expose_volume(w, event)
+Widget w;
+XEvent *event;
+{
+/* Re-display the volume window if an exposure event is received */
+int width, height;
+
+ width = height = 300;
+
+ XCopyArea(XtDisplay(volume_canvas), volume_pm,
+ XtWindow(volume_canvas), gc, 0, 0, width, height, 0,0);
+
+
+}
+
+static void
+expose_dryness(w, event)
+Widget w;
+XEvent *event;
+{
+/* Re-display the dryness window if an exposure event is received */
+int width, height;
+
+ width = height = 300;
+
+ XCopyArea(XtDisplay(dryness_canvas), dryness_pm,
+ XtWindow(dryness_canvas), gc, 0, 0, width, height, 0,0);
+
+
+}
+
+int
+GetHueValue(red, green, blue)
+int red;
+int green;
+int blue;
+{
+ XColor colour;
+
+ colour.red = red * 257;
+ colour.green = green * 257;
+ colour.blue = blue * 257;
+ colour.flags = DoRed | DoGreen | DoBlue;
+
+ if (XAllocColor(display, cmap, &colour) == 0)
+ fprintf(stderr,"colour allocation failed\n");
+
+ return (colour.pixel);
+}
+
+
+void
+DrawPoint(x,y,colour)
+int x;
+int y;
+int colour;
+/* Draw a point on the window and the back-up Pixmap */
+{
+ XSetForeground(XtDisplay(top_level), gc, colours[colour].pixel);
+
+ XDrawPoint(XtDisplay(top_level), XtWindow(colour_canvas), gc, x, y);
+ XDrawPoint(XtDisplay(top_level), colour_pm, gc, x, y);
+}
+
+int
+DrawVolumePoint(x,y,attr)
+int x;
+int y;
+int attr;
+/* Draw a point on the window and the back-up Pixmap */
+{
+ /* later - use the range of the volume to affect the colour
+ value
+ */
+
+ if (XtWindow(volume_canvas) == NULL)
+ return (-1);
+
+ XSetForeground(XtDisplay(top_level), gc, colours[attr].pixel);
+
+ XDrawPoint(XtDisplay(top_level), XtWindow(volume_canvas), gc, x, y);
+ XDrawPoint(XtDisplay(top_level), volume_pm, gc, x, y);
+
+ return(0);
+}
+
+int
+DrawDrynessPoint(x,y,attr)
+int x;
+int y;
+int attr;
+/* Draw a point on the window and the back-up Pixmap */
+{
+ /* later - use the range of the dryness to affect the colour
+ value
+ */
+
+ if (XtWindow(dryness_canvas) == NULL)
+ return (-1);
+
+ XSetForeground(XtDisplay(top_level), gc, colours[attr].pixel);
+
+ XDrawPoint(XtDisplay(top_level), XtWindow(dryness_canvas), gc, x, y);
+ XDrawPoint(XtDisplay(top_level), dryness_pm, gc, x, y);
+
+ return(0);
+}
+
+void
+ClearWindow()
+{
+ XClearWindow(XtDisplay(top_level), XtWindow(colour_canvas));
+}
+
+static void
+CleanWindow(win)
+Drawable win;
+/* Fill a window with a solid, white rectangle */
+{
+XGCValues values;
+long tqmask;
+
+ values.background = colours[0].pixel;
+ values.foreground = colours[255].pixel;;
+ values.fill_style = FillSolid;
+ values.function = GXclear;
+
+
+ tqmask = GCBackground| GCForeground| GCFillStyle | GCFunction;
+
+ tmp_gc = XtGetGC(top_level, tqmask, &values);
+
+ XFillRectangle(XtDisplay(top_level), win, tmp_gc, 0, 0, 300, 300);
+
+}
+
+void SetupCmap()
+{
+int i;
+
+ for (i=0;i<256;i++) {
+ colours[i].red = i*257;
+ colours[i].flags = DoRed | DoBlue | DoGreen;
+ }
+
+ /* for (i=0;i<=127;i++)
+ colours[i].green = i*2*257;
+
+ for (i=128;i>0;i--)
+ colours[255-i].green = (i-1)*2*257;*/
+
+ for (i=0;i<64;i++)
+ colours[i].green = i*4*257;
+
+ for (i=64;i<128;i++)
+ colours[i].green = 65536-i*4*257;
+
+ for (i=128;i<192;i++)
+ colours[i].green = (i-128)*2*257;
+
+ for (i=192;i<255;i++)
+ colours[i].green = 65536-(i-128)*2*257;
+
+
+ for (i=0;i<256;i++)
+ colours[i].blue = 65536 - i*257;
+
+ colours[0].red = 65535;
+ colours[0].green = 65535;
+ colours[0].blue = 65535;
+}
+
+void
+SetupGreyMap()
+{
+int i;
+
+ for (i=0;i<256;i++) {
+ colours[i].red = i*257;
+ colours[255 - i].flags = DoRed | DoBlue | DoGreen;
+ }
+
+
+ for (i=0;i<256;i++)
+ colours[i].green = i*257;
+
+ for (i=0;i<256;i++)
+ colours[i].blue = i*257;
+
+ colours[255].red = 255*257;
+ colours[255].green = 255*257;
+ colours[255].blue = 255*257;
+
+}
+
+
+main(argc, argv)
+int argc;
+char **argv;
+/* Create colour window heirarchy and add event handlers */
+{
+
+ static Arg args[]={
+ {XtNwidth, (XtArgVal) 0},
+ {XtNheight, (XtArgVal)0} };
+
+int width;
+int height;
+ int i;
+
+
+ width = 300;
+ height = 300;
+
+ args[0].value = (XtArgVal)width;
+
+ args[1].value = (XtArgVal)height;
+
+ top_level = XtInitialize("wet+sticky", "Wet+Sticky", NULL,
+ 0, &argc, argv);
+
+
+ display = XtDisplay(top_level);
+ screen = DefaultScreen(display);
+ screen_ptr = ScreenOfDisplay(display, DefaultScreen(display));
+
+ root = RootWindow(display, screen);
+
+ colour_shell = XtCreateApplicationShell("colour_frame",
+ topLevelShellWidgetClass, NULL, 0);
+
+
+
+ colour_box = XtCreateManagedWidget("colour_box", boxWidgetClass,
+ colour_shell, NULL, 0);
+
+
+ colour_canvas = XtCreateManagedWidget("", labelWidgetClass,
+ colour_box, args, XtNumber(args));
+
+
+ XtAddEventHandler(colour_canvas, ExposureMask, False, expose_event, 0);
+
+ XtAddEventHandler(colour_canvas, ButtonPressMask, False, stroke, 0);
+
+ XtAddEventHandler(colour_canvas, Button1MotionMask,
+ False, stroke_motion, 0);
+
+ XtRealizeWidget(colour_shell);
+
+ cmap = XCreateColormap( display, XtWindow(colour_shell),
+ XDefaultVisualOfScreen(screen_ptr), AllocAll);
+
+ for (i=0; i <= 255; i++)
+ colours[i].pixel = i;
+
+ XQueryColors(display, DefaultColormapOfScreen(screen_ptr),colours, 256);
+
+ /*SetupCmap();*/
+
+ SetupGreyMap();
+
+ XStoreColors(display, cmap, colours, 256);
+
+ i=0;
+ while( XAllocColorCells( display, DefaultColormapOfScreen(screen_ptr),
+ True, NULL, 0, &colours[i].pixel, 1 ) ) {
+ colours[i].pixel = i;
+ i++;
+ }
+
+ XSetWindowColormap(display, XtWindow(colour_shell), cmap);
+
+ XInstallColormap(display, cmap);
+
+ tqmask = GCBackground| GCForeground| GCFunction;
+
+ values.function = GXcopy;
+ values.background = colours[0].pixel;
+ values.foreground = colours[255].pixel;
+
+
+ gc = XtGetGC(colour_canvas, tqmask, &values);
+
+ colour_pm = XCreatePixmap(XtDisplay(top_level),
+ XtWindow(colour_shell), width, height,
+ XDefaultDepth(XtDisplay(top_level), 0));
+
+ CleanWindow(colour_pm);
+
+ StartWindow (CANVAS_WIDTH, CANVAS_HEIGHT);
+
+ StartUpWindows();
+}
+
+
+void StartWindow(width, height)
+int width;
+int height;
+/* Create Volume heirarchy and add event handlers */
+{
+ static Arg args[]={
+ {XtNwidth, (XtArgVal) 0},
+ {XtNheight, (XtArgVal)0} };
+
+ args[0].value = (XtArgVal)width;
+
+ args[1].value = (XtArgVal)height;
+
+ volume_shell = XtCreateApplicationShell("volume_frame",
+ topLevelShellWidgetClass, NULL, 0);
+
+ volume_box = XtCreateManagedWidget("volume_box", boxWidgetClass,
+ volume_shell, NULL, 0);
+
+ volume_canvas = XtCreateManagedWidget("", labelWidgetClass,
+ volume_box, args, XtNumber(args));
+
+ XtAddEventHandler(volume_canvas, ExposureMask, False,
+ expose_volume, 0);
+
+ XtRealizeWidget(volume_shell);
+
+ XSetWindowColormap(display, XtWindow(volume_shell), cmap);
+
+ volume_pm = XCreatePixmap(XtDisplay(top_level),
+ XtWindow(colour_shell), width, height,
+ XDefaultDepth(XtDisplay(top_level), 0));
+
+ CleanWindow(volume_pm);
+
+
+}
+
+void StartDrynessWindow(width, height)
+int width;
+int height;
+/* Create dryness heirarchy and add event handlers */
+{
+ static Arg args[]={
+ {XtNwidth, (XtArgVal) 0},
+ {XtNheight, (XtArgVal)0} };
+
+ args[0].value = (XtArgVal)width;
+
+ args[1].value = (XtArgVal)height;
+
+ dryness_shell = XtCreateApplicationShell("dryness_frame",
+ topLevelShellWidgetClass, NULL, 0);
+
+ dryness_box = XtCreateManagedWidget("dryness_box", boxWidgetClass,
+ dryness_shell, NULL, 0);
+ dryness_canvas
+= XtCreateManagedWidget("", labelWidgetClass,
+ dryness_box, args, XtNumber(args));
+
+ XtAddEventHandler(dryness_canvas, ExposureMask, False,
+ expose_dryness, 0);
+
+ XtRealizeWidget(dryness_shell);
+
+ XSetWindowColormap(display, XtWindow(dryness_shell), cmap);
+
+ dryness_pm = XCreatePixmap(XtDisplay(top_level),
+ XtWindow(colour_shell), width, height,
+ XDefaultDepth(XtDisplay(top_level), 0));
+
+ CleanWindow(dryness_pm);
+
+}
+
+static void
+draw_labels()
+{
+ XSetForeground(XtDisplay(colour_shell), gc, colours[1].pixel);
+
+ XDrawString(XtDisplay(colour_shell), XtWindow(colour_canvas), gc, 10, 10,
+ "Colour", strlen("Colour"));
+ XDrawString(XtDisplay(colour_shell), colour_pm, gc, 10, 10,
+ "Colour", strlen("Colour"));
+
+ XSetForeground(XtDisplay(colour_shell), gc, colours[128].pixel);
+
+ XDrawString(XtDisplay(colour_shell), XtWindow(volume_canvas), gc, 10, 10,
+ "Volume", strlen("Volume"));
+ XDrawString(XtDisplay(colour_shell), volume_pm, gc, 10, 10,
+ "Volume", strlen("Volume"));
+
+ XSetForeground(XtDisplay(colour_shell), gc, colours[255].pixel);
+
+ XDrawString(XtDisplay(colour_shell), XtWindow(dryness_canvas), gc, 10, 10,
+ "Bump Map", strlen("Bump Map"));
+ XDrawString(XtDisplay(colour_shell), dryness_pm, gc, 10, 10,
+ "Bump Map", strlen("Bump Map"));
+}
+
+void paint_cell(cell, x, y)
+CELL_PTR cell;
+int x, y;
+
+{
+ int colour, volColour, dryness;
+ POINT p;
+
+ p.x = x;
+ p.y = y;
+
+ /* The current display simply maps hue onto the indices of the colour
+ table. This involves some scaling since hues are in the range [0,360)
+ with the colour table being [0,256). */
+
+ colour = (int) (cell->contents.colour.hue *
+ ((float) MAX_COLOUR_INDEX / 360.0));
+
+ /*DrawPoint(x,y,colour); */
+
+ /* volColour is an index into the colour table in the range [0,255].
+ It is used to give a false colour image of the canvas's volume. */
+
+ /*if (x < SCALE_WIDTH) return; Don't draw over colour scale. */
+
+ volColour = MIN(cell->volume * 2, 255);
+ volColour = MAX(volColour, 0);
+ /* Make unfilled cells have a zero vol. */
+
+ /*DrawVolumePoint(x,y,volColour);*/
+
+ /* Dryness will be in the range [0,255]. */
+ dryness = (cell->contents.liquid_content * 255) / 100;
+
+ /*DrawDrynessPoint(x,y,dryness);*/
+}
+
+
+
+void draw_false_colour_scale()
+/* This routine places a scale along the top of the volume window
+ showing the colours being used. Low is at the left edge.
+ The colour palette has indices 0..255. */
+{
+ int x, y;
+
+ /*for (x=0; x < 255; x++)
+ for (y=0; y < SCALE_WIDTH; y++) DrawVolumePoint(x,y,MIN(x, 255));*/
+}
+
+
+void draw_full_canvas()
+{
+ int x, y;
+ CELL_PTR cell;
+ POINT p;
+
+ if (DEBUG) {
+ printf ("Starting to paint full canvas...");
+ fflush(stdout);
+ }
+
+ for (x=0; x < CANVAS_WIDTH; x++) {
+ for (y=0; y < CANVAS_HEIGHT; y++) {
+ p.x = x;
+ p.y = y;
+ /*cell = get_cell(p);*/
+ paint_cell(cell, x, y);
+ }
+ }
+ draw_false_colour_scale();
+ if (DEBUG) printf ("done.\n");
+}
+
+void
+bump_map()
+{
+ POINT p;
+ CELL_PTR cell;
+ register int x, y;
+ register int colour;
+
+
+ for (x=0; x < CANVAS_WIDTH; x++) {
+ for (y=0; y < CANVAS_HEIGHT; y++) {
+ p.x = x;
+ p.y = y;
+ /*cell = get_cell(p);*/
+ /*colour = (int) new_intensity_value(p);*/
+
+/* colour = (int) (cell->contents.colour.hue *
+ ((float) MAX_COLOUR_INDEX / 360.0));*/
+ DrawDrynessPoint(x,y,colour);
+ }
+ }
+
+}
+
+
+void evolve_paint()
+{
+
+}
+
+
+
+void StartUpWindows()
+{
+/* Start the X windows event loop and paint processing */
+XEvent event;
+
+
+
+ for (;;) {
+ if (XtPending()) {
+ XtNextEvent(&event);
+ XtDispatchEvent(&event);
+ }
+ else {
+ /* Evolve paint and re-display*/
+ evolve_paint();
+ }
+
+ } /* End for loop */
+
+
+}
+
+void
+stroke(w, client_data, event)
+Widget w;
+caddr_t client_data;
+XEvent *event;
+{
+/* brush_stroke(event->xbutton.x, event->xbutton.y);*/
+
+
+ /*if ((XEvent *)event != (XEvent *)NULL)
+ else
+ printf("Null event\n"); */
+
+/* DrawPoint(event->xbutton.x, event->xbutton.y, 128);
+ DrawVolumePoint(event->xbutton.x, event->xbutton.y, 128);
+ DrawDrynessPoint(event->xbutton.x, event->xbutton.y, 128);*/
+
+
+ XSetForeground(XtDisplay(top_level), gc, colours[128].pixel);
+
+ XFillRectangle(XtDisplay(top_level), XtWindow(colour_canvas), gc,
+ event->xmotion.x, event->xmotion.y ,1, 1);
+
+ XFillRectangle(XtDisplay(top_level), XtWindow(volume_canvas), gc,
+ event->xmotion.x, event->xmotion.y ,1, 1);
+
+ /*XFillRectangle(XtDisplay(top_level), XtWindow(dryness_canvas), gc,
+ event->xmotion.x, event->xmotion.y ,1, 1);*/
+
+ /*brush_stroke(event->xbutton.x, event->xbutton.y);*/
+}
+
+
+void
+stroke_motion(w, client_data, event)
+Widget w;
+caddr_t client_data;
+XEvent *event;
+{
+
+
+ /*if ((XEvent *)event != (XEvent *)NULL)
+ else
+ printf("Null event\n"); */
+
+
+ XSetForeground(XtDisplay(top_level), gc, colours[128].pixel);
+
+ XFillRectangle(XtDisplay(top_level), XtWindow(colour_canvas), gc,
+ event->xmotion.x, event->xmotion.y ,1, 1);
+ XFillRectangle(XtDisplay(top_level), XtWindow(volume_canvas), gc,
+ event->xmotion.x, event->xmotion.y ,1, 1);
+
+ XFillRectangle(XtDisplay(top_level), XtWindow(dryness_canvas), gc,
+ event->xmotion.x, event->xmotion.y ,1, 1);
+
+ /*brush_stroke(event->xbutton.x, event->xbutton.y);*/
+}
+
diff --git a/chalk/colorspaces/wetsticky/ws/constants.h b/chalk/colorspaces/wetsticky/ws/constants.h
new file mode 100644
index 00000000..fa72bc92
--- /dev/null
+++ b/chalk/colorspaces/wetsticky/ws/constants.h
@@ -0,0 +1,69 @@
+/*
+ FILE: constants.h
+ PURPOSE: Constains all the #DEFINES for Wet&Sticky.
+ AUTHORS: Kevin Waite and David England
+ VERSION: 1.00 (10-May-91)
+
+Copyright 1991, 1992, 2002, 2003 Tunde Cockshott, Kevin Waite, David England.
+
+Contact David England [email protected]
+School of Computing and Maths Sciences,
+Liverpool John Moores University
+Liverpool L3 3AF
+United Kingdom
+Phone +44 151 231 2271
+
+Wet and Sticky is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Wet and Sticky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Wet and Sticky; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA
+
+*/
+
+/* Some utility constants. */
+
+#define TRUE 1
+#define FALSE 0
+#define YES 1
+#define NO 0
+#define NIL 0
+#define DEBUG 1
+#define VERSION "1.0"
+
+/* Define the constants for colours in the HLS space. */
+
+#define UNFILLED -1
+#define MAX_COLOUR_INDEX 255
+
+
+/* Define the dimensions of the intelligent canvas. */
+
+#define CANVAS_WIDTH 300
+#define CANVAS_HEIGHT 300
+#define SCALE_WIDTH 30
+
+
+/* Define constants that control the evolution of the paint. */
+
+#define STEP_LIMIT 200
+#define REDRAW_LIMIT 500
+
+
+/* Define some constants used in testing the system. */
+
+#define DEFAULT_BLOB_SIZE (CANVAS_WIDTH / 3)
+#define BLOB_NAME "-blob"
+
+
+/* Constants used in modelling gravity. */
+
+#define NORTH 0
+#define EAST 1
+#define SOUTH 2
+#define WEST 3
+
+#define DEFAULT_GRAVITY_STRENGTH 10
+
+
+/* Define some macros. */
+
+#define MAX(A,B) ((A) > (B) ? (A) : (B))
+#define MIN(A,B) ((A) < (B) ? (A) : (B))
diff --git a/chalk/colorspaces/wetsticky/ws/engine.c b/chalk/colorspaces/wetsticky/ws/engine.c
new file mode 100644
index 00000000..2fb4917e
--- /dev/null
+++ b/chalk/colorspaces/wetsticky/ws/engine.c
@@ -0,0 +1,802 @@
+/*
+ FILE: engine.c
+ PURPOSE: Defines the routines for the Paint Engine.
+ AUTHOR: Kevin Waite
+ VERSION: 1.00 (10-May-91)
+
+Copyright 1991, 1992, 2002, 2003 Tunde Cockshott, Kevin Waite, David England.
+
+Contact David England [email protected]
+School of Computing and Maths Sciences,
+Liverpool John Moores University
+Liverpool L3 3AF
+United Kingdom
+Phone +44 151 231 2271
+
+Wet and Sticky is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Wet and Sticky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Wet and Sticky; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+*/
+
+#include "constants.h"
+#include "types.h"
+#include "canvas.h"
+#include <math.h>
+
+extern double HEIGHT_SCALE;
+
+/* *********************************************************************** */
+
+int random_percent()
+/* This function returns a random number in the range [0,100]. */
+{
+ extern long random();
+
+ return (random() % 101);
+}
+
+/* *********************************************************************** */
+
+BOOLEAN allow_event_based_on(value)
+/* The given value is a percentage. Compare this value
+ with a randomly generated percentage and if it is larger
+ then allow the event to happen (i.e. return TRUE) other-
+ wise return FALSE. */
+
+int value;
+
+{
+ if (value > random_percent()) return(TRUE);
+ return(FALSE);
+}
+
+/* *********************************************************************** */
+
+BOOLEAN age_paint(cell)
+/* Make the paint in the given cell older, i.e. let
+ if dry out a bit if it isn't already dry. This
+ function returns TRUE if the paint was already
+ dry or becomes so, and FALSE otherwise. */
+
+CELL_PTR cell;
+
+{
+ if (cell->volume == 0) return(TRUE);
+ if (cell->contents.liquid_content == 0) return(TRUE);
+ if (allow_event_based_on(cell->contents.drying_rate) == TRUE)
+ cell->contents.liquid_content--;
+
+ if (cell->contents.liquid_content == 0) return(TRUE);
+ return(FALSE);
+}
+
+/* *********************************************************************** */
+
+BOOLEAN similar_paint(aPaint, bPaint)
+/* Determine whether the two paints are similar. It is
+ assumed that aPaint has come from the host cell (and
+ so it is its miscibility value that is used). The
+ function returns TRUE if the paints are similar and
+ FALSE otherwise. */
+
+PAINT aPaint, bPaint;
+
+{
+ int delta;
+
+ delta = abs(aPaint.liquid_content - bPaint.liquid_content);
+ if (delta <= aPaint.miscibility) return(TRUE);
+ return(FALSE);
+}
+
+/* *********************************************************************** */
+
+int surplus_paint(cell)
+/* Returns the amount of paint held by this cell greater than its
+ absorbancy value. This is the amount of paint that can flow. */
+
+CELL_PTR cell;
+
+{
+ return (MAX(cell->volume - cell->absorbancy, 0));
+}
+
+/* *********************************************************************** */
+
+BOOLEAN has_surplus_paint(cell)
+/* Does the given cell have excess paint, i.e. can paint flow out
+ of this cell. Return TRUE if it can and FALSE otherwise. */
+
+CELL_PTR cell;
+
+{
+ if (surplus_paint(cell) > 0) return(TRUE);
+ return(FALSE);
+}
+
+/* *********************************************************************** */
+
+void stop() { /* Used for breakpointing. */ }
+
+void donate_paint(source, srcLocus, amount, dest, destLocus)
+/* The source cell is donating the specified volume of its paint
+ to the destination cell. The destination cell must mix this
+ new paint with its existing paint to yield a new paint.
+ This routine is also responsible for recording which cells
+ have been updated and so need tqrepainting.
+
+ A special case is recognised where the destination has not yet
+ had any paint applied. This causes the donated paint to become
+ to new contents of this cell.
+
+*/
+
+CELL_PTR source, dest;
+POINT srcLocus, destLocus;
+int amount;
+
+{
+ float delta, ratio;
+ int iDelta;
+
+ source->volume -= amount;
+
+ if (dest->volume == UNFILLED) {
+
+ /* The donated paint is going into an unfilled cell.
+ Copy the source's attributes into the destination. */
+
+ dest->volume = amount;
+ dest->contents.colour.hue = source->contents.colour.hue;
+ dest->contents.colour.lightness = source->contents.colour.lightness;
+ dest->contents.colour.saturation = source->contents.colour.saturation;
+ dest->contents.liquid_content = source->contents.liquid_content;
+ dest->contents.miscibility = source->contents.miscibility;
+ dest->contents.drying_rate = source->contents.drying_rate;
+
+ } else {
+
+ /* Need to mix the existing paint in the dest with this amount
+ of new paint from the source. This is done using a linear
+ interpolation mechanism using the relative amounts of the
+ paint as the control. */
+
+ if (dest->volume != 0)
+ ratio = amount / (float)(dest->volume);
+
+ iDelta = source->contents.colour.hue - dest->contents.colour.hue;
+ if (iDelta != 0) {
+ dest->contents.colour.hue += (int)(ratio * iDelta);
+ if (dest->contents.colour.hue >= 360)
+ dest->contents.colour.hue -= 360;
+ }
+
+ iDelta = source->contents.drying_rate - dest->contents.drying_rate;
+ dest->contents.drying_rate += (int)((int)ratio * iDelta);
+ dest->contents.drying_rate %= 101;
+
+ iDelta = source->contents.liquid_content - dest->contents.liquid_content;
+ dest->contents.liquid_content += (int)(ratio * iDelta);
+ dest->contents.liquid_content %= 101;
+
+ iDelta = source->contents.miscibility - dest -> contents.miscibility;
+ dest->contents.miscibility += (int)(ratio * iDelta);
+ dest->contents.miscibility %= 101;
+
+ delta = source -> contents.colour.saturation - dest -> contents.colour.saturation;
+ dest -> contents.colour.saturation += ratio * delta;
+
+ delta = source->contents.colour.lightness - dest->contents.colour.lightness;
+ dest->contents.colour.lightness += ratio * delta;
+
+ dest->volume += amount; /* The new volume of paint in dest. */
+
+ }
+
+ need_to_tqrepaint(destLocus);
+}
+
+/* *********************************************************************** */
+
+void handle_surface_tension(cell, locus)
+/* This routine handles the surface tension around the given cell.
+*/
+
+CELL_PTR cell;
+POINT locus;
+
+{
+ DIRECTION direction[3];
+ POINT loci[3];
+ CELL_PTR buddy[3];
+ BOOLEAN ok, similar[3];
+ int weakCount, weak[3], count[3], excess, chosen, side, start, finish,
+k, lowest;
+
+ if (has_surplus_paint(cell) == FALSE) return;
+
+ direction[0] = cell->gravity.direction;
+ direction[1] = clockwise_from(direction[0]);
+ direction[2] = anti_clockwise_from(direction[0]);
+
+ for (k=0; k < 3; k++) {
+ ok = neighbour(locus, direction[k], &loci[k]);
+ if (ok == TRUE) {
+ buddy[k] = get_cell(loci[k]);
+ count[k] = 0;
+ } else count[k] = -1;
+ }
+
+ for (k=0; k < 3; k++)
+ similar[k] = (count[k] == -1)
+ ? FALSE
+ : similar_paint(cell->contents, buddy[k]->contents);
+
+ for (k=0; k < 3; k++) {
+ if ((count[k] != -1) && (similar[k] == FALSE)) {
+ count[k] = 0;
+ start = MAX(k-1, 0);
+ finish = MIN(k+1, 2);
+ for (side=start; side <= finish; side++)
+ if ((count[side] != -1) && (similar[side] == FALSE)) count[k]++;
+
+ }
+ }
+
+ lowest = 4;
+ for (k=0; k < 3; k++) if (count[k] >= 0) lowest = MIN(count[k], lowest);
+
+ weakCount = 0;
+ for (k=0; k < 3; k++) if (count[k] == lowest) weak[weakCount++] = k;
+
+ /* The weak array now holds weakCount indices of those sides that have
+ the lowest surface tension and therefore where any paint would flow over.
+ Now it is necessary to see whether paint will actually flow based on
+ a probability level using the liquidity and volume of the paint in the
+ cell as parameters. Paint will flow over only one of the weakest sides
+ with the side chosen at random. */
+
+ if (random_percent() > cell->contents.liquid_content) return; /* Too
+viscous. */
+
+ excess = surplus_paint(cell);
+ if (random_percent() > excess * 3) return;
+ /* The '3' in the previous statement is an empirically-derived multiplier.
+*/
+
+ /* The paint will flow. Pick one of the weakest sides at random. */
+
+ chosen = weak[random_percent() % weakCount];
+ donate_paint(cell, locus, (excess / 2), buddy[chosen], loci[chosen]);
+}
+
+/* *********************************************************************** */
+
+BOOLEAN diffuse_paint(cell, locus)
+/* Diffuse paint among the neighbours of the given cell.
+ If this cell does not have surplus paint then return
+ TRUE otherwise return FALSE. */
+
+CELL_PTR cell;
+POINT locus;
+
+{
+ extern long random();
+ DIRECTION down, direction;
+ CELL_PTR buddy;
+ POINT nlocus;
+ BOOLEAN ok;
+ int excess;
+
+ if (has_surplus_paint(cell) == FALSE) return(TRUE);
+
+ down = cell->gravity.direction;
+ direction = ((random() & 01) == 0)
+ ? clockwise_from(down)
+ : anti_clockwise_from(down);
+
+ ok = neighbour(locus, direction, &nlocus);
+ if (ok == FALSE) return(TRUE);
+
+ buddy = get_cell(nlocus);
+
+ if (similar_paint(cell->contents, buddy->contents) == FALSE) {
+ handle_surface_tension(cell, locus);
+ return(FALSE);
+ }
+
+ if (buddy->volume >= cell->volume) return(FALSE);
+
+ if (allow_event_based_on(cell->contents.liquid_content) == FALSE)
+ return(FALSE);
+
+ /* Transfer one particle of paint from cell to its buddy. */
+
+ excess = (cell->volume - buddy->volume) / 2;
+ donate_paint(cell, locus, excess, buddy, nlocus);
+ return(FALSE);
+}
+
+/* *********************************************************************** */
+
+BOOLEAN apply_gravity(cell, locus)
+/* Subject the contents of the given cell to the effects
+ of gravity. Note that the direction of gravity is local
+ to the given cell. Locus is the address of this cell.
+ This function returns TRUE if the paint in this cell
+ cannot flow and FALSE otherwise.
+*/
+
+CELL_PTR cell;
+POINT locus;
+
+{
+ extern long random();
+ POINT downhill;
+ CELL_PTR down;
+ BOOLEAN ok, can_flow;
+ int barrier, excess;
+
+ ok = neighbour(locus, cell->gravity.direction, &downhill);
+ if (ok == FALSE) return(TRUE); /* At bottom of canvas. */
+
+ down = get_cell(downhill);
+
+ can_flow = down->volume < (cell->volume + cell->gravity.strength)
+ ? TRUE : FALSE;
+
+ if (can_flow == FALSE) return(TRUE);
+
+ /* Although this paint can flow introduce a random value that
+ uses the viscosity of the paint to determine whether it does
+ actually flow. */
+
+ barrier = random() % 10;
+ if (cell->contents.liquid_content > barrier) {
+ /* Paint is actually moving. Move half of the excess downward. */
+
+ excess = (cell->volume - cell->absorbancy) / 2;
+ donate_paint(cell, locus, excess, down, downhill);
+ }
+
+ return(FALSE);
+}
+
+
+float lx, ly, lz;
+
+void
+compute_shade_vectors()
+{
+ extern float lx, ly, lz;
+ float D;
+
+ lx = 1.0; ly = -1.0; lz = 3.0;
+
+ D = sqrt ( lx * lx + ly * ly + lz * lz );
+
+ lx = lx/D; ly = ly/D; lz = lz/D;
+
+}
+
+/* *********************************************************************** **
+ **
+** new_intensity_value **
+** **
+** calculates shade value for a pixel from surface characteristics ** **
+ **
+** Revision History **
+** **
+** Rev Date By Description **
+** 1.0 1/12/91 DE Original **
+** 1.1 1/04/92 DE Include Phong Shading **
+** 1.2 11/08/92 JWP Parameterized Specular Component ** **
+ **
+*********************************************************************** */
+
+float calc_d();
+float calc_g();
+float calc_f();
+float sqr();
+void printvector();
+void vectscale();
+void vectadd();
+float magnitude();
+
+float
+normalize (x, y, z)
+ float x, y, z; /*vector x, y, z components*/
+{
+ float result;
+
+ /* function calculates the amount to divide each vector component
+ to normalize it to a unit vector. The parameters are the x,y,z
+ components and the result is the amount to divide by */
+
+ result = sqrt (x*x + y*y + z*z);
+ return (result);
+
+ }
+
+
+
+float Newnormalize(V, W)
+float *V;
+float *W;
+{
+ float temp;
+
+ temp = normalize(V[0], V[1], V[2]);
+
+ W[0] = V[0]/temp;
+ W[1] = V[1]/temp;
+ W[2] = V[2]/temp;
+
+ return temp;
+}
+
+float dot(V, W)
+ float V[3];
+ float W[3];
+{
+
+ return ( (V[0])*(W[0]) + (V[1])*(W[1]) + (V[2])*(W[2]) );
+
+}
+
+float Phong (Nv, Lv, Ev, shine)
+float Nv[3];
+float Lv[3];
+float Ev[3];
+float shine;
+{
+ float Hv[3];
+
+ Newnormalize(Ev, Ev);
+
+ Hv[0] = Ev[0] + Lv[0];
+ Hv[1] = Ev[1] + Lv[1];
+ Hv[2] = Ev[2] + Lv[2];
+
+ Newnormalize (Hv, Hv);
+
+ shine = abs(shine);
+ return( pow(dot(Nv, Hv), shine) );
+}
+
+
+/******************* Auxillary functions *****************************/
+
+/* Function : calc_c
+* Returns : the microfacet distribution function */
+
+float calc_d(cos_alpha,c3)
+float cos_alpha;
+float c3;
+{
+float d;
+d=sqr( sqr(c3) / ( sqr(cos_alpha)*(sqr(c3) -1) +1)); return d;
+}
+
+/*
+* Function : calc_g
+* Returns : the geometrical attenuation factor. *
+* This function should return values between 0.0 and 1.0, so if it's * negative I will return 0.0 Anyway it does not seem to make any difference * at all whether I return 0.0, the negative value or the minimum of the * absolute values of (temp1,temp2,temp3) */
+
+float calc_g(N,H,L,V)
+float N[3]; /* Normal vector */
+float H[3]; /* Half-way vector */
+float L[3]; /* Light vector */
+float V[3]; /* View vector */
+{
+ float temp1,temp2,temp3,ret;
+ float NdotH,NdotV,NdotL,VdotH;
+ NdotH=dot(N,H);
+ NdotV=dot(N,V);
+ NdotL=dot(N,L);
+ VdotH=dot(V,H);
+ temp1=1.0;
+ temp2=(2*NdotH*NdotV)/VdotH;
+ temp3=(2*NdotH*NdotL)/VdotH;
+ /* Find minimum value */
+ if (temp1 < temp2)
+ if (temp1 < temp3)
+ ret=temp1;
+ else
+ ret=temp3;
+ else
+ if (temp2 < temp3)
+ ret=temp2;
+ else
+ ret=temp3;
+ if (ret < 0.0)
+ ret=0.0;
+ return ret;
+}
+
+/* Function : calc_f
+* Returns : the Fresnel term
+*/
+
+float calc_f(L,H,mu)
+float L[3];
+float H[3];
+float mu;
+{
+ float temp1,temp2;
+ float c,g;
+ c=dot(L,H);
+ g=sqrt(sqr(mu)+sqr(c) -1);
+ temp1 = (sqr(g-c)/sqr(g+c))*0.5;
+ temp2 = 1+(sqr( c*(g+c)-1 ) / sqr( c*(g-c)+1)); return (temp1*temp2);
+}
+
+/* Function : sqr
+* Returns : the square of its argument
+*/
+
+float sqr(x)
+float x;
+{
+ return (x*x);
+}
+
+/* Function : printvector
+* prints the contents of a vector with 3 elements */
+
+void printvector(v)
+float v[3];
+{
+ printf("[%f,%f,%f] ",v[0],v[1],v[2]);
+}
+
+void vectscale(v1, k, vout, n)
+float *v1;
+float k;
+float *vout;
+int n;
+{ vout[0] = v1[0]*k;
+ vout[1] = v1[1]*k;
+ vout[2] = v1[2]*k;
+}
+
+void vectadd(v1, v2, vout, n)
+float *v1, *v2, *vout;
+int n;
+{ vout[0] = v1[0] + v2[0];
+ vout[1] = v1[1] + v2[1];
+ vout[2] = v1[2] + v2[2];
+}
+
+float magnitude(v)
+float *v;
+{ return( normalize(v[0], v[1], v[2]) );
+}
+
+float T_S(Nv, Lv, Ev, shine)
+float Nv[3]; /* Normalized Normal vector */
+float Lv[3]; /* Normalized Light-source vector */
+float Ev[3]; /* Un-normalized Eye vector */
+float shine; /* parameter to absorb Phong coeff */
+{
+ float Hv[3]; /* Half-way vector H */
+ float cos_alpha;
+ float t;
+ float mdf; /* Micro facet distribtuion function */
+ float gaf; /* Geometrical attenuation factor*/ float ft; /* The Fresnel term */
+ float c3;
+ float mu; /* Refractive index */
+
+ /*initialize appearance constants*/
+ c3 = shine;
+ mu = 200.0;
+
+ /*normalize eye vector*/
+
+ Newnormalize(Ev, Ev);
+
+/* Calculate the half-way vector H, between the light vector and the
+view vector */
+
+ vectadd(Ev,Lv,Hv,3);
+ t = magnitude(Hv,3);
+
+ vectscale(Hv,(1/t),Hv,3);
+
+ /* Calculate the micro-facet distribution function D */
+
+ cos_alpha=dot(Nv,Hv);
+ mdf=calc_d(cos_alpha,c3);
+
+
+ /* Calculate the geometrical attenuation factor */
+
+ gaf=calc_g(Nv,Hv,Lv,Ev);
+
+ /* Calculate the Fresnel Term */
+
+ ft=calc_f(Lv,Hv,mu);
+
+ /* Calculate specular component */
+
+ return( (mdf*gaf*ft) / dot(Nv,Lv) );
+}
+
+
+
+
+float
+new_intensity_value(a_pnt)
+POINT a_pnt;
+/* Calculate the new intensity value of a pixel
+in order to construct a bump map of the paint surface
+*/
+{
+float h, h1, h2, h3, h4;
+ float shininess;
+float Ka, Kd, Ks;
+ float wetmax, degree, norm, distance;
+ float g;
+float Nv[3];
+ float Ev[3];
+ float Hv[3];
+ float Lv[3];
+ extern float lx, ly, lz;
+float intensity, light_intensity;
+int liquid;
+POINT b_pnt;
+CELL_PTR cell;
+CELL_PTR next_cell;
+ int x_cntr, y_cntr;
+
+ Ka = 0.0;
+ Kd = 0.5;
+ Ks = 0.5;
+
+ wetmax = 100.0;
+ distance = 2500.0;
+ light_intensity = 2.0;
+ shininess = 0.3;
+
+ cell = get_cell(a_pnt);
+
+ h = (float)cell->volume;
+
+ if (neighbour(a_pnt, NORTH, &b_pnt)) {
+ next_cell = get_cell(b_pnt);
+ h1 = (float)next_cell->volume;
+ } else
+ h1 = h;
+
+ if (neighbour(a_pnt, EAST, &b_pnt)) {
+ next_cell = get_cell(b_pnt);
+ h2 = (float)next_cell->volume;
+ } else
+ h2 = h;
+
+ if (neighbour(a_pnt, SOUTH, &b_pnt)) {
+ next_cell = get_cell(b_pnt);
+ h3 = (float)next_cell->volume;
+ } else
+ h3 = h;
+
+ if (neighbour(a_pnt, WEST, &b_pnt)) {
+ next_cell = get_cell(b_pnt);
+ h4 = (float)next_cell->volume;
+ } else
+ h4 = h;
+
+ h1 = h1/HEIGHT_SCALE;
+ h2 = h2/HEIGHT_SCALE;
+ h3 = h3/HEIGHT_SCALE;
+ h4 = h4/HEIGHT_SCALE;
+
+ /* test fix for "disappearing" paint */
+
+ if (cell->contents.liquid_content == 0)
+ liquid = 1;
+ else
+ liquid = cell->contents.liquid_content;
+
+ degree = (float)abs(liquid)/wetmax;
+
+ x_cntr= 150 - a_pnt.x;
+ y_cntr= 150 - a_pnt.y;
+
+ Ks = light_intensity * Ks /* * degree*/ ;
+
+ Kd = light_intensity * Kd;
+
+/* shininess = shininess/degree; */
+
+
+ Nv[1] = h3 - h1;
+ Nv[0] = h4 - h2;
+ Nv[2] = 4.0;
+
+ Newnormalize (Nv, Nv);
+
+ Lv[0] = lx;
+ Lv[1] = ly;
+ Lv[2] = lz;
+
+ g = dot(Lv, Nv)*Kd + Ka;
+
+ g = g * (float)cell->contents.colour.hue;
+
+ Ev[0] = (float)x_cntr;
+ Ev[1] = (float)y_cntr;
+ Ev[2] = distance;
+
+ intensity = g + Ks*T_S(Nv, Lv, Ev, shininess);
+
+ if ( intensity > 255.0 ) {
+ intensity = 0.0;
+ } else {
+ if (intensity < 0.0)
+ intensity = 255.0;
+ else
+ intensity = 255.0 - intensity;
+ }
+
+
+ /*printf("wetness %d colour %d intensity %f guraud %f phong %f\n",
+ cell->contents.liquid_content,
+ cell->contents.colour.hue,
+ intensity,
+ g,
+ intensity - g);*/
+
+
+return (intensity);
+}
+
+
+/* *********************************************************************** */
+
+void single_step()
+/* This routine defines the paint steps involved in the
+ basic cycle of the painting engine. */
+
+{
+ POINT locus;
+ CELL_PTR cell;
+ BOOLEAN done;
+
+ next_cell_point(&locus);
+ cell = get_cell(locus);
+
+ done = age_paint(cell);
+ if (done == TRUE) return;
+
+ done = diffuse_paint(cell, locus);
+ if (done == TRUE) return;
+
+ done = apply_gravity(cell, locus);
+}
+
+brush_stroke(x,y)
+int x;
+int y;
+{
+ POINT pnt;
+ CELL_PTR cell;
+
+
+ pnt.x = x;
+ pnt.y = y;
+
+ cell = get_cell(pnt);
+
+ cell->contents.liquid_content = 100;
+ cell->contents.drying_rate = 10;
+ cell->contents.miscibility = 80;
+
+ cell->contents.colour.hue = 128;
+ cell->contents.colour.saturation = 1.0;
+ cell->contents.colour.lightness = 0.0;
+
+ cell->volume = 50;
+
+}
+
+
diff --git a/chalk/colorspaces/wetsticky/ws/engine.h b/chalk/colorspaces/wetsticky/ws/engine.h
new file mode 100644
index 00000000..b6072b0a
--- /dev/null
+++ b/chalk/colorspaces/wetsticky/ws/engine.h
@@ -0,0 +1,33 @@
+/*
+ FILE: engine.h
+ PURPOSE: Defines the routines for the Paint Engine.
+ AUTHOR: Kevin Waite
+ VERSION: 1.00 (10-May-91)
+
+Copyright 1991, 1992, 2002, 2003 Tunde Cockshott, Kevin Waite, David England.
+
+Contact David England [email protected]
+School of Computing and Maths Sciences,
+Liverpool John Moores University
+Liverpool L3 3AF
+United Kingdom
+Phone +44 151 231 2271
+
+Wet and Sticky is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Wet and Sticky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Wet and Sticky; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA
+
+*/
+
+extern void single_step();
+/* This routine defines the paint steps involved in the
+ basic cycle of the painting engine. */
+
+extern brush_stroke();
+
+extern float intensity_value( /* POINT */);
+
+extern float new_intensity_value( /* POINT */);
+
+extern void compute_shade_vectors();
+
+
diff --git a/chalk/colorspaces/wetsticky/ws/engine3.c b/chalk/colorspaces/wetsticky/ws/engine3.c
new file mode 100644
index 00000000..9fd274cd
--- /dev/null
+++ b/chalk/colorspaces/wetsticky/ws/engine3.c
@@ -0,0 +1,617 @@
+/*
+ FILE: engine.c
+ PURPOSE: Defines the routines for the Paint Engine.
+ AUTHOR: Kevin Waite
+ VERSION: 1.00 (10-May-91)
+
+Copyright 1991, 1992, 2002, 2003 Tunde Cockshott, Kevin Waite, David England.
+
+Contact David England [email protected]
+School of Computing and Maths Sciences,
+Liverpool John Moores University
+Liverpool L3 3AF
+United Kingdom
+Phone +44 151 231 2271
+
+Wet and Sticky is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Wet and Sticky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Wet and Sticky; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+*/
+
+#include "constants.h"
+#include "types.h"
+#include "canvas.h"
+#include <math.h>
+
+#define HEIGHT_SCALE 1.0
+
+/* *********************************************************************** */
+
+int random_percent()
+/* This function returns a random number in the range [0,100]. */
+{
+ extern long random();
+
+ return (random() % 101);
+}
+
+/* *********************************************************************** */
+
+BOOLEAN allow_event_based_on(value)
+/* The given value is a percentage. Compare this value
+ with a randomly generated percentage and if it is larger
+ then allow the event to happen (i.e. return TRUE) other-
+ wise return FALSE. */
+
+int value;
+
+{
+ if (value > random_percent()) return(TRUE);
+ return(FALSE);
+}
+
+/* *********************************************************************** */
+
+BOOLEAN age_paint(cell)
+/* Make the paint in the given cell older, i.e. let
+ if dry out a bit if it isn't already dry. This
+ function returns TRUE if the paint was already
+ dry or becomes so, and FALSE otherwise. */
+
+CELL_PTR cell;
+
+{
+ if (cell->volume == 0) return(TRUE);
+ if (cell->contents.liquid_content == 0) return(TRUE);
+ if (allow_event_based_on(cell->contents.drying_rate) == TRUE)
+ cell->contents.liquid_content--;
+
+ if (cell->contents.liquid_content == 0) return(TRUE);
+ return(FALSE);
+}
+
+/* *********************************************************************** */
+
+BOOLEAN similar_paint(aPaint, bPaint)
+/* Determine whether the two paints are similar. It is
+ assumed that aPaint has come from the host cell (and
+ so it is its miscibility value that is used). The
+ function returns TRUE if the paints are similar and
+ FALSE otherwise. */
+
+PAINT aPaint, bPaint;
+
+{
+ int delta;
+
+ delta = abs(aPaint.liquid_content - bPaint.liquid_content);
+ if (delta <= aPaint.miscibility) return(TRUE);
+ return(FALSE);
+}
+
+/* *********************************************************************** */
+
+int surplus_paint(cell)
+/* Returns the amount of paint held by this cell greater than its
+ absorbancy value. This is the amount of paint that can flow. */
+
+CELL_PTR cell;
+
+{
+ return (MAX(cell->volume - cell->absorbancy, 0));
+}
+
+/* *********************************************************************** */
+
+BOOLEAN has_surplus_paint(cell)
+/* Does the given cell have excess paint, i.e. can paint flow out
+ of this cell. Return TRUE if it can and FALSE otherwise. */
+
+CELL_PTR cell;
+
+{
+ if (surplus_paint(cell) > 0) return(TRUE);
+ return(FALSE);
+}
+
+/* *********************************************************************** */
+
+void stop() { /* Used for breakpointing. */ }
+
+void donate_paint(source, srcLocus, amount, dest, destLocus)
+/* The source cell is donating the specified volume of its paint
+ to the destination cell. The destination cell must mix this
+ new paint with its existing paint to yield a new paint.
+ This routine is also responsible for recording which cells
+ have been updated and so need tqrepainting.
+
+ A special case is recognised where the destination has not yet
+ had any paint applied. This causes the donated paint to become
+ to new contents of this cell.
+
+*/
+
+CELL_PTR source, dest;
+POINT srcLocus, destLocus;
+int amount;
+
+{
+ float delta, ratio;
+ int iDelta;
+
+ source->volume -= amount;
+
+ if (dest->volume == UNFILLED) {
+
+ /* The donated paint is going into an unfilled cell.
+ Copy the source's attributes into the destination. */
+
+ dest->volume = amount;
+ dest->contents.colour.hue = source->contents.colour.hue;
+ dest->contents.colour.lightness = source->contents.colour.lightness;
+ dest->contents.colour.saturation = source->contents.colour.saturation;
+ dest->contents.liquid_content = source->contents.liquid_content;
+ dest->contents.miscibility = source->contents.miscibility;
+ dest->contents.drying_rate = source->contents.drying_rate;
+
+ } else {
+
+ /* Need to mix the existing paint in the dest with this amount
+ of new paint from the source. This is done using a linear
+ interpolation mechanism using the relative amounts of the
+ paint as the control. */
+
+ ratio = amount / (float)(dest->volume);
+
+ iDelta = source->contents.colour.hue - dest->contents.colour.hue;
+ if (iDelta != 0) {
+ dest->contents.colour.hue += (int)(ratio * iDelta);
+ if (dest->contents.colour.hue >= 360)
+ dest->contents.colour.hue -= 360;
+ }
+
+ iDelta = source->contents.drying_rate - dest->contents.drying_rate;
+ dest->contents.drying_rate += (int)(ratio * iDelta);
+ dest->contents.drying_rate %= 101;
+
+ iDelta = source->contents.liquid_content - dest->contents.liquid_content;
+ dest->contents.liquid_content += (int)(ratio * iDelta);
+ dest->contents.liquid_content %= 101;
+
+ iDelta = source->contents.miscibility - dest->contents.miscibility;
+ dest->contents.miscibility += (int)(ratio * iDelta);
+ dest->contents.miscibility %= 101;
+
+ delta = source->contents.colour.saturation - dest->contents.colour.saturation;
+ dest->contents.colour.saturation += ratio * delta;
+
+ delta = source->contents.colour.lightness - dest->contents.colour.lightness;
+ dest->contents.colour.lightness += ratio * delta;
+
+ dest->volume += amount; /* The new volume of paint in dest. */
+
+ }
+
+ need_to_tqrepaint(destLocus);
+}
+
+/* *********************************************************************** */
+
+void handle_surface_tension(cell, locus)
+/* This routine handles the surface tension around the given cell.
+*/
+
+CELL_PTR cell;
+POINT locus;
+
+{
+ DIRECTION direction[3];
+ POINT loci[3];
+ CELL_PTR buddy[3];
+ BOOLEAN ok, similar[3];
+ int weakCount, weak[3], count[3], excess, chosen, side, start, finish, k, lowest;
+
+ if (has_surplus_paint(cell) == FALSE) return;
+
+ direction[0] = cell->gravity.direction;
+ direction[1] = clockwise_from(direction[0]);
+ direction[2] = anti_clockwise_from(direction[0]);
+
+ for (k=0; k < 3; k++) {
+ ok = neighbour(locus, direction[k], &loci[k]);
+ if (ok == TRUE) {
+ buddy[k] = get_cell(loci[k]);
+ count[k] = 0;
+ } else count[k] = -1;
+ }
+
+ for (k=0; k < 3; k++)
+ similar[k] = (count[k] == -1)
+ ? FALSE
+ : similar_paint(cell->contents, buddy[k]->contents);
+
+ for (k=0; k < 3; k++) {
+ if ((count[k] != -1) && (similar[k] == FALSE)) {
+ count[k] = 0;
+ start = MAX(k-1, 0);
+ finish = MIN(k+1, 2);
+ for (side=start; side <= finish; side++)
+ if ((count[side] != -1) && (similar[side] == FALSE)) count[k]++;
+
+ }
+ }
+
+ lowest = 4;
+ for (k=0; k < 3; k++) if (count[k] >= 0) lowest = MIN(count[k], lowest);
+
+ weakCount = 0;
+ for (k=0; k < 3; k++) if (count[k] == lowest) weak[weakCount++] = k;
+
+ /* The weak array now holds weakCount indices of those sides that have
+ the lowest surface tension and therefore where any paint would flow over.
+ Now it is necessary to see whether paint will actually flow based on
+ a probability level using the liquidity and volume of the paint in the
+ cell as parameters. Paint will flow over only one of the weakest sides
+ with the side chosen at random. */
+
+ if (random_percent() > cell->contents.liquid_content) return; /* Too viscous. */
+
+ excess = surplus_paint(cell);
+ if (random_percent() > excess * 3) return;
+ /* The '3' in the previous statement is an empirically-derived multiplier. */
+
+ /* The paint will flow. Pick one of the weakest sides at random. */
+
+ chosen = weak[random_percent() % weakCount];
+ donate_paint(cell, locus, (excess / 2), buddy[chosen], loci[chosen]);
+}
+
+/* *********************************************************************** */
+
+BOOLEAN diffuse_paint(cell, locus)
+/* Diffuse paint among the neighbours of the given cell.
+ If this cell does not have surplus paint then return
+ TRUE otherwise return FALSE. */
+
+CELL_PTR cell;
+POINT locus;
+
+{
+ extern long random();
+ DIRECTION down, direction;
+ CELL_PTR buddy;
+ POINT nlocus;
+ BOOLEAN ok;
+ int excess;
+
+ if (has_surplus_paint(cell) == FALSE) return(TRUE);
+
+ down = cell->gravity.direction;
+ direction = ((random() & 01) == 0)
+ ? clockwise_from(down)
+ : anti_clockwise_from(down);
+
+ ok = neighbour(locus, direction, &nlocus);
+ if (ok == FALSE) return(TRUE);
+
+ buddy = get_cell(nlocus);
+
+ if (similar_paint(cell->contents, buddy->contents) == FALSE) {
+ handle_surface_tension(cell, locus);
+ return(FALSE);
+ }
+
+ if (buddy->volume >= cell->volume) return(FALSE);
+
+ if (allow_event_based_on(cell->contents.liquid_content) == FALSE)
+ return(FALSE);
+
+ /* Transfer one particle of paint from cell to its buddy. */
+
+ excess = (cell->volume - buddy->volume) / 2;
+ donate_paint(cell, locus, excess, buddy, nlocus);
+ return(FALSE);
+}
+
+/* *********************************************************************** */
+
+BOOLEAN apply_gravity(cell, locus)
+/* Subject the contents of the given cell to the effects
+ of gravity. Note that the direction of gravity is local
+ to the given cell. Locus is the address of this cell.
+ This function returns TRUE if the paint in this cell
+ cannot flow and FALSE otherwise.
+*/
+
+CELL_PTR cell;
+POINT locus;
+
+{
+ extern long random();
+ POINT downhill;
+ CELL_PTR down;
+ BOOLEAN ok, can_flow;
+ int barrier, excess;
+
+ ok = neighbour(locus, cell->gravity.direction, &downhill);
+ if (ok == FALSE) return(TRUE); /* At bottom of canvas. */
+
+ down = get_cell(downhill);
+
+ can_flow = down->volume < (cell->volume + cell->gravity.strength)
+ ? TRUE : FALSE;
+
+ if (can_flow == FALSE) return(TRUE);
+
+ /* Although this paint can flow introduce a random value that
+ uses the viscosity of the paint to determine whether it does
+ actually flow. */
+
+ barrier = random() % 10;
+ if (cell->contents.liquid_content > barrier) {
+ /* Paint is actually moving. Move half of the excess downward. */
+
+ excess = (cell->volume - cell->absorbancy) / 2;
+ donate_paint(cell, locus, excess, down, downhill);
+ }
+
+ return(FALSE);
+}
+
+
+float lx, ly, lz;
+
+void
+compute_shade_vectors()
+{
+ extern float lx, ly, lz;
+ float D;
+
+ lx = -1.0; ly = 1.0; lz = 2.0;
+
+ D = sqrt ( lx * lx + ly * ly + lz * lz );
+
+ lx = lx/D; ly = ly/D; lz = lz/D;
+
+}
+
+/* *********************************************************************** ** **
+** new_intensity_value **
+** **
+** calculates shade value for a pixel from surface characteristics ** ** **
+** Revision History **
+** **
+** Rev Date By Description **
+** 1.0 1/12/91 DE Original **
+** 1.1 1/04/92 DE Include Phong Shading **
+** 1.2 11/08/92 JWP Parameterized Specular Component ** ** **
+*********************************************************************** */
+float
+normalize (x, y, z)
+ float x, y, z; /*vector x, y, z components*/
+{
+ float result;
+
+ /* function calculates the amount to divide each vector component
+ to normalize it to a unit vector. The parameters are the x, y,
+z
+ components and the result is the amount to divide by */
+
+ result = sqrt (x*x + y*y + z*z);
+ return (result);
+
+ }
+
+
+
+float Newnormalize(V, W)
+float *V;
+float *W;
+{
+float temp;
+
+temp = normalize(V[0], V[1], V[2]);
+
+W[0] = V[0]/temp;
+W[1] = V[1]/temp;
+W[2] = V[2]/temp;
+
+return temp;
+}
+
+float dot(V, W)
+float V[3];
+float W[3];
+{
+
+return ( (V[0])*(W[0]) + (V[1])*(W[1]) + (V[2])*(W[2]) );
+
+}
+
+float Phong (Nv, Lv, Ev, shine)
+float Nv[3];
+float Lv[3];
+float Ev[3];
+float shine;
+{
+float Hv[3];
+
+Newnormalize(Ev, Ev);
+
+Hv[0] = Ev[0] + Lv[0];
+Hv[1] = Ev[1] + Lv[1];
+Hv[2] = Ev[2] + Lv[2];
+
+Newnormalize (Hv, Hv);
+
+shine = abs(shine);
+return( pow(dot(Nv, Hv), shine) );
+}
+
+
+float
+new_intensity_value(a_pnt)
+POINT a_pnt;
+/* Calculate the new intensity value of a pixel
+in order to construct a bump map of the paint surface
+*/
+{
+float h, h1, h2, h3, h4;
+ int shininess;
+float Ka, Kd, Ks;
+ float wetmax, degree, norm, distance;
+ float g;
+float Nv[3];
+ float Ev[3];
+ float Hv[3];
+ float Lv[3];
+ extern float lx, ly, lz;
+float intensity, light_intensity;
+POINT b_pnt;
+CELL_PTR cell;
+CELL_PTR next_cell;
+ int x_cntr, y_cntr;
+
+Ka = 0.1;
+Kd = 0.6;
+ Ks = 0.4;
+
+ wetmax = 100.0;
+ distance = 2500.0;
+ light_intensity = 2.0;
+ shininess = 200;
+
+cell = get_cell(a_pnt);
+
+h = (float)cell->volume;
+
+if (neighbour(a_pnt, NORTH, &b_pnt)) {
+next_cell = get_cell(b_pnt);
+h1 = (float)next_cell->volume;
+} else
+h1 = h;
+
+if (neighbour(a_pnt, EAST, &b_pnt)) {
+next_cell = get_cell(b_pnt);
+h2 = (float)next_cell->volume;
+} else
+h2 = h;
+
+if (neighbour(a_pnt, SOUTH, &b_pnt)) {
+next_cell = get_cell(b_pnt);
+h3 = (float)next_cell->volume;
+} else
+h3 = h;
+
+if (neighbour(a_pnt, WEST, &b_pnt)) {
+next_cell = get_cell(b_pnt);
+h4 = (float)next_cell->volume;
+} else
+h4 = h;
+
+h1 = h1/HEIGHT_SCALE;
+h2 = h2/HEIGHT_SCALE;
+h3 = h3/HEIGHT_SCALE;
+h4 = h4/HEIGHT_SCALE;
+
+ degree = (float)abs(cell->contents.liquid_content)/wetmax;
+
+ x_cntr= 150 - a_pnt.x;
+ y_cntr= 150 - a_pnt.y;
+
+ Ks = light_intensity * Ks * degree;
+
+ Kd = light_intensity * Kd;
+
+ shininess = (int)degree * shininess + 1;
+
+
+ Nv[1] = h3 - h1;
+ Nv[0] = h4 - h2;
+Nv[2] = 4.0;
+
+ Newnormalize (Nv, Nv);
+
+ Lv[0] = lx;
+Lv[1] = ly;
+ Lv[2] = lz;
+
+ g = dot(Lv, Nv)*Kd + Ka;
+
+ g = g * (float)cell->contents.colour.hue;
+
+Ev[0] = (float)x_cntr;
+Ev[1] = (float)y_cntr;
+Ev[2] = distance;
+
+ intensity = g + Ks*Phong(Nv, Lv, Ev, (float)shininess);
+
+ if ( intensity > 255.0 ) {
+ intensity = 0.0;
+ } else {
+ if (intensity < 0.0)
+ intensity = 255.0;
+ else
+ intensity = 255.0 - intensity;
+ }
+
+
+ /*printf("wetness %d colour %d intensity %f guraud %f phong %f\n",
+ cell->contents.liquid_content,
+ cell->contents.colour.hue,
+ intensity,
+ g,
+ intensity - g);*/
+
+
+return (intensity);
+}
+
+
+/* *********************************************************************** */
+
+void single_step()
+/* This routine defines the paint steps involved in the
+ basic cycle of the painting engine. */
+
+{
+ POINT locus;
+ CELL_PTR cell;
+ BOOLEAN done;
+
+ next_cell_point(&locus);
+ cell = get_cell(locus);
+
+ done = age_paint(cell);
+ if (done == TRUE) return;
+
+ done = diffuse_paint(cell, locus);
+ if (done == TRUE) return;
+
+ done = apply_gravity(cell, locus);
+}
+
+brush_stroke(x,y)
+int x;
+int y;
+{
+ POINT pnt;
+ CELL_PTR cell;
+
+
+ pnt.x = x;
+ pnt.y = y;
+
+ cell = get_cell(pnt);
+
+ cell->contents.liquid_content = 100;
+ cell->contents.drying_rate = 10;
+ cell->contents.miscibility = 80;
+
+ cell->contents.colour.hue = 128;
+ cell->contents.colour.saturation = 1.0;
+ cell->contents.colour.lightness = 0.0;
+
+ cell->volume = 50;
+
+}
+
diff --git a/chalk/colorspaces/wetsticky/ws/load_ppm.c b/chalk/colorspaces/wetsticky/ws/load_ppm.c
new file mode 100644
index 00000000..6368ee08
--- /dev/null
+++ b/chalk/colorspaces/wetsticky/ws/load_ppm.c
@@ -0,0 +1,244 @@
+/*
+ FILE: load_ppm.c
+ PURPOSE: Defines the routines to load a PPM portable pixmap image file.
+ AUTHOR: David England
+ VERSION: 1.00 (10-May-91)
+
+
+Copyright 1991, 1992, 2002, 2003 Tunde Cockshott, Kevin Waite, David England.
+
+Contact David England [email protected]
+School of Computing and Maths Sciences,
+Liverpool John Moores University
+Liverpool L3 3AF
+United Kingdom
+Phone +44 151 231 2271
+
+Wet and Sticky is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Wet and Sticky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Wet and Sticky; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+*/
+
+#include "constants.h"
+#include "types.h"
+#include "canvas.h"
+
+#include <ctype.h>
+#include <ppm.h>
+#include <ppmcmap.h>
+
+/* Max number of colors allowed in ppm input. */
+#define MAXCOLORS 256
+
+extern CELL canvas[CANVAS_WIDTH][CANVAS_HEIGHT];
+
+float
+max_rgb(r,g,b)
+float r;
+float g;
+float b;
+{
+ if ((r > g) && (r > b))
+ return (r);
+
+ if ((b > g) && (b > r))
+ return (b);
+
+ if ((g > b) && (g > r))
+ return (g);
+
+ return(0);
+}
+
+float
+min_rgb(r,g,b)
+float r;
+float g;
+float b;
+{
+ if ((r < g) && (b < g))
+ return (r);
+
+ if ((b < g) && (b < r))
+ return (b);
+
+ if ((g < b) && (g < r))
+ return (g);
+
+ return(0);
+}
+
+
+int
+GetHue(red, green, blue) /* rgb to hls */
+int red;
+int green;
+int blue;
+{
+ float min_col, max_col;
+ float h,s,l;
+ float rc, gc, bc;
+ float r, g, b;
+
+ r = (float)red/255.0;
+ b = (float)green/255.0;
+ g = (float)blue/255.0;
+
+ max_col = (float)max_rgb(r, g, b);
+ min_col = (float)min_rgb(r, g, b);
+
+ l = (max_col + min_col)/2.0 ;
+
+ if ( max_col == min_col) {
+ s = 0.0;
+ h = 0.0;
+ } else {
+ if ( l < 0.5) {
+ s = (max_col - min_col)/(max_col + min_col);
+ } else s = (max_col - min_col)/(2 - max_col - min_col);
+
+ rc = (max_col -r)/( max_col - min_col);
+ gc = (max_col -g)/(max_col - min_col);
+ bc = (max_col -b)/(max_col - min_col);
+
+ if (r == max_col)
+ h = bc - gc;
+ else if (g == max_col )
+ h = 2 + rc - bc;
+ else if (b == max_col)
+ h = 4 + gc -rc;
+
+ h = h * 60;
+
+ if ( h < 0.0)
+ h = h + 360;
+ }
+
+ return ((int)h);
+
+
+}
+
+GetHuePaint(r,g,b)
+int r;
+int g;
+int b;
+{
+
+ /*if ((r == 0) && (g == 0) && (b ==0)) {
+ canvas[i][j].contents.liquid_content = 0;
+ canvas[i][j].contents.drying_rate = 0;
+ canvas[i][j].contents.miscibility = 0;
+
+ canvas[i][j].contents.colour.hue = 0;
+ canvas[i][j].contents.colour.saturation = 1.0;
+ canvas[i][j].contents.colour.lightness = 0.0;
+ canvas[i][j].volume = 80;
+ return (0);
+ }
+
+ if ((r == 255) && (g == 255) && ( b == 255)) {
+ canvas[i][j].contents.liquid_content = 0;
+ canvas[i][j].contents.drying_rate = 0;
+ canvas[i][j].contents.miscibility = 0;
+
+ canvas[i][j].contents.colour.hue = 128;
+ canvas[i][j].contents.colour.saturation = 1.0;
+ canvas[i][j].contents.colour.lightness = 0.0;
+ canvas[i][j].volume = 80;
+ return (128);
+ }*/
+}
+
+load_ppm_format(filename, width, height)
+char *filename;
+int *width;
+int *height;
+{
+
+ FILE* ifp;
+ pixel **pixels;
+ int rows, cols, i, j;
+ pixval maxval;
+ int red, green, blue;
+ int hue;
+
+ /*ppm_init( &argc, argv );*/
+
+
+
+ ifp = pm_openr( filename);
+
+ pixels = ppm_readppm( ifp, &cols, &rows, &maxval );
+
+ *(width) = cols;
+ *(height) = rows;
+
+ fprintf(stderr,"Loading file %s, %dx%d. Please wait ", filename, rows,
+cols);
+
+ if (rows > CANVAS_HEIGHT)
+ rows = CANVAS_HEIGHT;
+
+ if (cols > CANVAS_WIDTH)
+ cols = CANVAS_WIDTH;
+
+ for (i=0; i< rows; i++) {
+ for (j=0; j< cols; j++) {
+ red = PPM_GETR(pixels[i][j]);
+ green = PPM_GETG(pixels[i][j]);
+ blue = PPM_GETB(pixels[i][j]);
+
+ /*hue = GetHue(red, green, blue);*/
+
+ /* For gray scale only */
+
+ hue = 255 - red;
+
+
+ /*fprintf(stderr,"hue %d ", hue);*/
+ /*GetHuePaint(red, green, blue, i, j);*/
+
+ canvas[i][j].contents.liquid_content = 80;
+ canvas[i][j].contents.drying_rate = 80;
+ canvas[i][j].contents.miscibility = 80;
+
+ canvas[i][j].contents.colour.hue = hue;
+ canvas[i][j].contents.colour.saturation = 1.0;
+ canvas[i][j].contents.colour.lightness = 0.0;
+ canvas[i][j].volume = (float)hue/2.5;
+
+ if (red == 0)
+ if (green == 0)
+ if ( blue == 0) {
+ canvas[i][j].contents.liquid_content = 0;
+ canvas[i][j].contents.drying_rate = 0;
+ canvas[i][j].contents.miscibility = 0;
+ canvas[i][j].contents.colour.hue = 0;
+ canvas[i][j].volume = 0;
+ }
+
+ if (red == 255)
+ if (green == 255)
+ if ( blue == 255) {
+ canvas[i][j].contents.liquid_content = 0;
+ canvas[i][j].contents.drying_rate = 0;
+ canvas[i][j].contents.miscibility = 0;
+ canvas[i][j].contents.colour.hue = 360;
+ canvas[i][j].volume = 0;
+ }
+
+
+ }
+ if (( i %10) == 0){
+ fprintf(stderr,".");
+ fflush(stderr);
+ }
+ }
+
+ printf(" done\n");
+
+ pm_close( ifp );
+
+ /*exit(0);*/
+
+}
diff --git a/chalk/colorspaces/wetsticky/ws/main.c b/chalk/colorspaces/wetsticky/ws/main.c
new file mode 100644
index 00000000..8185557a
--- /dev/null
+++ b/chalk/colorspaces/wetsticky/ws/main.c
@@ -0,0 +1,105 @@
+/*
+ FILE: main.c
+ PURPOSE: The top-level program for Wet&Sticky
+ AUTHOR: Kevin Waite and David England
+ VERSION: 1.00 (10-May-91)
+
+Copyright 1991, 1992, 2002, 2003 Tunde Cockshott, Kevin Waite, David England.
+
+Contact David England [email protected]
+School of Computing and Maths Sciences,
+Liverpool John Moores University
+Liverpool L3 3AF
+United Kingdom
+Phone +44 151 231 2271
+
+
+Wet and Sticky is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Wet and Sticky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Wet and Sticky; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+*/
+
+#include "constants.h"
+#include "types.h"
+#include "canvas.h"
+#include "win_interface.h"
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+
+double HEIGHT_SCALE;
+
+void main(argc, argv)
+int argc;
+char *argv[];
+
+/*
+ The Wet&Sticky program can be executed with optional parameters.
+ Those parameters used by the X graphics system are stripped out.
+ If no parameters are given then the program runs as a purely
+ interactive system. This requires input handling which is not
+ yet implemented. If the argument is the string '-blob' then the
+ program uses a square blob as the starting image. Otherwise the
+ program assumes the argument is a filename containing a previously
+ stored canvas. This is then loaded into the canvas as a starting
+ point.
+*/
+
+{
+ char *filename;
+ extern void exit();
+ int width;
+ int height;
+ extern int optind, opterr;
+ extern char *optarg;
+ int c,i;
+ int blob_flag;
+
+
+ fprintf(stdout, "Wet&Sticky Version %s\n", VERSION);
+ fprintf(stdout, "Implemented by K.Waite and D.England, 1991\n");
+ fprintf(stdout, "Based on ideas by Tunde Cockshott\n\n");
+
+
+ initialise_canvas();
+ if (DEBUG) fprintf (stdout, "Finished initialising the canvas\n");
+
+ CreateWindows (&argc, argv, CANVAS_WIDTH , CANVAS_HEIGHT);
+
+ filename = argv[1];
+
+ blob_flag = 1;
+ HEIGHT_SCALE = 20.0;
+
+ opterr = 0;
+ fprintf(stderr, "HEIGHT %g\n", HEIGHT_SCALE);
+
+ while ((c = getopt(argc, argv, "f:s:")) != EOF)
+ switch (c) {
+ case 'f':
+ filename = optarg;
+ load_file(filename, &width, &height);
+ blob_flag = 0;
+ break;
+ case 's':
+ fprintf(stderr, "HEIGHT string %s \n",optarg);
+ HEIGHT_SCALE = atof(optarg);
+ break;
+ case '?':
+ break;
+ }
+
+ if (blob_flag)
+ blob (DEFAULT_BLOB_SIZE);
+
+ fprintf(stderr, "HEIGHT %g\n", HEIGHT_SCALE);
+
+ StartVolumeWindow (CANVAS_WIDTH, CANVAS_HEIGHT);
+ StartDrynessWindow (CANVAS_WIDTH, CANVAS_HEIGHT);
+
+ if (DEBUG) fprintf (stdout, "Finished preparing X\n");
+
+ if (DEBUG) fprintf (stdout, "Passing control to window manager\n");
+ StartWindows();
+ exit(0);
+
+}
diff --git a/chalk/colorspaces/wetsticky/ws/makefile b/chalk/colorspaces/wetsticky/ws/makefile
new file mode 100644
index 00000000..a14beb9a
--- /dev/null
+++ b/chalk/colorspaces/wetsticky/ws/makefile
@@ -0,0 +1,55 @@
+CFLAGS = -O3
+#CFLAGS = -g #-std
+LINT_FLAGS = -bchxu
+
+SOURCES = load_ppm.c canvas.c engine.c x_interface.c main.c
+OBJECTS = x_interface.o load_ppm.o engine.o canvas.o
+OBJECTS2= ogl_interface.o load_ppm.o engine.o canvas.o
+
+GFX_LIB=-L/usr/X11R6/lib \
+ -lXaw -lXmu -lXt -lX11 -lm -lppm -lpgm -lpbm
+
+#PPM_LIBS = ppm/libppm.a ppm/libpgm.a ppm/libpbm.a
+
+OGL_LIBS=-L/usr/X11R6/lib \
+ -laux -lGLU -lGL -lXext -lX11 -limp -lm -lppm -lpgm -lpbm
+
+OGL_INCS=-I/usr2/share/src/OpenGL/libaux
+
+CC=cc
+
+wet+sticky: constants.h canvas.h engine.h $(OBJECTS) main.c
+ ${CC} -o wet+sticky $(CFLAGS) main.c $(OBJECTS) $(GFX_LIB)
+
+wet+sticky2: constants.h canvas.h engine.h $(OBJECTS2) main.c
+ ${CC} -o wet+sticky2 $(CFLAGS) main.c $(OBJECTS2) $(OGL_LIBS)
+
+cmap: cmap.o
+ ${CC} -g -o cmap cmap.o $(GFX_LIB)
+
+anim: constants.h canvas.h engine.h anim.c
+ ${CC} -o anim $(CFLAGS) anim.c $(GFX_LIB)
+
+engine.o: types.h constants.h canvas.h engine.h
+ ${CC} -c $(CFLAGS) engine3.c
+
+canvas.o: types.h constants.h canvas.h
+ ${CC} -c $(CFLAGS) canvas.c
+
+x_interface.o: constants.h types.h canvas.h engine.h x_interface.c
+ ${CC} -c $(CFLAGS) x_interface.c
+
+ogl_interface.o: constants.h types.h canvas.h engine.h ogl_interface.c
+ ${CC} -c $(CFLAGS) ${OGL_INCS} ogl_interface.c
+
+load_ppm.o: constants.h types.h canvas.h engine.h load_ppm.c
+ ${CC} -c $(CFLAGS) load_ppm.c
+
+cmap.o: cmap.c
+ ${CC} -c -g cmap.c
+
+clean:
+ /bin/rm -f core
+ /bin/rm -f *.o
+
+lint: alint $(LINT_FLAGS) $(SOURCES)
diff --git a/chalk/colorspaces/wetsticky/ws/mona.pgm b/chalk/colorspaces/wetsticky/ws/mona.pgm
new file mode 100644
index 00000000..2060ee90
--- /dev/null
+++ b/chalk/colorspaces/wetsticky/ws/mona.pgm
Binary files differ
diff --git a/chalk/colorspaces/wetsticky/ws/ogl_interface.c b/chalk/colorspaces/wetsticky/ws/ogl_interface.c
new file mode 100644
index 00000000..953b10c8
--- /dev/null
+++ b/chalk/colorspaces/wetsticky/ws/ogl_interface.c
@@ -0,0 +1,302 @@
+/*
+ FILE: xgl_interface.c
+ PURPOSE: Creation and access to a OpenGL window
+ to wet+sticky using OpenGL
+ AUTHOR: David England
+ VERSION: 1.00 (21-June-96)
+
+Copyright 1991, 1992, 2002, 2003 Tunde Cockshott, Kevin Waite, David England.
+
+Contact David England [email protected]
+School of Computing and Maths Sciences,
+Liverpool John Moores University
+Liverpool L3 3AF
+United Kingdom
+Phone +44 151 231 2271
+
+
+Wet and Sticky is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Wet and Sticky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Wet and Sticky; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+*/
+
+#include <GL/gl.h>
+#include <GL/glu.h>
+/*#include <imp.h>*/
+/*#include "aux.h"*/
+
+#include <stdio.h>
+
+#include "constants.h"
+#include "types.h"
+#include "engine.h"
+#include "canvas.h"
+
+static int count=0;
+
+
+void nullProc()
+{
+}
+
+void SetupCmap()
+{
+}
+
+float Value(n1, n2, hue)
+float n1, n2, hue;
+{
+ if (hue > 360 )
+ hue = hue -360;
+ else if (hue < 0 )
+ hue = hue +360;
+ if (hue < 60 )
+ return n1+(n2-n1)*hue/60;
+ else if (hue < 180 )
+ return n2;
+ else if (hue < 240 )
+ return n1+(n2-n1)*(240-hue)/60;
+ else return n1;
+}
+
+
+RGB_COLOUR hls_to_rgb(h, l, s)
+int h;
+float l;
+float s;
+{
+RGB_COLOUR rgb_colour;
+float m1, m2;
+
+if (l <= 0.5 )
+ m2 = l*(1+s);
+else
+ m2 = l+s - l*s;
+m1 = 2*l-m2;
+
+rgb_colour.r = Value(m1, m2, h+120);
+rgb_colour.g = Value(m1,m2, h);
+rgb_colour.b = Value(m1,m2, h-120);
+
+return (rgb_colour);
+}
+
+void
+DrawPoint(x,y,hls_col)
+int x;
+int y;
+HLS_COLOUR hls_col;
+/* Draw a point on the window and the back-up Pixmap */
+{
+RGB_COLOUR rgb_colour;
+
+ rgb_colour = hls_to_rgb(hls_col.hue,
+ hls_col.lightness,
+ hls_col.saturation);
+
+
+ printf("h %.2f l %.2f s %.2f\n", hls_col.hue, hls_col.lightness,
+ hls_col.saturation);
+
+ printf( "r %.2f g %.2f b %.2f\n", rgb_colour.r, rgb_colour.g,
+ rgb_colour.b);
+
+ glColor3f(rgb_colour.r, rgb_colour.g, rgb_colour.b);
+
+ glBegin(GL_POINTS);
+ glVertex2s(x,y);
+ glVertex2s(x+1,y+1);
+ glEnd();
+
+}
+
+void
+DrawVolumePoint(x,y,attr)
+int x;
+int y;
+int attr;
+{
+/*set colour, draw point at offset */
+}
+
+void
+DrawDrynessPoint(x,y,attr)
+int x;
+int y;
+int attr;
+/* Draw a point on the window and the back-up Pixmap */
+{
+
+}
+
+void
+ClearWindow()
+{
+
+}
+
+static void
+CleanWindow()
+/* Fill a window with a solid, white rectangle */
+{
+}
+
+
+void CreateWindows(argc, argv, width, height)
+int *argc;
+char **argv;
+int width;
+int height;
+
+{
+
+ auxInitDisplayMode( AUX_RGBA);
+
+ auxInitPosition(50,50, width*3, height);
+
+ auxInitWindow(argv[0]);
+
+ glClearColor(1.0, 1.0, 1.0, 0.0);
+
+ glClear(GL_COLOR_BUFFER_BIT);
+
+}
+
+
+static void
+draw_labels()
+{
+}
+
+void paint_cell(cell, x, y)
+CELL_PTR cell;
+int x, y;
+
+{
+ DrawPoint(x,y, cell->contents.colour);
+
+ /* volColour is an index into the colour table in the range [0,255].
+ It is used to give a false colour image of the canvas's volume. */
+
+ /*DrawVolumePoint(x,y,volColour);*/
+
+
+ /*DrawDrynessPoint(x,y,dryness);*/
+}
+
+
+
+
+void draw_full_canvas()
+{
+ int x, y;
+ CELL_PTR cell;
+ POINT p;
+
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ if (DEBUG) {
+ printf ("Starting to paint full canvas...");
+ fflush(stdout);
+ }
+
+ for (y=0; y < CANVAS_HEIGHT; y++)
+ for (x=0; x < CANVAS_WIDTH; x++) {
+ p.x = x;
+ p.y = y;
+ cell = get_cell(p);
+ paint_cell(cell, x, y);
+ }
+
+ glFlush();
+ sleep(10);
+
+ if (DEBUG) printf ("done.\n");
+}
+
+void
+bump_map()
+{
+ POINT p;
+ CELL_PTR cell;
+ register int x, y;
+ register int colour;
+
+
+ for (y=0; y < CANVAS_HEIGHT; y++) {
+ for (x=0; x < CANVAS_WIDTH; x++) {
+ p.x = x;
+ p.y = y;
+ cell = get_cell(p);
+ colour = (int) new_intensity_value(p);
+
+/* colour = (int) (cell->contents.colour.hue *
+ ((float) MAX_COLOUR_INDEX / 360.0));*/
+ DrawDrynessPoint(x,y,colour);
+ }
+ }
+
+}
+
+
+void evolve_paint()
+{
+ int k;
+ POINT p;
+ CELL_PTR cell;
+ int new_x, new_y;
+ extern int count;
+
+ /*count++;
+ if (count > 500) {
+ fprintf(stderr,".");
+ fflush(stderr);
+ bump_map();
+ }*/
+
+ for (k=0; k < STEP_LIMIT; k++) single_step();
+ while (TRUE) {
+ next_cell_for_tqrepaint(&cell, &p);
+ if (cell == NIL) return;
+ paint_cell(cell, p.x, p.y);
+ glFlush();
+ }
+
+
+}
+
+void StartVolumeWindow()
+{
+}
+
+void StartDrynessWindow()
+{
+}
+
+void StartWindows()
+{
+
+
+ draw_full_canvas();
+ compute_shade_vectors(); /* Set vectors for shading */
+ draw_labels();
+
+ /*auxIdleFunc(evolve_paint);
+
+ auxMainLoop(draw_full_canvas);*/
+
+
+}
+
+void
+stroke()
+{
+
+}
+
+
+void
+stroke_motion()
+{
+
+}
+
diff --git a/chalk/colorspaces/wetsticky/ws/test2.jpg b/chalk/colorspaces/wetsticky/ws/test2.jpg
new file mode 100644
index 00000000..4254264f
--- /dev/null
+++ b/chalk/colorspaces/wetsticky/ws/test2.jpg
Binary files differ
diff --git a/chalk/colorspaces/wetsticky/ws/test3.jpg b/chalk/colorspaces/wetsticky/ws/test3.jpg
new file mode 100644
index 00000000..2b25a0d5
--- /dev/null
+++ b/chalk/colorspaces/wetsticky/ws/test3.jpg
Binary files differ
diff --git a/chalk/colorspaces/wetsticky/ws/types.h b/chalk/colorspaces/wetsticky/ws/types.h
new file mode 100644
index 00000000..af671f53
--- /dev/null
+++ b/chalk/colorspaces/wetsticky/ws/types.h
@@ -0,0 +1,72 @@
+/*
+ FILE: types.h
+ PURPOSE: Defines all the main types used in Wet&Sticky.
+ AUTHORS: Kevin Waite and David England
+ VERSION: 1.00 (10-May-91)
+
+Copyright 1991, 1992, 2002, 2003 Tunde Cockshott, Kevin Waite, David England.
+
+Contact David England [email protected]
+School of Computing and Maths Sciences,
+Liverpool John Moores University
+Liverpool L3 3AF
+United Kingdom
+Phone +44 151 231 2271
+
+Wet and Sticky is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Wet and Sticky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Wet and Sticky; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA
+
+
+*/
+
+
+/* A colour is specified as a vector in HLS space. Hue is a value
+ in the range 0..360 degrees with 0 degrees being red. Saturation
+ and Lightness are both in the range [0,1]. A lightness of 0 means
+ black, with 1 being white. A totally saturated colour has saturation
+ of 1.
+*/
+
+typedef struct hls_colour { short int hue; float saturation, lightness; }
+HLS_COLOUR;
+
+typedef struct rgb_colour {float r; float g; float b;}
+RGB_COLOUR;
+
+
+/* The address of a cell on the canvas. */
+
+typedef struct point { int x, y; } POINT, *POINT_PTR;
+
+
+/* A direction can be NORTH, EAST, SOUTH or WEST. */
+
+typedef short int DIRECTION;
+
+typedef short int BOOLEAN; /* FALSE or TRUE */
+
+
+typedef struct paint {
+ HLS_COLOUR colour;
+ int liquid_content; /* [0,100]. */
+ int drying_rate; /* [0,100]. */
+ int miscibility; /* [0,inf]. */
+} PAINT, *PAINT_PTR;
+
+
+/* Defines the strength and direction of gravity for a cell. */
+
+typedef struct gravity {
+ DIRECTION direction;
+ int strength; /* [0,Infinity). */
+} GRAVITY, *GRAVITY_PTR;
+
+
+/* Defines the contents and attributes of a cell on the canvas. */
+
+typedef struct cell {
+ PAINT contents; /* The paint in this cell. */
+ GRAVITY gravity; /* This cell's gravity. */
+ short int absorbancy; /* How much paint can this cell hold? */
+ short int volume; /* The volume of paint. */
+} CELL, *CELL_PTR;
diff --git a/chalk/colorspaces/wetsticky/ws/win_interface.h b/chalk/colorspaces/wetsticky/ws/win_interface.h
new file mode 100644
index 00000000..ee7a064b
--- /dev/null
+++ b/chalk/colorspaces/wetsticky/ws/win_interface.h
@@ -0,0 +1,28 @@
+/*
+Copyright 1991, 1992, 2002, 2003 Tunde Cockshott, Kevin Waite, David England.
+
+Contact David England [email protected]
+School of Computing and Maths Sciences,
+Liverpool John Moores University
+Liverpool L3 3AF
+United Kingdom
+Phone +44 151 231 2271
+
+Wet and Sticky is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Wet and Sticky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Wet and Sticky; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA
+
+
+*/
+
+extern void DrawPoint(/* int x, int y; int colour*/);
+extern int DrawVolumePoint(/* int x, int y; int attr*/);
+extern int DrawDrynessPoint(/* int x, int y; int attr*/);
+extern void ClearWindow();
+extern void CreateWindows(/* int *argc, char *argv[], int width, int height*/);
+extern void StartWindows(); /* enter infinite loop */
+extern void StartVolumeWindow(/*int width, int height*/);
+ /* display attribute window */
+extern void StartDrynessWindow(/*int width, int height*/);
+ /* display attribute window */
+
+
diff --git a/chalk/colorspaces/wetsticky/ws/x_interface.c b/chalk/colorspaces/wetsticky/ws/x_interface.c
new file mode 100644
index 00000000..a8b54b3e
--- /dev/null
+++ b/chalk/colorspaces/wetsticky/ws/x_interface.c
@@ -0,0 +1,795 @@
+/*
+ FILE: x_interface.c
+ PURPOSE: Creation and access to an X windows interface
+ to wet+sticky using Athena Widgets
+ AUTHOR: David England
+ VERSION: 1.00 (13-May-91)
+
+Copyright 1991, 1992, 2002, 2003 Tunde Cockshott, Kevin Waite, David England.
+Contact David England [email protected]
+School of Computing and Maths Sciences,
+Liverpool John Moores University
+Liverpool L3 3AF
+United Kingdom
+Phone +44 151 231 2271
+
+
+Wet and Sticky is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or (at
+your option) any later version. Wet and Sticky is distributed in the
+hope that it will be useful, but WITHOUT ANY WARRANTY; without even
+the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+PURPOSE. See the GNU General Public License for more details. You
+should have received a copy of the GNU General Public License along
+with Wet and Sticky; if not, write to the Free Software Foundation,
+Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+*/
+
+#include <X11/Xos.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Intrinsic.h>
+
+#include <X11/cursorfont.h>
+#include <X11/StringDefs.h>
+
+#include <X11/Shell.h>
+#include <X11/Xaw/Box.h>
+#include <X11/Xaw/Label.h>
+#include <stdio.h>
+
+#include "constants.h"
+#include "types.h"
+#include "engine.h"
+#include "canvas.h"
+
+/* Window Heirarchy -
+ Three shell widgets, one for colour output, two for attributes output
+ plus a back_up pixmap for redrawing
+*/
+
+static Widget top_level;
+static Widget colour_shell;
+static Widget colour_box;
+static Widget colour_canvas;
+static Pixmap colour_pm;
+
+static Widget volume_shell;
+static Widget volume_box;
+static Widget volume_canvas;
+static Pixmap volume_pm;
+
+static Widget dryness_shell;
+static Widget dryness_box;
+static Widget dryness_canvas;
+static Pixmap dryness_pm;
+
+static GC gc;
+static GC tmp_gc;
+static long tqmask;
+static XGCValues values;
+
+static Colormap cmap;
+static XColor colours[256];
+void stroke();
+void stroke_motion();
+
+Display *display;
+int screen;
+Screen *screen_ptr;
+Window root;
+
+static int count=0;
+static int frame_count=0;
+char pix_file[64];
+
+static void
+expose_event(w, event)
+Widget w;
+XEvent *event;
+{
+/* Re-display the colour window if an exposure event is received */
+int width, height;
+
+ width = height = 300;
+
+ XCopyArea(XtDisplay(colour_canvas), colour_pm,
+ XtWindow(colour_canvas), gc, 0, 0, width, height, 0,0);
+
+}
+
+
+static void
+expose_volume(w, event)
+Widget w;
+XEvent *event;
+{
+/* Re-display the volume window if an exposure event is received */
+int width, height;
+
+ width = 300;
+ height = 300;
+
+ XCopyArea(XtDisplay(volume_canvas), volume_pm,
+ XtWindow(volume_canvas), gc, 0, 0, width, height, 0,0);
+
+
+}
+
+static void
+expose_dryness(w, event)
+Widget w;
+XEvent *event;
+{
+/* Re-display the dryness window if an exposure event is received */
+int width, height;
+
+ width = height = 300;
+
+ XCopyArea(XtDisplay(dryness_canvas), dryness_pm,
+ XtWindow(dryness_canvas), gc, 0, 0, width, height, 0,0);
+
+
+}
+
+void expose_canvases()
+{
+int width, height;
+
+width = height = 300;
+
+ XCopyArea(XtDisplay(colour_canvas), colour_pm,
+ XtWindow(colour_canvas), gc, 0, 0, width, height, 0,0);
+
+ XCopyArea(XtDisplay(dryness_canvas), dryness_pm,
+ XtWindow(dryness_canvas), gc, 0, 0, width, height, 0,0);
+
+ XCopyArea(XtDisplay(dryness_canvas), dryness_pm,
+ XtWindow(dryness_canvas), gc, 0, 0, 300, 300, 0,0);
+
+}
+
+int
+GetHueValue(red, green, blue)
+int red;
+int green;
+int blue;
+{
+ XColor colour;
+
+ colour.red = red * 257;
+ colour.green = green * 257;
+ colour.blue = blue * 257;
+ colour.flags = DoRed | DoGreen | DoBlue;
+
+ if (XAllocColor(display, cmap, &colour) == 0)
+ fprintf(stderr,"colour allocation failed\n");
+
+ return (colour.pixel);
+}
+
+
+void
+DrawPoint(x,y,colour)
+int x;
+int y;
+int colour;
+/* Draw a point on the window and the back-up Pixmap */
+{
+ /* PROBS ? */
+
+ XSetForeground(XtDisplay(top_level), gc, colours[colour].pixel);
+
+ XDrawPoint(XtDisplay(top_level), XtWindow(colour_canvas), gc, x, y);
+ XDrawPoint(XtDisplay(top_level), colour_pm, gc, x, y);
+}
+
+void
+DrawBackgroundPoint(x,y,colour)
+int x;
+int y;
+int colour;
+/* Draw a point on the window and the back-up Pixmap */
+{
+ /* PROBS ? */
+
+ XSetForeground(XtDisplay(top_level), gc, colours[colour].pixel);
+
+ XDrawPoint(XtDisplay(top_level), colour_pm, gc, x, y);
+}
+
+
+int
+DrawVolumePoint(x,y,attr)
+int x;
+int y;
+int attr;
+/* Draw a point on the window and the back-up Pixmap */
+{
+ if (XtWindow(volume_canvas) == NULL)
+ return (-1);
+
+ XSetForeground(XtDisplay(top_level), gc, colours[attr].pixel);
+
+ XDrawPoint(XtDisplay(top_level), XtWindow(volume_canvas), gc, x, y);
+ XDrawPoint(XtDisplay(top_level), volume_pm, gc, x, y);
+
+ return(0);
+}
+
+int
+DrawBackgroundVolumePoint(x,y,attr)
+int x;
+int y;
+int attr;
+/* Draw a point on the window and the back-up Pixmap */
+{
+ if (XtWindow(volume_canvas) == NULL)
+ return (-1);
+
+ XSetForeground(XtDisplay(top_level), gc, colours[attr].pixel);
+
+ XDrawPoint(XtDisplay(top_level), volume_pm, gc, x, y);
+
+ return(0);
+}
+
+
+int
+DrawDrynessPoint(x,y,attr)
+int x;
+int y;
+int attr;
+/* Draw a point on the window and the back-up Pixmap */
+{
+ /* later - use the range of the dryness to affect the colour
+ value
+ */
+
+ if (XtWindow(dryness_canvas) == NULL)
+ return (-1);
+
+ XSetForeground(XtDisplay(top_level), gc, colours[attr].pixel);
+
+/* XDrawPoint(XtDisplay(top_level), XtWindow(dryness_canvas), gc, x, y);
+*/
+ XDrawPoint(XtDisplay(top_level), dryness_pm, gc, x, y);
+
+ return(0);
+}
+
+void
+ClearWindow()
+{
+ XClearWindow(XtDisplay(top_level), XtWindow(colour_canvas));
+}
+
+static void
+CleanWindow(win)
+Drawable win;
+/* Fill a window with a solid, white rectangle */
+{
+XGCValues values;
+long tqmask;
+
+ values.background = colours[0].pixel;
+ values.foreground = colours[255].pixel;;
+ values.fill_style = FillSolid;
+ values.function = GXclear;
+
+
+ tqmask = GCBackground| GCForeground| GCFillStyle | GCFunction;
+
+ tmp_gc = XtGetGC(top_level, tqmask, &values);
+
+ XFillRectangle(XtDisplay(top_level), win, tmp_gc, 0, 0, 300, 300);
+
+}
+
+void SetupCmap()
+{
+int i;
+
+ for (i=0;i<256;i++) {
+ colours[i].red = i*257;
+ colours[i].flags = DoRed | DoBlue | DoGreen;
+ }
+
+ /* for (i=0;i<=127;i++)
+ colours[i].green = i*2*257;
+
+ for (i=128;i>0;i--)
+ colours[255-i].green = (i-1)*2*257;*/
+
+ for (i=0;i<64;i++)
+ colours[i].green = i*4*257;
+
+ for (i=64;i<128;i++)
+ colours[i].green = 65536-i*4*257;
+
+ for (i=128;i<192;i++)
+ colours[i].green = (i-128)*2*257;
+
+ for (i=192;i<255;i++)
+ colours[i].green = 65536-(i-128)*2*257;
+
+
+ for (i=0;i<256;i++)
+ colours[i].blue = 65536 - i*257;
+
+ colours[0].red = 65535;
+ colours[0].green = 65535;
+ colours[0].blue = 65535;
+}
+
+void
+SetupGreyMap()
+{
+int i;
+
+ for (i=0;i<256;i++) {
+ colours[i].red = i*257;
+ colours[255 - i].flags = DoRed | DoBlue | DoGreen;
+ }
+
+
+ for (i=0;i<256;i++)
+ colours[i].green = i*257;
+
+ for (i=0;i<256;i++)
+ colours[i].blue = i*257;
+
+ colours[255].red = 255*257;
+ colours[255].green = 255*257;
+ colours[255].blue = 255*257;
+
+}
+
+
+void CreateWindows(argc, argv, width, height)
+int *argc;
+char **argv;
+int width;
+int height;
+/* Create colour window heirarchy and add event handlers */
+{
+
+ static Arg args[]={
+ {XtNwidth, (XtArgVal) 0},
+ {XtNheight, (XtArgVal)0} };
+
+ int i;
+
+ args[0].value = (XtArgVal)width;
+
+ args[1].value = (XtArgVal)height;
+
+ top_level = XtInitialize("wet+sticky", "Wet+Sticky", NULL,
+ 0, argc, argv);
+
+
+ display = XtDisplay(top_level);
+ screen = DefaultScreen(display);
+ screen_ptr = ScreenOfDisplay(display, DefaultScreen(display));
+
+ root = RootWindow(display, screen);
+
+ colour_shell = XtCreateApplicationShell("colour_frame",
+ topLevelShellWidgetClass, NULL, 0);
+
+
+
+ colour_box = XtCreateManagedWidget("colour_box", boxWidgetClass,
+ colour_shell, NULL, 0);
+
+
+ colour_canvas = XtCreateManagedWidget("", labelWidgetClass,
+ colour_box, args, XtNumber(args));
+
+
+ XtAddEventHandler(colour_canvas, ExposureMask, False, expose_event, 0);
+
+ XtAddEventHandler(colour_canvas, ButtonPressMask, False, stroke, 0);
+
+ XtAddEventHandler(colour_canvas, Button1MotionMask,
+ False, stroke_motion, 0);
+
+ XtRealizeWidget(colour_shell);
+
+ cmap = XCreateColormap( display, XtWindow(colour_shell),
+ XDefaultVisualOfScreen(screen_ptr), AllocAll);
+
+ for (i=0; i <= 255; i++)
+ colours[i].pixel = i;
+
+ XQueryColors(display, DefaultColormapOfScreen(screen_ptr),colours, 256);
+
+ SetupCmap();
+
+ /*SetupGreyMap();*/
+
+ XStoreColors(display, cmap, colours, 256);
+
+ i=0;
+ while( XAllocColorCells( display, DefaultColormapOfScreen(screen_ptr),
+ True, NULL, 0, &colours[i].pixel, 1 ) ) {
+ colours[i].pixel = i;
+ i++;
+ }
+
+ XSetWindowColormap(display, XtWindow(colour_shell), cmap);
+
+ XInstallColormap(display, cmap);
+
+ tqmask = GCBackground| GCForeground| GCFunction;
+
+ values.function = GXcopy;
+ values.background = colours[0].pixel;
+ values.foreground = colours[255].pixel;
+
+
+ gc = XtGetGC(colour_canvas, tqmask, &values);
+
+ colour_pm = XCreatePixmap(XtDisplay(top_level),
+ XtWindow(colour_shell), width, height,
+ XDefaultDepth(XtDisplay(top_level), 0));
+
+ CleanWindow(colour_pm);
+
+}
+
+
+void StartVolumeWindow(width, height)
+int width;
+int height;
+/* Create Volume heirarchy and add event handlers */
+{
+ static Arg args[]={
+ {XtNwidth, (XtArgVal) 0},
+ {XtNheight, (XtArgVal)0} };
+
+ args[0].value = (XtArgVal)width;
+
+ args[1].value = (XtArgVal)height;
+
+ volume_shell = XtCreateApplicationShell("volume_frame",
+ topLevelShellWidgetClass, NULL, 0);
+
+ volume_box = XtCreateManagedWidget("volume_box", boxWidgetClass,
+ volume_shell, NULL, 0);
+
+ volume_canvas = XtCreateManagedWidget("", labelWidgetClass,
+ volume_box, args, XtNumber(args));
+
+ XtAddEventHandler(volume_canvas, ExposureMask, False,
+ expose_volume, 0);
+
+ XtRealizeWidget(volume_shell);
+
+ XSetWindowColormap(display, XtWindow(volume_shell), cmap);
+
+ volume_pm = XCreatePixmap(XtDisplay(top_level),
+ XtWindow(colour_shell), width, height,
+ XDefaultDepth(XtDisplay(top_level), 0));
+
+ CleanWindow(volume_pm);
+
+
+}
+
+void StartDrynessWindow(width, height)
+int width;
+int height;
+/* Create dryness heirarchy and add event handlers */
+{
+ static Arg args[]={
+ {XtNwidth, (XtArgVal) 0},
+ {XtNheight, (XtArgVal)0} };
+
+ char name[32];
+
+ args[0].value = (XtArgVal)width;
+
+ args[1].value = (XtArgVal)height;
+
+ dryness_shell = XtCreateApplicationShell("dryness_frame",
+ topLevelShellWidgetClass, NULL, 0);
+
+ dryness_box = XtCreateManagedWidget("dryness_box", boxWidgetClass,
+ dryness_shell, NULL, 0);
+ dryness_canvas = XtCreateManagedWidget("Name", labelWidgetClass,
+ dryness_box, args, XtNumber(args));
+
+ fprintf(stderr,"Bumps %d\n",(int)dryness_canvas);
+
+ XtAddEventHandler(dryness_canvas, ExposureMask, False,
+ expose_dryness, 0);
+
+ XtRealizeWidget(dryness_shell);
+
+ XSetWindowColormap(display, XtWindow(dryness_shell), cmap);
+
+ dryness_pm = XCreatePixmap(XtDisplay(top_level),
+ XtWindow(colour_shell), width, height,
+ XDefaultDepth(XtDisplay(top_level), 0));
+
+ XStoreName(display, XtWindow(dryness_shell), "bumps");
+
+ CleanWindow(dryness_pm);
+
+}
+
+static void
+draw_labels()
+{
+ XSetForeground(XtDisplay(colour_shell), gc, colours[1].pixel);
+
+ XDrawString(XtDisplay(colour_shell), XtWindow(colour_canvas), gc, 10, 10,
+ "Colour", strlen("Colour"));
+ XDrawString(XtDisplay(colour_shell), colour_pm, gc, 10, 10,
+ "Colour", strlen("Colour"));
+
+ XSetForeground(XtDisplay(colour_shell), gc, colours[128].pixel);
+
+ XDrawString(XtDisplay(colour_shell), XtWindow(volume_canvas), gc, 10, 10,
+ "Volume", strlen("Volume"));
+ XDrawString(XtDisplay(colour_shell), volume_pm, gc, 10, 10,
+ "Volume", strlen("Volume"));
+
+ XSetForeground(XtDisplay(colour_shell), gc, colours[255].pixel);
+
+ XDrawString(XtDisplay(colour_shell), XtWindow(dryness_canvas), gc, 10, 10,
+ "Bump Map", strlen("Bump Map"));
+ XDrawString(XtDisplay(colour_shell), dryness_pm, gc, 10, 10,
+ "Bump Map", strlen("Bump Map"));
+}
+
+void paint_cell(cell, x, y)
+CELL_PTR cell;
+int x, y;
+
+{
+ int colour, volColour, dryness;
+ POINT p;
+
+ p.x = x;
+ p.y = y;
+
+ /* The current display simply maps hue onto the indices of the colour
+ table. This involves some scaling since hues are in the range [0,360)
+ with the colour table being [0,256). */
+
+ colour = (int) (cell->contents.colour.hue *
+ ((float) MAX_COLOUR_INDEX / 360.0));
+
+ DrawBackgroundPoint(x,y,colour);
+
+ /* volColour is an index into the colour table in the range [0,255].
+ It is used to give a false colour image of the canvas's volume. */
+
+ /*if (x < SCALE_WIDTH) return; Don't draw over colour scale. */
+
+ volColour = MIN(cell->volume * 2, 255);
+ volColour = MAX(volColour, 0);
+ /* Make unfilled cells have a zero vol. */
+
+ DrawBackgroundVolumePoint(x,y,volColour);
+
+ /* Dryness will be in the range [0,255]. */
+ dryness = (cell->contents.liquid_content * 255) / 100;
+
+ /*DrawDrynessPoint(x,y,dryness);*/
+}
+
+
+
+void draw_false_colour_scale()
+/* This routine places a scale along the top of the volume window
+ showing the colours being used. Low is at the left edge.
+ The colour palette has indices 0..255. */
+{
+ int x, y;
+
+ /*for (x=0; x < 255; x++)
+ for (y=0; y < SCALE_WIDTH; y++) DrawVolumePoint(x,y,MIN(x, 255));*/
+}
+
+
+void draw_full_canvas()
+{
+ int x, y;
+ CELL_PTR cell;
+ POINT p;
+
+ if (DEBUG) {
+ printf ("Starting to paint full canvas...");
+ fflush(stdout);
+ }
+
+ for (y=0; y < CANVAS_HEIGHT; y++)
+ for (x=0; x < CANVAS_WIDTH; x++) {
+ p.x = x;
+ p.y = y;
+ cell = get_cell(p);
+ paint_cell(cell, x, y);
+ }
+
+ expose_canvases();
+
+ draw_false_colour_scale();
+ if (DEBUG) printf ("done.\n");
+}
+
+void
+bump_map()
+{
+ POINT p;
+ CELL_PTR cell;
+ register int x, y;
+ register int colour;
+
+
+ for (y=0; y < CANVAS_HEIGHT; y++) {
+ for (x=0; x < CANVAS_WIDTH; x++) {
+ p.x = x;
+ p.y = y;
+ cell = get_cell(p);
+ colour = (int) new_intensity_value(p);
+
+/* colour = (int) (cell->contents.colour.hue *
+ ((float) MAX_COLOUR_INDEX / 360.0));*/
+ DrawDrynessPoint(x,y,colour);
+ }
+ }
+
+}
+
+draw_cmap_line()
+
+{
+
+int i;
+
+ for (i=0; i< 255; i++) {
+ DrawDrynessPoint(0,i,i);
+ }
+}
+
+void evolve_paint()
+{
+ int k;
+ POINT p;
+ CELL_PTR cell;
+ int new_x, new_y;
+ Window tempChild;
+ extern Window root;
+ extern int count;
+ extern int frame_count;
+
+ count++;
+ if (count > 5000) {
+ fprintf(stderr,".");
+ fflush(stderr);
+ bump_map();
+ expose_canvases();
+
+ /*XTranslateCoordinates(display,XtWindow(dryness_canvas), root,
+ 0,0, &new_x, &new_y, &tempChild);*/
+ /*if (frame_count < 10)
+ sprintf(pix_file,"xwd -name bumps -out pixmap0%d.xwd &" ,frame_count);
+ else
+ sprintf(pix_file,"xwd -name bumps -out pixmap%d.xwd &" ,frame_count);
+ */
+
+
+ /*system(pix_file);*/
+ /*XWriteBitmapFile(display, pix_file,dryness_pm, 300, 300,-1,-1 );*/
+ count = 0;
+ frame_count++;
+ /*if (frame_count > 250) {
+ fprintf(stderr,"Done\n");
+ sleep(2);
+ exit(0);
+ } */
+ /*exit(0)*/;
+ }
+
+
+
+ for (k=0; k < STEP_LIMIT; k++) single_step();
+ while (TRUE) {
+ next_cell_for_tqrepaint(&cell, &p);
+ if (cell == NIL) return;
+ paint_cell(cell, p.x, p.y);
+ }
+
+}
+
+
+
+void StartWindows()
+{
+/* Start the X windows event loop and paint processing */
+XEvent event;
+
+
+ draw_full_canvas();
+ compute_shade_vectors(); /* Set vectors for shading */
+ draw_labels();
+
+ for (;;) {
+ if (XtPending()) {
+ XtNextEvent(&event);
+ XtDispatchEvent(&event);
+ }
+ else {
+ /* Evolve paint and re-display*/
+ evolve_paint();
+ }
+
+ } /* End for loop */
+
+
+}
+
+void
+stroke(w, client_data, event)
+Widget w;
+caddr_t client_data;
+XEvent *event;
+{
+/* brush_stroke(event->xbutton.x, event->xbutton.y);*/
+
+
+ /*if ((XEvent *)event != (XEvent *)NULL)
+ else
+ printf("Null event\n"); */
+
+/* DrawPoint(event->xbutton.x, event->xbutton.y, 128);
+ DrawVolumePoint(event->xbutton.x, event->xbutton.y, 128);
+ DrawDrynessPoint(event->xbutton.x, event->xbutton.y, 128);*/
+
+
+ XSetForeground(XtDisplay(top_level), gc, colours[128].pixel);
+
+ XFillRectangle(XtDisplay(top_level), XtWindow(colour_canvas), gc,
+ event->xmotion.x, event->xmotion.y ,1, 1);
+
+ XFillRectangle(XtDisplay(top_level), XtWindow(volume_canvas), gc,
+ event->xmotion.x, event->xmotion.y ,1, 1);
+
+ XFillRectangle(XtDisplay(top_level), XtWindow(dryness_canvas), gc,
+ event->xmotion.x, event->xmotion.y ,1, 1);
+
+ brush_stroke(event->xbutton.x, event->xbutton.y);
+}
+
+
+void
+stroke_motion(w, client_data, event)
+Widget w;
+caddr_t client_data;
+XEvent *event;
+{
+
+
+ /*if ((XEvent *)event != (XEvent *)NULL)
+ else
+ printf("Null event\n"); */
+
+
+ XSetForeground(XtDisplay(top_level), gc, colours[128].pixel);
+
+ XFillRectangle(XtDisplay(top_level), XtWindow(colour_canvas), gc,
+ event->xmotion.x, event->xmotion.y ,1, 1);
+ XFillRectangle(XtDisplay(top_level), XtWindow(volume_canvas), gc,
+ event->xmotion.x, event->xmotion.y ,1, 1);
+
+ XFillRectangle(XtDisplay(top_level), XtWindow(dryness_canvas), gc,
+ event->xmotion.x, event->xmotion.y ,1, 1);
+
+ brush_stroke(event->xbutton.x, event->xbutton.y);
+}
+
diff --git a/chalk/colorspaces/wetsticky/wstool.ui b/chalk/colorspaces/wetsticky/wstool.ui
new file mode 100644
index 00000000..2f95d18b
--- /dev/null
+++ b/chalk/colorspaces/wetsticky/wstool.ui
@@ -0,0 +1,262 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>WdgWSPaintOp</class>
+<widget class="TQWidget">
+ <property name="name">
+ <cstring>WdgWSPaintOp</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>582</width>
+ <height>359</height>
+ </rect>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="TQGroupBox" row="0" column="0">
+ <property name="name">
+ <cstring>grpGravity</cstring>
+ </property>
+ <property name="title">
+ <string>&amp;Gravity</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="TQCheckBox" row="0" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>chkGravity</cstring>
+ </property>
+ <property name="text">
+ <string>Paint &amp;gravity</string>
+ </property>
+ </widget>
+ <widget class="TQLabel" row="1" column="0">
+ <property name="name">
+ <cstring>lblDirection</cstring>
+ </property>
+ <property name="text">
+ <string>Direction:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>intDryingRate</cstring>
+ </property>
+ </widget>
+ <widget class="TQComboBox" row="1" column="1">
+ <item>
+ <property name="text">
+ <string>Up</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Right</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Down</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Left</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>cmbGravitationalDirection</cstring>
+ </property>
+ </widget>
+ <widget class="TQLabel" row="2" column="0">
+ <property name="name">
+ <cstring>lblStrength</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Strength:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>intGravitationalStrength</cstring>
+ </property>
+ </widget>
+ <widget class="KIntNumInput" row="2" column="1">
+ <property name="name">
+ <cstring>intGravitationalStrength</cstring>
+ </property>
+ <property name="minValue">
+ <number>0</number>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="TQGroupBox" row="1" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>grpPaint</cstring>
+ </property>
+ <property name="title">
+ <string>&amp;Paint</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="TQLabel" row="0" column="0">
+ <property name="name">
+ <cstring>lblDryingRate</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Drying rate:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>intDryingRate</cstring>
+ </property>
+ </widget>
+ <widget class="TQCheckBox" row="1" column="0" rowspan="2" colspan="4">
+ <property name="name">
+ <cstring>chkLiquid</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Liquid content:</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="KIntNumInput" row="0" column="1" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>intDryingRate</cstring>
+ </property>
+ <property name="minValue">
+ <number>0</number>
+ </property>
+ <property name="maxValue">
+ <number>100</number>
+ </property>
+ </widget>
+ <widget class="KIntNumInput" row="2" column="2" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>intMiscibility</cstring>
+ </property>
+ </widget>
+ <widget class="KIntNumInput" row="3" column="3">
+ <property name="name">
+ <cstring>intLiquidContent</cstring>
+ </property>
+ <property name="minValue">
+ <number>0</number>
+ </property>
+ <property name="maxValue">
+ <number>100</number>
+ </property>
+ </widget>
+ <widget class="TQLabel" row="3" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>lblMiscibility</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Miscibility:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>intMiscibility</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="TQGroupBox" row="0" column="1">
+ <property name="name">
+ <cstring>grpSubstrate</cstring>
+ </property>
+ <property name="title">
+ <string>&amp;Canvas</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KIntNumInput" row="3" column="1">
+ <property name="name">
+ <cstring>intHeight</cstring>
+ </property>
+ </widget>
+ <widget class="TQLabel" row="3" column="0">
+ <property name="name">
+ <cstring>lblHeight</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Height:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>intHeight</cstring>
+ </property>
+ </widget>
+ <widget class="KIntNumInput" row="2" column="1">
+ <property name="name">
+ <cstring>intAbsorbency</cstring>
+ </property>
+ <property name="minValue">
+ <number>0</number>
+ </property>
+ <property name="maxValue">
+ <number>100</number>
+ </property>
+ </widget>
+ <widget class="TQLabel" row="2" column="0">
+ <property name="name">
+ <cstring>lblAbsorbency</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Absorbency:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>intAbsorbency</cstring>
+ </property>
+ </widget>
+ <widget class="TQLabel" row="1" column="0">
+ <property name="name">
+ <cstring>lblColor</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Color:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>bnCanvasColor</cstring>
+ </property>
+ </widget>
+ <widget class="TQCheckBox" row="0" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>chkCanvas</cstring>
+ </property>
+ <property name="text">
+ <string>Paint canvas attributes</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="KColorButton" row="1" column="1">
+ <property name="name">
+ <cstring>bnCanvasColor</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </grid>
+</widget>
+<customwidgets>
+</customwidgets>
+<tqlayoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>knuminput.h</includehint>
+ <includehint>knuminput.h</includehint>
+ <includehint>knuminput.h</includehint>
+ <includehint>knuminput.h</includehint>
+ <includehint>knuminput.h</includehint>
+ <includehint>knuminput.h</includehint>
+</includehints>
+</UI>